xref: /freebsd/lib/libsecureboot/brf.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1 // The functions here are derrived from BearSSL/tools/*.c
2 // When that is refactored suitably we can use them directly.
3 /*
4  * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 #include <sys/cdefs.h>
27 #define NEED_BRSSL_H
28 #include "libsecureboot-priv.h"
29 #include <brssl.h>
30 
31 
32 static int
is_ign(int c)33 is_ign(int c)
34 {
35 	if (c == 0) {
36 		return (0);
37 	}
38 	if (c <= 32 || c == '-' || c == '_' || c == '.'
39 		|| c == '/' || c == '+' || c == ':')
40 	{
41 		return (1);
42 	}
43 	return (0);
44 }
45 
46 /*
47  * Get next non-ignored character, normalised:
48  *    ASCII letters are converted to lowercase
49  *    control characters, space, '-', '_', '.', '/', '+' and ':' are ignored
50  * A terminating zero is returned as 0.
51  */
52 static int
next_char(const char ** ps,const char * limit)53 next_char(const char **ps, const char *limit)
54 {
55 	for (;;) {
56 		int c;
57 
58 		if (*ps == limit) {
59 			return (0);
60 		}
61 		c = *(*ps) ++;
62 		if (c == 0) {
63 			return (0);
64 		}
65 		if (c >= 'A' && c <= 'Z') {
66 			c += 'a' - 'A';
67 		}
68 		if (!is_ign(c)) {
69 			return (c);
70 		}
71 	}
72 }
73 
74 /*
75  * Partial string equality comparison, with normalisation.
76  */
77 static int
eqstr_chunk(const char * s1,size_t s1_len,const char * s2,size_t s2_len)78 eqstr_chunk(const char *s1, size_t s1_len, const char *s2, size_t s2_len)
79 {
80 	const char *lim1, *lim2;
81 
82 	lim1 = s1 + s1_len;
83 	lim2 = s2 + s2_len;
84 	for (;;) {
85 		int c1, c2;
86 
87 		c1 = next_char(&s1, lim1);
88 		c2 = next_char(&s2, lim2);
89 		if (c1 != c2) {
90 			return (0);
91 		}
92 		if (c1 == 0) {
93 			return (1);
94 		}
95 	}
96 }
97 
98 /* see brssl.h */
99 int
eqstr(const char * s1,const char * s2)100 eqstr(const char *s1, const char *s2)
101 {
102 	return (eqstr_chunk(s1, strlen(s1), s2, strlen(s2)));
103 }
104 
105 int
looks_like_DER(const unsigned char * buf,size_t len)106 looks_like_DER(const unsigned char *buf, size_t len)
107 {
108 	int fb;
109 	size_t dlen;
110 
111 	if (len < 2) {
112 		return (0);
113 	}
114 	if (*buf ++ != 0x30) {
115 		return (0);
116 	}
117 	fb = *buf ++;
118 	len -= 2;
119 	if (fb < 0x80) {
120 		return ((size_t)fb == len);
121 	} else if (fb == 0x80) {
122 		return (0);
123 	} else {
124 		fb -= 0x80;
125 		if (len < (size_t)fb + 2) {
126 			return (0);
127 		}
128 		len -= (size_t)fb;
129 		dlen = 0;
130 		while (fb -- > 0) {
131 			if (dlen > (len >> 8)) {
132 				return (0);
133 			}
134 			dlen = (dlen << 8) + (size_t)*buf ++;
135 		}
136 		return (dlen == len);
137 	}
138 }
139 
140 static void
vblob_append(void * cc,const void * data,size_t len)141 vblob_append(void *cc, const void *data, size_t len)
142 {
143 	bvector *bv;
144 
145 	bv = cc;
146 	VEC_ADDMANY(*bv, data, len);
147 }
148 
149 void
free_pem_object_contents(pem_object * po)150 free_pem_object_contents(pem_object *po)
151 {
152 	if (po != NULL) {
153 		xfree(po->name);
154 		xfree(po->data);
155 	}
156 }
157 
158 pem_object *
decode_pem(const void * src,size_t len,size_t * num)159 decode_pem(const void *src, size_t len, size_t *num)
160 {
161 	VECTOR(pem_object) pem_list = VEC_INIT;
162 	br_pem_decoder_context pc;
163 	pem_object po, *pos;
164 	const unsigned char *buf;
165 	bvector bv = VEC_INIT;
166 	int inobj;
167 	int extra_nl;
168 
169 	*num = 0;
170 	br_pem_decoder_init(&pc);
171 	buf = src;
172 	inobj = 0;
173 	po.name = NULL;
174 	po.data = NULL;
175 	po.data_len = 0;
176 	extra_nl = 1;
177 	while (len > 0) {
178 		size_t tlen;
179 
180 		tlen = br_pem_decoder_push(&pc, buf, len);
181 		buf += tlen;
182 		len -= tlen;
183 		switch (br_pem_decoder_event(&pc)) {
184 
185 		case BR_PEM_BEGIN_OBJ:
186 			po.name = xstrdup(br_pem_decoder_name(&pc));
187 			br_pem_decoder_setdest(&pc, vblob_append, &bv);
188 			inobj = 1;
189 			break;
190 
191 		case BR_PEM_END_OBJ:
192 			if (inobj) {
193 				po.data = VEC_TOARRAY(bv);
194 				po.data_len = VEC_LEN(bv);
195 				VEC_ADD(pem_list, po);
196 				VEC_CLEAR(bv);
197 				po.name = NULL;
198 				po.data = NULL;
199 				po.data_len = 0;
200 				inobj = 0;
201 			}
202 			break;
203 
204 		case BR_PEM_ERROR:
205 			xfree(po.name);
206 			VEC_CLEAR(bv);
207 			ve_error_set("ERROR: invalid PEM encoding");
208 			VEC_CLEAREXT(pem_list, &free_pem_object_contents);
209 			return (NULL);
210 		}
211 
212 		/*
213 		 * We add an extra newline at the end, in order to
214 		 * support PEM files that lack the newline on their last
215 		 * line (this is somwehat invalid, but PEM format is not
216 		 * standardised and such files do exist in the wild, so
217 		 * we'd better accept them).
218 		 */
219 		if (len == 0 && extra_nl) {
220 			extra_nl = 0;
221 			buf = (const unsigned char *)"\n";
222 			len = 1;
223 		}
224 	}
225 	if (inobj) {
226 	    ve_error_set("ERROR: unfinished PEM object");
227 		xfree(po.name);
228 		VEC_CLEAR(bv);
229 		VEC_CLEAREXT(pem_list, &free_pem_object_contents);
230 		return (NULL);
231 	}
232 
233 	*num = VEC_LEN(pem_list);
234 	VEC_ADD(pem_list, po);
235 	pos = VEC_TOARRAY(pem_list);
236 	VEC_CLEAR(pem_list);
237 	return (pos);
238 }
239 
240 br_x509_certificate *
parse_certificates(unsigned char * buf,size_t len,size_t * num)241 parse_certificates(unsigned char *buf, size_t len, size_t *num)
242 {
243 	VECTOR(br_x509_certificate) cert_list = VEC_INIT;
244 	pem_object *pos;
245 	size_t u, num_pos;
246 	br_x509_certificate *xcs;
247 	br_x509_certificate dummy;
248 
249 	*num = 0;
250 
251 	/*
252 	 * Check for a DER-encoded certificate.
253 	 */
254 	if (looks_like_DER(buf, len)) {
255 		xcs = xmalloc(2 * sizeof *xcs);
256 		xcs[0].data = buf;
257 		xcs[0].data_len = len;
258 		xcs[1].data = NULL;
259 		xcs[1].data_len = 0;
260 		*num = 1;
261 		return (xcs);
262 	}
263 
264 	pos = decode_pem(buf, len, &num_pos);
265 	if (pos == NULL) {
266 		return (NULL);
267 	}
268 	for (u = 0; u < num_pos; u ++) {
269 		if (eqstr(pos[u].name, "CERTIFICATE")
270 			|| eqstr(pos[u].name, "X509 CERTIFICATE"))
271 		{
272 			br_x509_certificate xc;
273 
274 			xc.data = pos[u].data;
275 			xc.data_len = pos[u].data_len;
276 			pos[u].data = NULL;
277 			VEC_ADD(cert_list, xc);
278 		}
279 	}
280 	for (u = 0; u < num_pos; u ++) {
281 		free_pem_object_contents(&pos[u]);
282 	}
283 	xfree(pos);
284 
285 	if (VEC_LEN(cert_list) == 0) {
286 		return (NULL);
287 	}
288 	*num = VEC_LEN(cert_list);
289 	dummy.data = NULL;
290 	dummy.data_len = 0;
291 	VEC_ADD(cert_list, dummy);
292 	xcs = VEC_TOARRAY(cert_list);
293 	VEC_CLEAR(cert_list);
294 	return (xcs);
295 }
296 
297 br_x509_certificate *
read_certificates(const char * fname,size_t * num)298 read_certificates(const char *fname, size_t *num)
299 {
300 	br_x509_certificate *xcs;
301 	unsigned char *buf;
302 	size_t len;
303 
304 	*num = 0;
305 
306 	/*
307 	 * TODO: reading the whole file is crude; we could parse them
308 	 * in a streamed fashion. But it does not matter much in practice.
309 	 */
310 	buf = read_file(fname, &len);
311 	if (buf == NULL) {
312 		return (NULL);
313 	}
314 	xcs = parse_certificates(buf, len, num);
315 	if (xcs == NULL) {
316 	    ve_error_set("ERROR: no certificate in file '%s'\n", fname);
317 	}
318 	xfree(buf);
319 	return (xcs);
320 }
321 
322 /* see brssl.h */
323 void
free_certificates(br_x509_certificate * certs,size_t num)324 free_certificates(br_x509_certificate *certs, size_t num)
325 {
326 	size_t u;
327 
328 	for (u = 0; u < num; u ++) {
329 		xfree(certs[u].data);
330 	}
331 	xfree(certs);
332 }
333 
334 
335 static void
dn_append(void * ctx,const void * buf,size_t len)336 dn_append(void *ctx, const void *buf, size_t len)
337 {
338 	VEC_ADDMANY(*(bvector *)ctx, buf, len);
339 }
340 
341 int
certificate_to_trust_anchor_inner(br_x509_trust_anchor * ta,br_x509_certificate * xc)342 certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
343 	br_x509_certificate *xc)
344 {
345 	br_x509_decoder_context dc;
346 	bvector vdn = VEC_INIT;
347 	br_x509_pkey *pk;
348 
349 	br_x509_decoder_init(&dc, dn_append, &vdn);
350 	br_x509_decoder_push(&dc, xc->data, xc->data_len);
351 	pk = br_x509_decoder_get_pkey(&dc);
352 	if (pk == NULL) {
353 	    ve_error_set("ERROR: CA decoding failed with error %d\n",
354 		      br_x509_decoder_last_error(&dc));
355 	    VEC_CLEAR(vdn);
356 	    return (-1);
357 	}
358 	ta->dn.data = VEC_TOARRAY(vdn);
359 	ta->dn.len = VEC_LEN(vdn);
360 	VEC_CLEAR(vdn);
361 	ta->flags = 0;
362 	if (br_x509_decoder_isCA(&dc)) {
363 		ta->flags |= BR_X509_TA_CA;
364 	}
365 	switch (pk->key_type) {
366 	case BR_KEYTYPE_RSA:
367 		ta->pkey.key_type = BR_KEYTYPE_RSA;
368 		ta->pkey.key.rsa.n = xblobdup(pk->key.rsa.n, pk->key.rsa.nlen);
369 		ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;
370 		ta->pkey.key.rsa.e = xblobdup(pk->key.rsa.e, pk->key.rsa.elen);
371 		ta->pkey.key.rsa.elen = pk->key.rsa.elen;
372 		break;
373 	case BR_KEYTYPE_EC:
374 		ta->pkey.key_type = BR_KEYTYPE_EC;
375 		ta->pkey.key.ec.curve = pk->key.ec.curve;
376 		ta->pkey.key.ec.q = xblobdup(pk->key.ec.q, pk->key.ec.qlen);
377 		ta->pkey.key.ec.qlen = pk->key.ec.qlen;
378 		break;
379 	default:
380 	    ve_error_set("ERROR: unsupported public key type in CA\n");
381 		xfree(ta->dn.data);
382 		return (-1);
383 	}
384 	return (0);
385 }
386 
387 /* see brssl.h */
388 void
free_ta_contents(br_x509_trust_anchor * ta)389 free_ta_contents(br_x509_trust_anchor *ta)
390 {
391 	xfree(ta->dn.data);
392 	switch (ta->pkey.key_type) {
393 	case BR_KEYTYPE_RSA:
394 		xfree(ta->pkey.key.rsa.n);
395 		xfree(ta->pkey.key.rsa.e);
396 		break;
397 	case BR_KEYTYPE_EC:
398 		xfree(ta->pkey.key.ec.q);
399 		break;
400 	}
401 }
402