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