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
24static fido_assert_t *
25prepare_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
91static void *
92load_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
151int
152assert_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