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