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 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 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 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 100 eqstr(const char *s1, const char *s2) 101 { 102 return (eqstr_chunk(s1, strlen(s1), s2, strlen(s2))); 103 } 104 105 int 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 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 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 * 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 * 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 * 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 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 336 dn_append(void *ctx, const void *buf, size_t len) 337 { 338 VEC_ADDMANY(*(bvector *)ctx, buf, len); 339 } 340 341 int 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 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