10afa8e06SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include <fido.h>
90afa8e06SEd Maste #include <fido/es256.h>
10*2ccfa855SEd Maste #include <fido/es384.h>
110afa8e06SEd Maste #include <fido/rs256.h>
120afa8e06SEd Maste #include <fido/eddsa.h>
130afa8e06SEd Maste
140afa8e06SEd Maste #include <stdbool.h>
150afa8e06SEd Maste #include <stdio.h>
160afa8e06SEd Maste #include <stdlib.h>
170afa8e06SEd Maste #include <string.h>
180afa8e06SEd Maste #ifdef HAVE_UNISTD_H
190afa8e06SEd Maste #include <unistd.h>
200afa8e06SEd Maste #endif
210afa8e06SEd Maste
220afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
230afa8e06SEd Maste #include "extern.h"
240afa8e06SEd Maste
25f540a430SEd Maste static const unsigned char cd[32] = {
260afa8e06SEd Maste 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
270afa8e06SEd Maste 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56,
280afa8e06SEd Maste 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52,
290afa8e06SEd Maste 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76,
300afa8e06SEd Maste };
310afa8e06SEd Maste
320afa8e06SEd Maste static void
usage(void)330afa8e06SEd Maste usage(void)
340afa8e06SEd Maste {
35*2ccfa855SEd Maste fprintf(stderr, "usage: assert [-t es256|es384|rs256|eddsa] "
36*2ccfa855SEd Maste "[-a cred_id] [-h hmac_secret] [-s hmac_salt] [-P pin] "
37*2ccfa855SEd Maste "[-T seconds] [-b blobkey] [-puv] <pubkey> <device>\n");
380afa8e06SEd Maste exit(EXIT_FAILURE);
390afa8e06SEd Maste }
400afa8e06SEd Maste
410afa8e06SEd Maste static void
verify_assert(int type,const unsigned char * authdata_ptr,size_t authdata_len,const unsigned char * sig_ptr,size_t sig_len,bool up,bool uv,int ext,const char * key)420afa8e06SEd Maste verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len,
430afa8e06SEd Maste const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext,
440afa8e06SEd Maste const char *key)
450afa8e06SEd Maste {
460afa8e06SEd Maste fido_assert_t *assert = NULL;
470afa8e06SEd Maste EC_KEY *ec = NULL;
480afa8e06SEd Maste RSA *rsa = NULL;
490afa8e06SEd Maste EVP_PKEY *eddsa = NULL;
500afa8e06SEd Maste es256_pk_t *es256_pk = NULL;
51*2ccfa855SEd Maste es384_pk_t *es384_pk = NULL;
520afa8e06SEd Maste rs256_pk_t *rs256_pk = NULL;
530afa8e06SEd Maste eddsa_pk_t *eddsa_pk = NULL;
540afa8e06SEd Maste void *pk;
550afa8e06SEd Maste int r;
560afa8e06SEd Maste
570afa8e06SEd Maste /* credential pubkey */
580afa8e06SEd Maste switch (type) {
590afa8e06SEd Maste case COSE_ES256:
600afa8e06SEd Maste if ((ec = read_ec_pubkey(key)) == NULL)
610afa8e06SEd Maste errx(1, "read_ec_pubkey");
620afa8e06SEd Maste
630afa8e06SEd Maste if ((es256_pk = es256_pk_new()) == NULL)
640afa8e06SEd Maste errx(1, "es256_pk_new");
650afa8e06SEd Maste
660afa8e06SEd Maste if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK)
670afa8e06SEd Maste errx(1, "es256_pk_from_EC_KEY");
680afa8e06SEd Maste
690afa8e06SEd Maste pk = es256_pk;
700afa8e06SEd Maste EC_KEY_free(ec);
710afa8e06SEd Maste ec = NULL;
720afa8e06SEd Maste
730afa8e06SEd Maste break;
74*2ccfa855SEd Maste case COSE_ES384:
75*2ccfa855SEd Maste if ((ec = read_ec_pubkey(key)) == NULL)
76*2ccfa855SEd Maste errx(1, "read_ec_pubkey");
77*2ccfa855SEd Maste
78*2ccfa855SEd Maste if ((es384_pk = es384_pk_new()) == NULL)
79*2ccfa855SEd Maste errx(1, "es384_pk_new");
80*2ccfa855SEd Maste
81*2ccfa855SEd Maste if (es384_pk_from_EC_KEY(es384_pk, ec) != FIDO_OK)
82*2ccfa855SEd Maste errx(1, "es384_pk_from_EC_KEY");
83*2ccfa855SEd Maste
84*2ccfa855SEd Maste pk = es384_pk;
85*2ccfa855SEd Maste EC_KEY_free(ec);
86*2ccfa855SEd Maste ec = NULL;
87*2ccfa855SEd Maste
88*2ccfa855SEd Maste break;
890afa8e06SEd Maste case COSE_RS256:
900afa8e06SEd Maste if ((rsa = read_rsa_pubkey(key)) == NULL)
910afa8e06SEd Maste errx(1, "read_rsa_pubkey");
920afa8e06SEd Maste
930afa8e06SEd Maste if ((rs256_pk = rs256_pk_new()) == NULL)
940afa8e06SEd Maste errx(1, "rs256_pk_new");
950afa8e06SEd Maste
960afa8e06SEd Maste if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK)
970afa8e06SEd Maste errx(1, "rs256_pk_from_RSA");
980afa8e06SEd Maste
990afa8e06SEd Maste pk = rs256_pk;
1000afa8e06SEd Maste RSA_free(rsa);
1010afa8e06SEd Maste rsa = NULL;
1020afa8e06SEd Maste
1030afa8e06SEd Maste break;
1040afa8e06SEd Maste case COSE_EDDSA:
1050afa8e06SEd Maste if ((eddsa = read_eddsa_pubkey(key)) == NULL)
1060afa8e06SEd Maste errx(1, "read_eddsa_pubkey");
1070afa8e06SEd Maste
1080afa8e06SEd Maste if ((eddsa_pk = eddsa_pk_new()) == NULL)
1090afa8e06SEd Maste errx(1, "eddsa_pk_new");
1100afa8e06SEd Maste
1110afa8e06SEd Maste if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK)
1120afa8e06SEd Maste errx(1, "eddsa_pk_from_EVP_PKEY");
1130afa8e06SEd Maste
1140afa8e06SEd Maste pk = eddsa_pk;
1150afa8e06SEd Maste EVP_PKEY_free(eddsa);
1160afa8e06SEd Maste eddsa = NULL;
1170afa8e06SEd Maste
1180afa8e06SEd Maste break;
1190afa8e06SEd Maste default:
1200afa8e06SEd Maste errx(1, "unknown credential type %d", type);
1210afa8e06SEd Maste }
1220afa8e06SEd Maste
1230afa8e06SEd Maste if ((assert = fido_assert_new()) == NULL)
1240afa8e06SEd Maste errx(1, "fido_assert_new");
1250afa8e06SEd Maste
1260afa8e06SEd Maste /* client data hash */
127f540a430SEd Maste r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
1280afa8e06SEd Maste if (r != FIDO_OK)
129f540a430SEd Maste errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
1300afa8e06SEd Maste
1310afa8e06SEd Maste /* relying party */
1320afa8e06SEd Maste r = fido_assert_set_rp(assert, "localhost");
1330afa8e06SEd Maste if (r != FIDO_OK)
1340afa8e06SEd Maste errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
1350afa8e06SEd Maste
1360afa8e06SEd Maste /* authdata */
1370afa8e06SEd Maste r = fido_assert_set_count(assert, 1);
1380afa8e06SEd Maste if (r != FIDO_OK)
1390afa8e06SEd Maste errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r);
1400afa8e06SEd Maste r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len);
1410afa8e06SEd Maste if (r != FIDO_OK)
1420afa8e06SEd Maste errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r);
1430afa8e06SEd Maste
1440afa8e06SEd Maste /* extension */
1450afa8e06SEd Maste r = fido_assert_set_extensions(assert, ext);
1460afa8e06SEd Maste if (r != FIDO_OK)
1470afa8e06SEd Maste errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
1480afa8e06SEd Maste r);
1490afa8e06SEd Maste
1500afa8e06SEd Maste /* user presence */
1510afa8e06SEd Maste if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
1520afa8e06SEd Maste errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
1530afa8e06SEd Maste
1540afa8e06SEd Maste /* user verification */
1550afa8e06SEd Maste if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
1560afa8e06SEd Maste errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
1570afa8e06SEd Maste
1580afa8e06SEd Maste /* sig */
1590afa8e06SEd Maste r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
1600afa8e06SEd Maste if (r != FIDO_OK)
1610afa8e06SEd Maste errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r);
1620afa8e06SEd Maste
1630afa8e06SEd Maste r = fido_assert_verify(assert, 0, type, pk);
1640afa8e06SEd Maste if (r != FIDO_OK)
1650afa8e06SEd Maste errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r);
1660afa8e06SEd Maste
1670afa8e06SEd Maste es256_pk_free(&es256_pk);
168*2ccfa855SEd Maste es384_pk_free(&es384_pk);
1690afa8e06SEd Maste rs256_pk_free(&rs256_pk);
1700afa8e06SEd Maste eddsa_pk_free(&eddsa_pk);
1710afa8e06SEd Maste
1720afa8e06SEd Maste fido_assert_free(&assert);
1730afa8e06SEd Maste }
1740afa8e06SEd Maste
1750afa8e06SEd Maste int
main(int argc,char ** argv)1760afa8e06SEd Maste main(int argc, char **argv)
1770afa8e06SEd Maste {
1780afa8e06SEd Maste bool up = false;
1790afa8e06SEd Maste bool uv = false;
1800afa8e06SEd Maste bool u2f = false;
1810afa8e06SEd Maste fido_dev_t *dev = NULL;
1820afa8e06SEd Maste fido_assert_t *assert = NULL;
1830afa8e06SEd Maste const char *pin = NULL;
1840afa8e06SEd Maste const char *blobkey_out = NULL;
1850afa8e06SEd Maste const char *hmac_out = NULL;
1860afa8e06SEd Maste unsigned char *body = NULL;
187f540a430SEd Maste long long ms = 0;
1880afa8e06SEd Maste size_t len;
1890afa8e06SEd Maste int type = COSE_ES256;
1900afa8e06SEd Maste int ext = 0;
1910afa8e06SEd Maste int ch;
1920afa8e06SEd Maste int r;
1930afa8e06SEd Maste
1940afa8e06SEd Maste if ((assert = fido_assert_new()) == NULL)
1950afa8e06SEd Maste errx(1, "fido_assert_new");
1960afa8e06SEd Maste
1970afa8e06SEd Maste while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) {
1980afa8e06SEd Maste switch (ch) {
1990afa8e06SEd Maste case 'P':
2000afa8e06SEd Maste pin = optarg;
2010afa8e06SEd Maste break;
2020afa8e06SEd Maste case 'T':
203f540a430SEd Maste if (base10(optarg, &ms) < 0)
2040afa8e06SEd Maste errx(1, "base10: %s", optarg);
205f540a430SEd Maste if (ms <= 0 || ms > 30)
2060afa8e06SEd Maste errx(1, "-T: %s must be in (0,30]", optarg);
207f540a430SEd Maste ms *= 1000; /* seconds to milliseconds */
2080afa8e06SEd Maste break;
2090afa8e06SEd Maste case 'a':
2100afa8e06SEd Maste if (read_blob(optarg, &body, &len) < 0)
2110afa8e06SEd Maste errx(1, "read_blob: %s", optarg);
2120afa8e06SEd Maste if ((r = fido_assert_allow_cred(assert, body,
2130afa8e06SEd Maste len)) != FIDO_OK)
2140afa8e06SEd Maste errx(1, "fido_assert_allow_cred: %s (0x%x)",
2150afa8e06SEd Maste fido_strerr(r), r);
2160afa8e06SEd Maste free(body);
2170afa8e06SEd Maste body = NULL;
2180afa8e06SEd Maste break;
2190afa8e06SEd Maste case 'b':
2200afa8e06SEd Maste ext |= FIDO_EXT_LARGEBLOB_KEY;
2210afa8e06SEd Maste blobkey_out = optarg;
2220afa8e06SEd Maste break;
2230afa8e06SEd Maste case 'h':
2240afa8e06SEd Maste hmac_out = optarg;
2250afa8e06SEd Maste break;
2260afa8e06SEd Maste case 'p':
2270afa8e06SEd Maste up = true;
2280afa8e06SEd Maste break;
2290afa8e06SEd Maste case 's':
2300afa8e06SEd Maste ext |= FIDO_EXT_HMAC_SECRET;
2310afa8e06SEd Maste if (read_blob(optarg, &body, &len) < 0)
2320afa8e06SEd Maste errx(1, "read_blob: %s", optarg);
2330afa8e06SEd Maste if ((r = fido_assert_set_hmac_salt(assert, body,
2340afa8e06SEd Maste len)) != FIDO_OK)
2350afa8e06SEd Maste errx(1, "fido_assert_set_hmac_salt: %s (0x%x)",
2360afa8e06SEd Maste fido_strerr(r), r);
2370afa8e06SEd Maste free(body);
2380afa8e06SEd Maste body = NULL;
2390afa8e06SEd Maste break;
2400afa8e06SEd Maste case 't':
241*2ccfa855SEd Maste if (strcmp(optarg, "es256") == 0)
2420afa8e06SEd Maste type = COSE_ES256;
243*2ccfa855SEd Maste else if (strcmp(optarg, "es384") == 0)
244*2ccfa855SEd Maste type = COSE_ES384;
245*2ccfa855SEd Maste else if (strcmp(optarg, "rs256") == 0)
2460afa8e06SEd Maste type = COSE_RS256;
2470afa8e06SEd Maste else if (strcmp(optarg, "eddsa") == 0)
2480afa8e06SEd Maste type = COSE_EDDSA;
2490afa8e06SEd Maste else
2500afa8e06SEd Maste errx(1, "unknown type %s", optarg);
2510afa8e06SEd Maste break;
2520afa8e06SEd Maste case 'u':
2530afa8e06SEd Maste u2f = true;
2540afa8e06SEd Maste break;
2550afa8e06SEd Maste case 'v':
2560afa8e06SEd Maste uv = true;
2570afa8e06SEd Maste break;
2580afa8e06SEd Maste default:
2590afa8e06SEd Maste usage();
2600afa8e06SEd Maste }
2610afa8e06SEd Maste }
2620afa8e06SEd Maste
2630afa8e06SEd Maste argc -= optind;
2640afa8e06SEd Maste argv += optind;
2650afa8e06SEd Maste
2660afa8e06SEd Maste if (argc != 2)
2670afa8e06SEd Maste usage();
2680afa8e06SEd Maste
2690afa8e06SEd Maste fido_init(0);
2700afa8e06SEd Maste
2710afa8e06SEd Maste if ((dev = fido_dev_new()) == NULL)
2720afa8e06SEd Maste errx(1, "fido_dev_new");
2730afa8e06SEd Maste
2740afa8e06SEd Maste r = fido_dev_open(dev, argv[1]);
2750afa8e06SEd Maste if (r != FIDO_OK)
2760afa8e06SEd Maste errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
2770afa8e06SEd Maste if (u2f)
2780afa8e06SEd Maste fido_dev_force_u2f(dev);
2790afa8e06SEd Maste
2800afa8e06SEd Maste /* client data hash */
281f540a430SEd Maste r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
2820afa8e06SEd Maste if (r != FIDO_OK)
283f540a430SEd Maste errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
2840afa8e06SEd Maste
2850afa8e06SEd Maste /* relying party */
2860afa8e06SEd Maste r = fido_assert_set_rp(assert, "localhost");
2870afa8e06SEd Maste if (r != FIDO_OK)
2880afa8e06SEd Maste errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
2890afa8e06SEd Maste
2900afa8e06SEd Maste /* extensions */
2910afa8e06SEd Maste r = fido_assert_set_extensions(assert, ext);
2920afa8e06SEd Maste if (r != FIDO_OK)
2930afa8e06SEd Maste errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
2940afa8e06SEd Maste r);
2950afa8e06SEd Maste
2960afa8e06SEd Maste /* user presence */
2970afa8e06SEd Maste if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
2980afa8e06SEd Maste errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
2990afa8e06SEd Maste
3000afa8e06SEd Maste /* user verification */
3010afa8e06SEd Maste if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
3020afa8e06SEd Maste errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
3030afa8e06SEd Maste
304f540a430SEd Maste /* timeout */
305f540a430SEd Maste if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK)
306f540a430SEd Maste errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r);
3070afa8e06SEd Maste
308f540a430SEd Maste if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
3090afa8e06SEd Maste fido_dev_cancel(dev);
3100afa8e06SEd Maste errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r);
3110afa8e06SEd Maste }
3120afa8e06SEd Maste
3130afa8e06SEd Maste r = fido_dev_close(dev);
3140afa8e06SEd Maste if (r != FIDO_OK)
3150afa8e06SEd Maste errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
3160afa8e06SEd Maste
3170afa8e06SEd Maste fido_dev_free(&dev);
3180afa8e06SEd Maste
3190afa8e06SEd Maste if (fido_assert_count(assert) != 1)
3200afa8e06SEd Maste errx(1, "fido_assert_count: %d signatures returned",
3210afa8e06SEd Maste (int)fido_assert_count(assert));
3220afa8e06SEd Maste
3230afa8e06SEd Maste /* when verifying, pin implies uv */
3240afa8e06SEd Maste if (pin)
3250afa8e06SEd Maste uv = true;
3260afa8e06SEd Maste
3270afa8e06SEd Maste verify_assert(type, fido_assert_authdata_ptr(assert, 0),
3280afa8e06SEd Maste fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0),
3290afa8e06SEd Maste fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]);
3300afa8e06SEd Maste
3310afa8e06SEd Maste if (hmac_out != NULL) {
3320afa8e06SEd Maste /* extract the hmac secret */
3330afa8e06SEd Maste if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0),
3340afa8e06SEd Maste fido_assert_hmac_secret_len(assert, 0)) < 0)
3350afa8e06SEd Maste errx(1, "write_blob");
3360afa8e06SEd Maste }
3370afa8e06SEd Maste
3380afa8e06SEd Maste if (blobkey_out != NULL) {
3390afa8e06SEd Maste /* extract the hmac secret */
3400afa8e06SEd Maste if (write_blob(blobkey_out,
3410afa8e06SEd Maste fido_assert_largeblob_key_ptr(assert, 0),
3420afa8e06SEd Maste fido_assert_largeblob_key_len(assert, 0)) < 0)
3430afa8e06SEd Maste errx(1, "write_blob");
3440afa8e06SEd Maste }
3450afa8e06SEd Maste
3460afa8e06SEd Maste fido_assert_free(&assert);
3470afa8e06SEd Maste
3480afa8e06SEd Maste exit(0);
3490afa8e06SEd Maste }
350