]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libsecureboot/brf.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / lib / libsecureboot / brf.c
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
34 static int
35 is_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  */
54 static int
55 next_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  */
79 static int
80 eqstr_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 */
101 int
102 eqstr(const char *s1, const char *s2)
103 {
104         return (eqstr_chunk(s1, strlen(s1), s2, strlen(s2)));
105 }
106
107 int
108 looks_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
142 static void
143 vblob_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
151 void
152 free_pem_object_contents(pem_object *po)
153 {
154         if (po != NULL) {
155                 xfree(po->name);
156                 xfree(po->data);
157         }
158 }
159
160 pem_object *
161 decode_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
242 br_x509_certificate *
243 parse_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
299 br_x509_certificate *
300 read_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 */
325 void
326 free_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
337 static void
338 dn_append(void *ctx, const void *buf, size_t len)
339 {
340         VEC_ADDMANY(*(bvector *)ctx, buf, len);
341 }
342
343 int
344 certificate_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 */
390 void
391 free_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 }