xref: /netbsd-src/external/bsd/libfido2/dist/tools/assert_verify.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 fido_assert_t *
24 prepare_assert(FILE *in_f, int flags)
25 {
26 	fido_assert_t *assert = NULL;
27 	struct blob cdh;
28 	struct blob authdata;
29 	struct blob sig;
30 	char *rpid = NULL;
31 	int r;
32 
33 	memset(&cdh, 0, sizeof(cdh));
34 	memset(&authdata, 0, sizeof(authdata));
35 	memset(&sig, 0, sizeof(sig));
36 
37 	r = base64_read(in_f, &cdh);
38 	r |= string_read(in_f, &rpid);
39 	r |= base64_read(in_f, &authdata);
40 	r |= base64_read(in_f, &sig);
41 	if (r < 0)
42 		errx(1, "input error");
43 
44 	if (flags & FLAG_DEBUG) {
45 		fprintf(stderr, "client data hash:\n");
46 		xxd(cdh.ptr, cdh.len);
47 		fprintf(stderr, "relying party id: %s\n", rpid);
48 		fprintf(stderr, "authenticator data:\n");
49 		xxd(authdata.ptr, authdata.len);
50 		fprintf(stderr, "signature:\n");
51 		xxd(sig.ptr, sig.len);
52 	}
53 
54 	if ((assert = fido_assert_new()) == NULL)
55 		errx(1, "fido_assert_new");
56 	if ((r = fido_assert_set_count(assert, 1)) != FIDO_OK)
57 		errx(1, "fido_assert_count: %s", fido_strerr(r));
58 
59 	if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr,
60 	    cdh.len)) != FIDO_OK ||
61 	    (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK ||
62 	    (r = fido_assert_set_authdata(assert, 0, authdata.ptr,
63 	    authdata.len)) != FIDO_OK ||
64 	    (r = fido_assert_set_sig(assert, 0, sig.ptr, sig.len)) != FIDO_OK)
65 		errx(1, "fido_assert_set: %s", fido_strerr(r));
66 
67 	if (flags & FLAG_UP) {
68 		if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
69 			errx(1, "fido_assert_set_up: %s", fido_strerr(r));
70 	}
71 	if (flags & FLAG_UV) {
72 		if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
73 			errx(1, "fido_assert_set_uv: %s", fido_strerr(r));
74 	}
75 	if (flags & FLAG_HMAC) {
76 		if ((r = fido_assert_set_extensions(assert,
77 		    FIDO_EXT_HMAC_SECRET)) != FIDO_OK)
78 			errx(1, "fido_assert_set_extensions: %s",
79 			    fido_strerr(r));
80 	}
81 
82 	free(cdh.ptr);
83 	free(authdata.ptr);
84 	free(sig.ptr);
85 	free(rpid);
86 
87 	return (assert);
88 }
89 
90 static void *
91 load_pubkey(int type, const char *file)
92 {
93 	EC_KEY *ec = NULL;
94 	RSA *rsa = NULL;
95 	EVP_PKEY *eddsa = NULL;
96 	es256_pk_t *es256_pk = NULL;
97 	rs256_pk_t *rs256_pk = NULL;
98 	eddsa_pk_t *eddsa_pk = NULL;
99 	void *pk = NULL;
100 
101 	if (type == COSE_ES256) {
102 		if ((ec = read_ec_pubkey(file)) == NULL)
103 			errx(1, "read_ec_pubkey");
104 		if ((es256_pk = es256_pk_new()) == NULL)
105 			errx(1, "es256_pk_new");
106 		if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK)
107 			errx(1, "es256_pk_from_EC_KEY");
108 
109 		pk = es256_pk;
110 		EC_KEY_free(ec);
111 	} else if (type == COSE_RS256) {
112 		if ((rsa = read_rsa_pubkey(file)) == NULL)
113 			errx(1, "read_rsa_pubkey");
114 		if ((rs256_pk = rs256_pk_new()) == NULL)
115 			errx(1, "rs256_pk_new");
116 		if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK)
117 			errx(1, "rs256_pk_from_RSA");
118 
119 		pk = rs256_pk;
120 		RSA_free(rsa);
121 	} else if (type == COSE_EDDSA) {
122 		if ((eddsa = read_eddsa_pubkey(file)) == NULL)
123 			errx(1, "read_eddsa_pubkey");
124 		if ((eddsa_pk = eddsa_pk_new()) == NULL)
125 			errx(1, "eddsa_pk_new");
126 		if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK)
127 			errx(1, "eddsa_pk_from_EVP_PKEY");
128 
129 		pk = eddsa_pk;
130 		EVP_PKEY_free(eddsa);
131 	}
132 
133 	return (pk);
134 }
135 
136 int
137 assert_verify(int argc, char **argv)
138 {
139 	fido_assert_t *assert = NULL;
140 	void *pk = NULL;
141 	char *in_path = NULL;
142 	FILE *in_f = NULL;
143 	int type = COSE_ES256;
144 	int flags = 0;
145 	int ch;
146 	int r;
147 
148 	while ((ch = getopt(argc, argv, "dhi:pv")) != -1) {
149 		switch (ch) {
150 		case 'd':
151 			flags |= FLAG_DEBUG;
152 			break;
153 		case 'h':
154 			flags |= FLAG_HMAC;
155 			break;
156 		case 'i':
157 			in_path = optarg;
158 			break;
159 		case 'p':
160 			flags |= FLAG_UP;
161 			break;
162 		case 'v':
163 			flags |= FLAG_UV;
164 			break;
165 		default:
166 			usage();
167 		}
168 	}
169 
170 	argc -= optind;
171 	argv += optind;
172 
173 	if (argc < 1 || argc > 2)
174 		usage();
175 
176 	in_f = open_read(in_path);
177 
178 	if (argc > 1 && cose_type(argv[1], &type) < 0)
179 		errx(1, "unknown type %s", argv[1]);
180 
181 	fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
182 
183 	pk = load_pubkey(type, argv[0]);
184 	assert = prepare_assert(in_f, flags);
185 	if ((r = fido_assert_verify(assert, 0, type, pk)) != FIDO_OK)
186 		errx(1, "fido_assert_verify: %s", fido_strerr(r));
187 	fido_assert_free(&assert);
188 
189 	fclose(in_f);
190 	in_f = NULL;
191 
192 	exit(0);
193 }
194