1 /* 2 * Copyright (c) 2018-2021 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 cd[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(assert, cd, sizeof(cd)); 110 if (r != FIDO_OK) 111 errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r); 112 113 /* relying party */ 114 r = fido_assert_set_rp(assert, "localhost"); 115 if (r != FIDO_OK) 116 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); 117 118 /* authdata */ 119 r = fido_assert_set_count(assert, 1); 120 if (r != FIDO_OK) 121 errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r); 122 r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len); 123 if (r != FIDO_OK) 124 errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r); 125 126 /* extension */ 127 r = fido_assert_set_extensions(assert, ext); 128 if (r != FIDO_OK) 129 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), 130 r); 131 132 /* user presence */ 133 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) 134 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); 135 136 /* user verification */ 137 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) 138 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); 139 140 /* sig */ 141 r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len); 142 if (r != FIDO_OK) 143 errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r); 144 145 r = fido_assert_verify(assert, 0, type, pk); 146 if (r != FIDO_OK) 147 errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r); 148 149 es256_pk_free(&es256_pk); 150 rs256_pk_free(&rs256_pk); 151 eddsa_pk_free(&eddsa_pk); 152 153 fido_assert_free(&assert); 154 } 155 156 int 157 main(int argc, char **argv) 158 { 159 bool up = false; 160 bool uv = false; 161 bool u2f = false; 162 fido_dev_t *dev = NULL; 163 fido_assert_t *assert = NULL; 164 const char *pin = NULL; 165 const char *blobkey_out = NULL; 166 const char *hmac_out = NULL; 167 unsigned char *body = NULL; 168 long long ms = 0; 169 size_t len; 170 int type = COSE_ES256; 171 int ext = 0; 172 int ch; 173 int r; 174 175 if ((assert = fido_assert_new()) == NULL) 176 errx(1, "fido_assert_new"); 177 178 while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) { 179 switch (ch) { 180 case 'P': 181 pin = optarg; 182 break; 183 case 'T': 184 if (base10(optarg, &ms) < 0) 185 errx(1, "base10: %s", optarg); 186 if (ms <= 0 || ms > 30) 187 errx(1, "-T: %s must be in (0,30]", optarg); 188 ms *= 1000; /* seconds to milliseconds */ 189 break; 190 case 'a': 191 if (read_blob(optarg, &body, &len) < 0) 192 errx(1, "read_blob: %s", optarg); 193 if ((r = fido_assert_allow_cred(assert, body, 194 len)) != FIDO_OK) 195 errx(1, "fido_assert_allow_cred: %s (0x%x)", 196 fido_strerr(r), r); 197 free(body); 198 body = NULL; 199 break; 200 case 'b': 201 ext |= FIDO_EXT_LARGEBLOB_KEY; 202 blobkey_out = optarg; 203 break; 204 case 'h': 205 hmac_out = optarg; 206 break; 207 case 'p': 208 up = true; 209 break; 210 case 's': 211 ext |= FIDO_EXT_HMAC_SECRET; 212 if (read_blob(optarg, &body, &len) < 0) 213 errx(1, "read_blob: %s", optarg); 214 if ((r = fido_assert_set_hmac_salt(assert, body, 215 len)) != FIDO_OK) 216 errx(1, "fido_assert_set_hmac_salt: %s (0x%x)", 217 fido_strerr(r), r); 218 free(body); 219 body = NULL; 220 break; 221 case 't': 222 if (strcmp(optarg, "ecdsa") == 0) 223 type = COSE_ES256; 224 else if (strcmp(optarg, "rsa") == 0) 225 type = COSE_RS256; 226 else if (strcmp(optarg, "eddsa") == 0) 227 type = COSE_EDDSA; 228 else 229 errx(1, "unknown type %s", optarg); 230 break; 231 case 'u': 232 u2f = true; 233 break; 234 case 'v': 235 uv = true; 236 break; 237 default: 238 usage(); 239 } 240 } 241 242 argc -= optind; 243 argv += optind; 244 245 if (argc != 2) 246 usage(); 247 248 fido_init(0); 249 250 if ((dev = fido_dev_new()) == NULL) 251 errx(1, "fido_dev_new"); 252 253 r = fido_dev_open(dev, argv[1]); 254 if (r != FIDO_OK) 255 errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); 256 if (u2f) 257 fido_dev_force_u2f(dev); 258 259 /* client data hash */ 260 r = fido_assert_set_clientdata(assert, cd, sizeof(cd)); 261 if (r != FIDO_OK) 262 errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r); 263 264 /* relying party */ 265 r = fido_assert_set_rp(assert, "localhost"); 266 if (r != FIDO_OK) 267 errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); 268 269 /* extensions */ 270 r = fido_assert_set_extensions(assert, ext); 271 if (r != FIDO_OK) 272 errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), 273 r); 274 275 /* user presence */ 276 if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) 277 errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); 278 279 /* user verification */ 280 if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) 281 errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); 282 283 /* timeout */ 284 if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK) 285 errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r); 286 287 if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) { 288 fido_dev_cancel(dev); 289 errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r); 290 } 291 292 r = fido_dev_close(dev); 293 if (r != FIDO_OK) 294 errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); 295 296 fido_dev_free(&dev); 297 298 if (fido_assert_count(assert) != 1) 299 errx(1, "fido_assert_count: %d signatures returned", 300 (int)fido_assert_count(assert)); 301 302 /* when verifying, pin implies uv */ 303 if (pin) 304 uv = true; 305 306 verify_assert(type, fido_assert_authdata_ptr(assert, 0), 307 fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), 308 fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); 309 310 if (hmac_out != NULL) { 311 /* extract the hmac secret */ 312 if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0), 313 fido_assert_hmac_secret_len(assert, 0)) < 0) 314 errx(1, "write_blob"); 315 } 316 317 if (blobkey_out != NULL) { 318 /* extract the hmac secret */ 319 if (write_blob(blobkey_out, 320 fido_assert_largeblob_key_ptr(assert, 0), 321 fido_assert_largeblob_key_len(assert, 0)) < 0) 322 errx(1, "write_blob"); 323 } 324 325 fido_assert_free(&assert); 326 327 exit(0); 328 } 329