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