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