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