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