Home | History | Annotate | Line # | Download | only in examples
assert.c revision 1.1
      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