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
32static int
33is_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 */
52static int
53next_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 */
77static int
78eqstr_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 */
99int
100eqstr(const char *s1, const char *s2)
101{
102	return (eqstr_chunk(s1, strlen(s1), s2, strlen(s2)));
103}
104
105int
106looks_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
140static void
141vblob_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
149void
150free_pem_object_contents(pem_object *po)
151{
152	if (po != NULL) {
153		xfree(po->name);
154		xfree(po->data);
155	}
156}
157
158pem_object *
159decode_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
240br_x509_certificate *
241parse_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
297br_x509_certificate *
298read_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 */
323void
324free_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
335static void
336dn_append(void *ctx, const void *buf, size_t len)
337{
338	VEC_ADDMANY(*(bvector *)ctx, buf, len);
339}
340
341int
342certificate_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 */
388void
389free_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