1 // The functions here are derrived from BearSSL/tools/*.c
2 // When that is refactored suitably we can use them directly.
4 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
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
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 #include "libsecureboot-priv.h"
40 if (c <= 32 || c == '-' || c == '_' || c == '.'
41 || c == '/' || c == '+' || c == ':')
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.
55 next_char(const char **ps, const char *limit)
67 if (c >= 'A' && c <= 'Z') {
77 * Partial string equality comparison, with normalisation.
80 eqstr_chunk(const char *s1, size_t s1_len, const char *s2, size_t s2_len)
82 const char *lim1, *lim2;
89 c1 = next_char(&s1, lim1);
90 c2 = next_char(&s2, lim2);
102 eqstr(const char *s1, const char *s2)
104 return (eqstr_chunk(s1, strlen(s1), s2, strlen(s2)));
108 looks_like_DER(const unsigned char *buf, size_t len)
116 if (*buf ++ != 0x30) {
122 return ((size_t)fb == len);
123 } else if (fb == 0x80) {
127 if (len < (size_t)fb + 2) {
133 if (dlen > (len >> 8)) {
136 dlen = (dlen << 8) + (size_t)*buf ++;
138 return (dlen == len);
143 vblob_append(void *cc, const void *data, size_t len)
148 VEC_ADDMANY(*bv, data, len);
152 free_pem_object_contents(pem_object *po)
161 decode_pem(const void *src, size_t len, size_t *num)
163 VECTOR(pem_object) pem_list = VEC_INIT;
164 br_pem_decoder_context pc;
166 const unsigned char *buf;
167 bvector bv = VEC_INIT;
172 br_pem_decoder_init(&pc);
182 tlen = br_pem_decoder_push(&pc, buf, len);
185 switch (br_pem_decoder_event(&pc)) {
187 case BR_PEM_BEGIN_OBJ:
188 po.name = xstrdup(br_pem_decoder_name(&pc));
189 br_pem_decoder_setdest(&pc, vblob_append, &bv);
195 po.data = VEC_TOARRAY(bv);
196 po.data_len = VEC_LEN(bv);
197 VEC_ADD(pem_list, po);
209 ve_error_set("ERROR: invalid PEM encoding");
210 VEC_CLEAREXT(pem_list, &free_pem_object_contents);
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).
221 if (len == 0 && extra_nl) {
223 buf = (const unsigned char *)"\n";
228 ve_error_set("ERROR: unfinished PEM object");
231 VEC_CLEAREXT(pem_list, &free_pem_object_contents);
235 *num = VEC_LEN(pem_list);
236 VEC_ADD(pem_list, po);
237 pos = VEC_TOARRAY(pem_list);
242 br_x509_certificate *
243 parse_certificates(unsigned char *buf, size_t len, size_t *num)
245 VECTOR(br_x509_certificate) cert_list = VEC_INIT;
248 br_x509_certificate *xcs;
249 br_x509_certificate dummy;
254 * Check for a DER-encoded certificate.
256 if (looks_like_DER(buf, len)) {
257 xcs = xmalloc(2 * sizeof *xcs);
259 xcs[0].data_len = len;
266 pos = decode_pem(buf, len, &num_pos);
270 for (u = 0; u < num_pos; u ++) {
271 if (eqstr(pos[u].name, "CERTIFICATE")
272 || eqstr(pos[u].name, "X509 CERTIFICATE"))
274 br_x509_certificate xc;
276 xc.data = pos[u].data;
277 xc.data_len = pos[u].data_len;
279 VEC_ADD(cert_list, xc);
282 for (u = 0; u < num_pos; u ++) {
283 free_pem_object_contents(&pos[u]);
287 if (VEC_LEN(cert_list) == 0) {
290 *num = VEC_LEN(cert_list);
293 VEC_ADD(cert_list, dummy);
294 xcs = VEC_TOARRAY(cert_list);
295 VEC_CLEAR(cert_list);
299 br_x509_certificate *
300 read_certificates(const char *fname, size_t *num)
302 br_x509_certificate *xcs;
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.
312 buf = read_file(fname, &len);
316 xcs = parse_certificates(buf, len, num);
318 ve_error_set("ERROR: no certificate in file '%s'\n", fname);
326 free_certificates(br_x509_certificate *certs, size_t num)
330 for (u = 0; u < num; u ++) {
331 xfree(certs[u].data);
338 dn_append(void *ctx, const void *buf, size_t len)
340 VEC_ADDMANY(*(bvector *)ctx, buf, len);
344 certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
345 br_x509_certificate *xc)
347 br_x509_decoder_context dc;
348 bvector vdn = VEC_INIT;
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);
355 ve_error_set("ERROR: CA decoding failed with error %d\n",
356 br_x509_decoder_last_error(&dc));
360 ta->dn.data = VEC_TOARRAY(vdn);
361 ta->dn.len = VEC_LEN(vdn);
364 if (br_x509_decoder_isCA(&dc)) {
365 ta->flags |= BR_X509_TA_CA;
367 switch (pk->key_type) {
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;
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;
382 ve_error_set("ERROR: unsupported public key type in CA\n");
391 free_ta_contents(br_x509_trust_anchor *ta)
394 switch (ta->pkey.key_type) {
396 xfree(ta->pkey.key.rsa.n);
397 xfree(ta->pkey.key.rsa.e);
400 xfree(ta->pkey.key.ec.q);