Home | History | Annotate | Line # | Download | only in examples
assert.c revision 1.1.1.3
      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 <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 cdh[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_hash(assert, cdh, sizeof(cdh));
    110 	if (r != FIDO_OK)
    111 		errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)",
    112 		    fido_strerr(r), r);
    113 
    114 	/* relying party */
    115 	r = fido_assert_set_rp(assert, "localhost");
    116 	if (r != FIDO_OK)
    117 		errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
    118 
    119 	/* authdata */
    120 	r = fido_assert_set_count(assert, 1);
    121 	if (r != FIDO_OK)
    122 		errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r);
    123 	r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len);
    124 	if (r != FIDO_OK)
    125 		errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r);
    126 
    127 	/* extension */
    128 	r = fido_assert_set_extensions(assert, ext);
    129 	if (r != FIDO_OK)
    130 		errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
    131 		    r);
    132 
    133 	/* user presence */
    134 	if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
    135 		errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
    136 
    137 	/* user verification */
    138 	if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
    139 		errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
    140 
    141 	/* sig */
    142 	r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
    143 	if (r != FIDO_OK)
    144 		errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r);
    145 
    146 	r = fido_assert_verify(assert, 0, type, pk);
    147 	if (r != FIDO_OK)
    148 		errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r);
    149 
    150 	es256_pk_free(&es256_pk);
    151 	rs256_pk_free(&rs256_pk);
    152 	eddsa_pk_free(&eddsa_pk);
    153 
    154 	fido_assert_free(&assert);
    155 }
    156 
    157 int
    158 main(int argc, char **argv)
    159 {
    160 	bool		 up = false;
    161 	bool		 uv = false;
    162 	bool		 u2f = false;
    163 	fido_dev_t	*dev = NULL;
    164 	fido_assert_t	*assert = NULL;
    165 	const char	*pin = NULL;
    166 	const char	*blobkey_out = 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:b: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 'b':
    206 			ext |= FIDO_EXT_LARGEBLOB_KEY;
    207 			blobkey_out = optarg;
    208 			break;
    209 		case 'h':
    210 			hmac_out = optarg;
    211 			break;
    212 		case 'p':
    213 			up = true;
    214 			break;
    215 		case 's':
    216 			ext |= FIDO_EXT_HMAC_SECRET;
    217 			if (read_blob(optarg, &body, &len) < 0)
    218 				errx(1, "read_blob: %s", optarg);
    219 			if ((r = fido_assert_set_hmac_salt(assert, body,
    220 			    len)) != FIDO_OK)
    221 				errx(1, "fido_assert_set_hmac_salt: %s (0x%x)",
    222 				    fido_strerr(r), r);
    223 			free(body);
    224 			body = NULL;
    225 			break;
    226 		case 't':
    227 			if (strcmp(optarg, "ecdsa") == 0)
    228 				type = COSE_ES256;
    229 			else if (strcmp(optarg, "rsa") == 0)
    230 				type = COSE_RS256;
    231 			else if (strcmp(optarg, "eddsa") == 0)
    232 				type = COSE_EDDSA;
    233 			else
    234 				errx(1, "unknown type %s", optarg);
    235 			break;
    236 		case 'u':
    237 			u2f = true;
    238 			break;
    239 		case 'v':
    240 			uv = true;
    241 			break;
    242 		default:
    243 			usage();
    244 		}
    245 	}
    246 
    247 	argc -= optind;
    248 	argv += optind;
    249 
    250 	if (argc != 2)
    251 		usage();
    252 
    253 	fido_init(0);
    254 
    255 	if ((dev = fido_dev_new()) == NULL)
    256 		errx(1, "fido_dev_new");
    257 
    258 	r = fido_dev_open(dev, argv[1]);
    259 	if (r != FIDO_OK)
    260 		errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
    261 	if (u2f)
    262 		fido_dev_force_u2f(dev);
    263 
    264 	/* client data hash */
    265 	r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh));
    266 	if (r != FIDO_OK)
    267 		errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)",
    268 		    fido_strerr(r), r);
    269 
    270 	/* relying party */
    271 	r = fido_assert_set_rp(assert, "localhost");
    272 	if (r != FIDO_OK)
    273 		errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r);
    274 
    275 	/* extensions */
    276 	r = fido_assert_set_extensions(assert, ext);
    277 	if (r != FIDO_OK)
    278 		errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r),
    279 		    r);
    280 
    281 	/* user presence */
    282 	if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
    283 		errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r);
    284 
    285 	/* user verification */
    286 	if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
    287 		errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
    288 
    289 #ifdef SIGNAL_EXAMPLE
    290 	prepare_signal_handler(SIGINT);
    291 	if (seconds) {
    292 		prepare_signal_handler(SIGALRM);
    293 		alarm((unsigned)seconds);
    294 	}
    295 #endif
    296 
    297 	r = fido_dev_get_assert(dev, assert, pin);
    298 	if (r != FIDO_OK) {
    299 #ifdef SIGNAL_EXAMPLE
    300 		if (got_signal)
    301 			fido_dev_cancel(dev);
    302 #endif
    303 		errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r);
    304 	}
    305 
    306 	r = fido_dev_close(dev);
    307 	if (r != FIDO_OK)
    308 		errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
    309 
    310 	fido_dev_free(&dev);
    311 
    312 	if (fido_assert_count(assert) != 1)
    313 		errx(1, "fido_assert_count: %d signatures returned",
    314 		    (int)fido_assert_count(assert));
    315 
    316 	/* when verifying, pin implies uv */
    317 	if (pin)
    318 		uv = true;
    319 
    320 	verify_assert(type, fido_assert_authdata_ptr(assert, 0),
    321 	    fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0),
    322 	    fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]);
    323 
    324 	if (hmac_out != NULL) {
    325 		/* extract the hmac secret */
    326 		if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0),
    327 		    fido_assert_hmac_secret_len(assert, 0)) < 0)
    328 			errx(1, "write_blob");
    329 	}
    330 
    331 	if (blobkey_out != NULL) {
    332 		/* extract the hmac secret */
    333 		if (write_blob(blobkey_out,
    334 		    fido_assert_largeblob_key_ptr(assert, 0),
    335 		    fido_assert_largeblob_key_len(assert, 0)) < 0)
    336 			errx(1, "write_blob");
    337 	}
    338 
    339 	fido_assert_free(&assert);
    340 
    341 	exit(0);
    342 }
    343