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>
28 #include "libsecureboot-priv.h"
38 if (c <= 32 || c == '-' || c == '_' || c == '.'
39 || c == '/' || c == '+' || c == ':')
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.
53 next_char(const char **ps, const char *limit)
65 if (c >= 'A' && c <= 'Z') {
75 * Partial string equality comparison, with normalisation.
78 eqstr_chunk(const char *s1, size_t s1_len, const char *s2, size_t s2_len)
80 const char *lim1, *lim2;
87 c1 = next_char(&s1, lim1);
88 c2 = next_char(&s2, lim2);
100 eqstr(const char *s1, const char *s2)
102 return (eqstr_chunk(s1, strlen(s1), s2, strlen(s2)));
106 looks_like_DER(const unsigned char *buf, size_t len)
114 if (*buf ++ != 0x30) {
120 return ((size_t)fb == len);
121 } else if (fb == 0x80) {
125 if (len < (size_t)fb + 2) {
131 if (dlen > (len >> 8)) {
134 dlen = (dlen << 8) + (size_t)*buf ++;
136 return (dlen == len);
141 vblob_append(void *cc, const void *data, size_t len)
146 VEC_ADDMANY(*bv, data, len);
150 free_pem_object_contents(pem_object *po)
159 decode_pem(const void *src, size_t len, size_t *num)
161 VECTOR(pem_object) pem_list = VEC_INIT;
162 br_pem_decoder_context pc;
164 const unsigned char *buf;
165 bvector bv = VEC_INIT;
170 br_pem_decoder_init(&pc);
180 tlen = br_pem_decoder_push(&pc, buf, len);
183 switch (br_pem_decoder_event(&pc)) {
185 case BR_PEM_BEGIN_OBJ:
186 po.name = xstrdup(br_pem_decoder_name(&pc));
187 br_pem_decoder_setdest(&pc, vblob_append, &bv);
193 po.data = VEC_TOARRAY(bv);
194 po.data_len = VEC_LEN(bv);
195 VEC_ADD(pem_list, po);
207 ve_error_set("ERROR: invalid PEM encoding");
208 VEC_CLEAREXT(pem_list, &free_pem_object_contents);
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).
219 if (len == 0 && extra_nl) {
221 buf = (const unsigned char *)"\n";
226 ve_error_set("ERROR: unfinished PEM object");
229 VEC_CLEAREXT(pem_list, &free_pem_object_contents);
233 *num = VEC_LEN(pem_list);
234 VEC_ADD(pem_list, po);
235 pos = VEC_TOARRAY(pem_list);
240 br_x509_certificate *
241 parse_certificates(unsigned char *buf, size_t len, size_t *num)
243 VECTOR(br_x509_certificate) cert_list = VEC_INIT;
246 br_x509_certificate *xcs;
247 br_x509_certificate dummy;
252 * Check for a DER-encoded certificate.
254 if (looks_like_DER(buf, len)) {
255 xcs = xmalloc(2 * sizeof *xcs);
257 xcs[0].data_len = len;
264 pos = decode_pem(buf, len, &num_pos);
268 for (u = 0; u < num_pos; u ++) {
269 if (eqstr(pos[u].name, "CERTIFICATE")
270 || eqstr(pos[u].name, "X509 CERTIFICATE"))
272 br_x509_certificate xc;
274 xc.data = pos[u].data;
275 xc.data_len = pos[u].data_len;
277 VEC_ADD(cert_list, xc);
280 for (u = 0; u < num_pos; u ++) {
281 free_pem_object_contents(&pos[u]);
285 if (VEC_LEN(cert_list) == 0) {
288 *num = VEC_LEN(cert_list);
291 VEC_ADD(cert_list, dummy);
292 xcs = VEC_TOARRAY(cert_list);
293 VEC_CLEAR(cert_list);
297 br_x509_certificate *
298 read_certificates(const char *fname, size_t *num)
300 br_x509_certificate *xcs;
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.
310 buf = read_file(fname, &len);
314 xcs = parse_certificates(buf, len, num);
316 ve_error_set("ERROR: no certificate in file '%s'\n", fname);
324 free_certificates(br_x509_certificate *certs, size_t num)
328 for (u = 0; u < num; u ++) {
329 xfree(certs[u].data);
336 dn_append(void *ctx, const void *buf, size_t len)
338 VEC_ADDMANY(*(bvector *)ctx, buf, len);
342 certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
343 br_x509_certificate *xc)
345 br_x509_decoder_context dc;
346 bvector vdn = VEC_INIT;
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);
353 ve_error_set("ERROR: CA decoding failed with error %d\n",
354 br_x509_decoder_last_error(&dc));
358 ta->dn.data = VEC_TOARRAY(vdn);
359 ta->dn.len = VEC_LEN(vdn);
362 if (br_x509_decoder_isCA(&dc)) {
363 ta->flags |= BR_X509_TA_CA;
365 switch (pk->key_type) {
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;
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;
380 ve_error_set("ERROR: unsupported public key type in CA\n");
389 free_ta_contents(br_x509_trust_anchor *ta)
392 switch (ta->pkey.key_type) {
394 xfree(ta->pkey.key.rsa.n);
395 xfree(ta->pkey.key.rsa.e);
398 xfree(ta->pkey.key.ec.q);