1 /* 2 * Copyright (c) 2018 Yubico AB. All rights reserved. 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 */ 6 7 #include <fido.h> 8 #include <fido/es256.h> 9 #include <fido/rs256.h> 10 #include <fido/eddsa.h> 11 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #ifdef HAVE_UNISTD_H 17 #include <unistd.h> 18 #endif 19 20 #include "../openbsd-compat/openbsd-compat.h" 21 #include "extern.h" 22 23 static const unsigned char cdh[32] = { 24 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 25 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, 26 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, 27 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, 28 }; 29 30 static void 31 usage(void) 32 { 33 fprintf(stderr, "usage: assert [-t ecdsa|rsa|eddsa] [-a cred_id] " 34 "[-h hmac_secret] [-s hmac_salt] [-P pin] [-T seconds] " 35 "[-b blobkey] [-puv] <pubkey> <device>\n"); 36 exit(EXIT_FAILURE); 37 } 38 39 static void 40 verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len, 41 const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext, 42 const char *key) 43 { 44 fido_assert_t *assert = NULL; 45 EC_KEY *ec = NULL; 46 RSA *rsa = NULL; 47 EVP_PKEY *eddsa = NULL; 48 es256_pk_t *es256_pk = NULL; 49 rs256_pk_t *rs256_pk = NULL; 50 eddsa_pk_t *eddsa_pk = NULL; 51 void *pk; 52 int r; 53 54 /* credential pubkey */ 55 switch (type) { 56 case COSE_ES256: 57 if ((ec = read_ec_pubkey(key)) == NULL) 58 errx(1, "read_ec_pubkey"); 59 60 if ((es256_pk = es256_pk_new()) == NULL) 61 errx(1, "es256_pk_new"); 62 63 if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) 64 errx(1, "es256_pk_from_EC_KEY"); 65 66 pk = es256_pk; 67 EC_KEY_free(ec); 68 ec = NULL; 69 70 break; 71 case COSE_RS256: 72 if ((rsa = read_rsa_pubkey(key)) == NULL) 73 errx(1, "read_rsa_pubkey"); 74 75 if ((rs256_pk = rs256_pk_new()) == NULL) 76 errx(1, "rs256_pk_new"); 77 78 if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) 79 errx(1, "rs256_pk_from_RSA"); 80 81 pk = rs256_pk; 82 RSA_free(rsa); 83 rsa = NULL; 84 85 break; 86 case COSE_EDDSA: 87 if ((eddsa = read_eddsa_pubkey(key)) == NULL) 88 errx(1, "read_eddsa_pubkey"); 89 90 if ((eddsa_pk = eddsa_pk_new()) == NULL) 91 errx(1, "eddsa_pk_new"); 92 93 if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) 94 errx(1, "eddsa_pk_from_EVP_PKEY"); 95 96 pk = eddsa_pk; 97 EVP_PKEY_free(eddsa); 98 eddsa = NULL; 99 100 break; 101 default: 102 errx(1, "unknown credential type %d", type); 103 } 104 105 if ((assert = fido_assert_new()) == NULL) 106 errx(1, "fido_assert_new"); 107 108 /* client data hash */ 109 r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); 110 if (r != FIDO_OK) 111 errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", 112 fido_strerr(r), r); 113 114 /* relying party */ 115 r = fido_assert_set_rp(assert, "localhost"); 116 if (r != FIDO_OK) 117 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); 118 119 /* authdata */ 120 r = fido_assert_set_count(assert, 1); 121 if (r != FIDO_OK) 122 errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r); 123 r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len); 124 if (r != FIDO_OK) 125 errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r); 126 127 /* extension */ 128 r = fido_assert_set_extensions(assert, ext); 129 if (r != FIDO_OK) 130 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), 131 r); 132 133 /* user presence */ 134 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) 135 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); 136 137 /* user verification */ 138 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) 139 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); 140 141 /* sig */ 142 r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len); 143 if (r != FIDO_OK) 144 errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r); 145 146 r = fido_assert_verify(assert, 0, type, pk); 147 if (r != FIDO_OK) 148 errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r); 149 150 es256_pk_free(&es256_pk); 151 rs256_pk_free(&rs256_pk); 152 eddsa_pk_free(&eddsa_pk); 153 154 fido_assert_free(&assert); 155 } 156 157 int 158 main(int argc, char **argv) 159 { 160 bool up = false; 161 bool uv = false; 162 bool u2f = false; 163 fido_dev_t *dev = NULL; 164 fido_assert_t *assert = NULL; 165 const char *pin = NULL; 166 const char *blobkey_out = NULL; 167 const char *hmac_out = NULL; 168 unsigned char *body = NULL; 169 long long seconds = 0; 170 size_t len; 171 int type = COSE_ES256; 172 int ext = 0; 173 int ch; 174 int r; 175 176 if ((assert = fido_assert_new()) == NULL) 177 errx(1, "fido_assert_new"); 178 179 while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) { 180 switch (ch) { 181 case 'P': 182 pin = optarg; 183 break; 184 case 'T': 185 #ifndef SIGNAL_EXAMPLE 186 (void)seconds; 187 errx(1, "-T not supported"); 188 #else 189 if (base10(optarg, &seconds) < 0) 190 errx(1, "base10: %s", optarg); 191 if (seconds <= 0 || seconds > 30) 192 errx(1, "-T: %s must be in (0,30]", optarg); 193 break; 194 #endif 195 case 'a': 196 if (read_blob(optarg, &body, &len) < 0) 197 errx(1, "read_blob: %s", optarg); 198 if ((r = fido_assert_allow_cred(assert, body, 199 len)) != FIDO_OK) 200 errx(1, "fido_assert_allow_cred: %s (0x%x)", 201 fido_strerr(r), r); 202 free(body); 203 body = NULL; 204 break; 205 case 'b': 206 ext |= FIDO_EXT_LARGEBLOB_KEY; 207 blobkey_out = optarg; 208 break; 209 case 'h': 210 hmac_out = optarg; 211 break; 212 case 'p': 213 up = true; 214 break; 215 case 's': 216 ext |= FIDO_EXT_HMAC_SECRET; 217 if (read_blob(optarg, &body, &len) < 0) 218 errx(1, "read_blob: %s", optarg); 219 if ((r = fido_assert_set_hmac_salt(assert, body, 220 len)) != FIDO_OK) 221 errx(1, "fido_assert_set_hmac_salt: %s (0x%x)", 222 fido_strerr(r), r); 223 free(body); 224 body = NULL; 225 break; 226 case 't': 227 if (strcmp(optarg, "ecdsa") == 0) 228 type = COSE_ES256; 229 else if (strcmp(optarg, "rsa") == 0) 230 type = COSE_RS256; 231 else if (strcmp(optarg, "eddsa") == 0) 232 type = COSE_EDDSA; 233 else 234 errx(1, "unknown type %s", optarg); 235 break; 236 case 'u': 237 u2f = true; 238 break; 239 case 'v': 240 uv = true; 241 break; 242 default: 243 usage(); 244 } 245 } 246 247 argc -= optind; 248 argv += optind; 249 250 if (argc != 2) 251 usage(); 252 253 fido_init(0); 254 255 if ((dev = fido_dev_new()) == NULL) 256 errx(1, "fido_dev_new"); 257 258 r = fido_dev_open(dev, argv[1]); 259 if (r != FIDO_OK) 260 errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); 261 if (u2f) 262 fido_dev_force_u2f(dev); 263 264 /* client data hash */ 265 r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); 266 if (r != FIDO_OK) 267 errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", 268 fido_strerr(r), r); 269 270 /* relying party */ 271 r = fido_assert_set_rp(assert, "localhost"); 272 if (r != FIDO_OK) 273 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); 274 275 /* extensions */ 276 r = fido_assert_set_extensions(assert, ext); 277 if (r != FIDO_OK) 278 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), 279 r); 280 281 /* user presence */ 282 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) 283 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); 284 285 /* user verification */ 286 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) 287 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); 288 289 #ifdef SIGNAL_EXAMPLE 290 prepare_signal_handler(SIGINT); 291 if (seconds) { 292 prepare_signal_handler(SIGALRM); 293 alarm((unsigned)seconds); 294 } 295 #endif 296 297 r = fido_dev_get_assert(dev, assert, pin); 298 if (r != FIDO_OK) { 299 #ifdef SIGNAL_EXAMPLE 300 if (got_signal) 301 fido_dev_cancel(dev); 302 #endif 303 errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r); 304 } 305 306 r = fido_dev_close(dev); 307 if (r != FIDO_OK) 308 errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); 309 310 fido_dev_free(&dev); 311 312 if (fido_assert_count(assert) != 1) 313 errx(1, "fido_assert_count: %d signatures returned", 314 (int)fido_assert_count(assert)); 315 316 /* when verifying, pin implies uv */ 317 if (pin) 318 uv = true; 319 320 verify_assert(type, fido_assert_authdata_ptr(assert, 0), 321 fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), 322 fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); 323 324 if (hmac_out != NULL) { 325 /* extract the hmac secret */ 326 if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0), 327 fido_assert_hmac_secret_len(assert, 0)) < 0) 328 errx(1, "write_blob"); 329 } 330 331 if (blobkey_out != NULL) { 332 /* extract the hmac secret */ 333 if (write_blob(blobkey_out, 334 fido_assert_largeblob_key_ptr(assert, 0), 335 fido_assert_largeblob_key_len(assert, 0)) < 0) 336 errx(1, "write_blob"); 337 } 338 339 fido_assert_free(&assert); 340 341 exit(0); 342 } 343