xref: /freebsd/contrib/bearssl/tools/verify.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
1 /*
2  * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <errno.h>
30 
31 #include "brssl.h"
32 #include "bearssl.h"
33 
34 static unsigned
35 rsa_bit_length(const br_rsa_public_key *pk)
36 {
37 	size_t u;
38 	unsigned x, bl;
39 
40 	for (u = 0; u < pk->nlen; u ++) {
41 		if (pk->n[u] != 0) {
42 			break;
43 		}
44 	}
45 	if (u == pk->nlen) {
46 		return 0;
47 	}
48 	bl = (unsigned)(pk->nlen - u - 1) << 3;
49 	x = pk->n[u];
50 	while (x != 0) {
51 		bl ++;
52 		x >>= 1;
53 	}
54 	return bl;
55 }
56 
57 static void
58 print_rsa(const br_rsa_public_key *pk, int print_text, int print_C)
59 {
60 	if (print_text) {
61 		size_t u;
62 
63 		printf("n = ");
64 		for (u = 0; u < pk->nlen; u ++) {
65 			printf("%02X", pk->n[u]);
66 		}
67 		printf("\n");
68 		printf("e = ");
69 		for (u = 0; u < pk->elen; u ++) {
70 			printf("%02X", pk->e[u]);
71 		}
72 		printf("\n");
73 	}
74 	if (print_C) {
75 		size_t u;
76 
77 		printf("\nstatic const unsigned char RSA_N[] = {");
78 		for (u = 0; u < pk->nlen; u ++) {
79 			if (u != 0) {
80 				printf(",");
81 			}
82 			if (u % 12 == 0) {
83 				printf("\n\t");
84 			} else {
85 				printf(" ");
86 			}
87 			printf("0x%02X", pk->n[u]);
88 		}
89 		printf("\n};\n");
90 		printf("\nstatic const unsigned char RSA_E[] = {");
91 		for (u = 0; u < pk->elen; u ++) {
92 			if (u != 0) {
93 				printf(",");
94 			}
95 			if (u % 12 == 0) {
96 				printf("\n\t");
97 			} else {
98 				printf(" ");
99 			}
100 			printf("0x%02X", pk->e[u]);
101 		}
102 		printf("\n};\n");
103 		printf("\nstatic const br_rsa_public_key RSA = {\n");
104 		printf("\t(unsigned char *)RSA_N, sizeof RSA_N,\n");
105 		printf("\t(unsigned char *)RSA_E, sizeof RSA_E\n");
106 		printf("};\n");
107 	}
108 }
109 
110 static void
111 print_ec(const br_ec_public_key *pk, int print_text, int print_C)
112 {
113 	if (print_text) {
114 		size_t u;
115 
116 		printf("Q = ");
117 		for (u = 0; u < pk->qlen; u ++) {
118 			printf("%02X", pk->q[u]);
119 		}
120 		printf("\n");
121 	}
122 	if (print_C) {
123 		size_t u;
124 
125 		printf("\nstatic const unsigned char EC_Q[] = {");
126 		for (u = 0; u < pk->qlen; u ++) {
127 			if (u != 0) {
128 				printf(",");
129 			}
130 			if (u % 12 == 0) {
131 				printf("\n\t");
132 			} else {
133 				printf(" ");
134 			}
135 			printf("0x%02X", pk->q[u]);
136 		}
137 		printf("\n};\n");
138 		printf("\nstatic const br_ec_public_key EC = {\n");
139 		printf("\t%d,\n", pk->curve);
140 		printf("\t(unsigned char *)EC_Q, sizeof EC_Q\n");
141 		printf("};\n");
142 	}
143 }
144 
145 static void
146 usage_verify(void)
147 {
148 	fprintf(stderr,
149 "usage: brssl verify [ options ] file...\n");
150 	fprintf(stderr,
151 "options:\n");
152 	fprintf(stderr,
153 "   -q            suppress verbose messages\n");
154 	fprintf(stderr,
155 "   -sni name     check presence of a specific server name\n");
156 	fprintf(stderr,
157 "   -CA file      add certificates in 'file' to trust anchors\n");
158 	fprintf(stderr,
159 "   -text         print public key details (human-readable)\n");
160 	fprintf(stderr,
161 "   -C            print public key details (C code)\n");
162 }
163 
164 typedef VECTOR(br_x509_certificate) cert_list;
165 
166 static void
167 free_cert_contents(br_x509_certificate *xc)
168 {
169 	xfree(xc->data);
170 }
171 
172 /* see brssl.h */
173 int
174 do_verify(int argc, char *argv[])
175 {
176 	int retcode;
177 	int verbose;
178 	int i;
179 	const char *sni;
180 	anchor_list anchors = VEC_INIT;
181 	cert_list chain = VEC_INIT;
182 	size_t u;
183 	br_x509_minimal_context mc;
184 	int err;
185 	int print_text, print_C;
186 	br_x509_pkey *pk;
187 	const br_x509_pkey *tpk;
188 	unsigned usages;
189 
190 	retcode = 0;
191 	verbose = 1;
192 	sni = NULL;
193 	print_text = 0;
194 	print_C = 0;
195 	pk = NULL;
196 	for (i = 0; i < argc; i ++) {
197 		const char *arg;
198 
199 		arg = argv[i];
200 		if (arg[0] != '-') {
201 			br_x509_certificate *xcs;
202 			size_t num;
203 
204 			xcs = read_certificates(arg, &num);
205 			if (xcs == NULL) {
206 				usage_verify();
207 				goto verify_exit_error;
208 			}
209 			VEC_ADDMANY(chain, xcs, num);
210 			xfree(xcs);
211 			continue;
212 		}
213 		if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
214 			verbose = 1;
215 		} else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
216 			verbose = 0;
217 		} else if (eqstr(arg, "-sni")) {
218 			if (++ i >= argc) {
219 				fprintf(stderr,
220 					"ERROR: no argument for '-sni'\n");
221 				usage_verify();
222 				goto verify_exit_error;
223 			}
224 			if (sni != NULL) {
225 				fprintf(stderr, "ERROR: duplicate SNI\n");
226 				usage_verify();
227 				goto verify_exit_error;
228 			}
229 			sni = argv[i];
230 			continue;
231 		} else if (eqstr(arg, "-CA")) {
232 			if (++ i >= argc) {
233 				fprintf(stderr,
234 					"ERROR: no argument for '-CA'\n");
235 				usage_verify();
236 				goto verify_exit_error;
237 			}
238 			arg = argv[i];
239 			if (read_trust_anchors(&anchors, arg) == 0) {
240 				usage_verify();
241 				goto verify_exit_error;
242 			}
243 			continue;
244 		} else if (eqstr(arg, "-text")) {
245 			print_text = 1;
246 		} else if (eqstr(arg, "-C")) {
247 			print_C = 1;
248 		} else {
249 			fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
250 			usage_verify();
251 			goto verify_exit_error;
252 		}
253 	}
254 	if (VEC_LEN(chain) == 0) {
255 		fprintf(stderr, "ERROR: no certificate chain provided\n");
256 		usage_verify();
257 		goto verify_exit_error;
258 	}
259 	br_x509_minimal_init(&mc, &br_sha256_vtable,
260 		&VEC_ELT(anchors, 0), VEC_LEN(anchors));
261 	br_x509_minimal_set_hash(&mc, br_sha1_ID, &br_sha1_vtable);
262 	br_x509_minimal_set_hash(&mc, br_sha224_ID, &br_sha224_vtable);
263 	br_x509_minimal_set_hash(&mc, br_sha256_ID, &br_sha256_vtable);
264 	br_x509_minimal_set_hash(&mc, br_sha384_ID, &br_sha384_vtable);
265 	br_x509_minimal_set_hash(&mc, br_sha512_ID, &br_sha512_vtable);
266 	br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
267 	br_x509_minimal_set_ecdsa(&mc,
268 		&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
269 
270 	mc.vtable->start_chain(&mc.vtable, sni);
271 	for (u = 0; u < VEC_LEN(chain); u ++) {
272 		br_x509_certificate *xc;
273 
274 		xc = &VEC_ELT(chain, u);
275 		mc.vtable->start_cert(&mc.vtable, xc->data_len);
276 		mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
277 		mc.vtable->end_cert(&mc.vtable);
278 	}
279 	err = mc.vtable->end_chain(&mc.vtable);
280 	tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
281 	if (tpk != NULL) {
282 		pk = xpkeydup(tpk);
283 	}
284 
285 	if (err == 0) {
286 		if (verbose) {
287 			int hkx;
288 
289 			fprintf(stderr, "Validation success; usages:");
290 			hkx = 0;
291 			if (usages & BR_KEYTYPE_KEYX) {
292 				fprintf(stderr, " key exchange");
293 				hkx = 1;
294 			}
295 			if (usages & BR_KEYTYPE_SIGN) {
296 				if (hkx) {
297 					fprintf(stderr, ",");
298 				}
299 				fprintf(stderr, " signature");
300 			}
301 			fprintf(stderr, "\n");
302 		}
303 	} else {
304 		if (verbose) {
305 			const char *errname, *errmsg;
306 
307 			fprintf(stderr, "Validation failed, err = %d", err);
308 			errname = find_error_name(err, &errmsg);
309 			if (errname != NULL) {
310 				fprintf(stderr, " (%s): %s\n", errname, errmsg);
311 			} else {
312 				fprintf(stderr, " (unknown)\n");
313 			}
314 		}
315 		retcode = -1;
316 	}
317 	if (pk != NULL) {
318 		switch (pk->key_type) {
319 		case BR_KEYTYPE_RSA:
320 			if (verbose) {
321 				fprintf(stderr, "Key type: RSA (%u bits)\n",
322 					rsa_bit_length(&pk->key.rsa));
323 			}
324 			print_rsa(&pk->key.rsa, print_text, print_C);
325 			break;
326 		case BR_KEYTYPE_EC:
327 			if (verbose) {
328 				fprintf(stderr, "Key type: EC (%s)\n",
329 					ec_curve_name(pk->key.ec.curve));
330 			}
331 			print_ec(&pk->key.ec, print_text, print_C);
332 			break;
333 		default:
334 			if (verbose) {
335 				fprintf(stderr, "Unknown key type\n");
336 				break;
337 			}
338 		}
339 	}
340 
341 	/*
342 	 * Release allocated structures.
343 	 */
344 verify_exit:
345 	VEC_CLEAREXT(anchors, &free_ta_contents);
346 	VEC_CLEAREXT(chain, &free_cert_contents);
347 	xfreepkey(pk);
348 	return retcode;
349 
350 verify_exit_error:
351 	retcode = -1;
352 	goto verify_exit;
353 }
354