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