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 } 404