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 *
prepare_assert(FILE * in_f,int flags)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 *
load_pubkey(int type,const char * file)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
assert_verify(int argc,char ** argv)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