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