1 /* $OpenBSD: cert.c,v 1.56 2022/02/04 16:50:49 tb Exp $ */
2 /*
3 * Copyright (c) 2021 Job Snijders <job@openbsd.org>
4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/socket.h>
20
21 #include <arpa/inet.h>
22 #include <assert.h>
23 #include <err.h>
24 #include <inttypes.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <openssl/asn1.h>
31 #include <openssl/x509.h>
32 #include <openssl/x509v3.h>
33
34 #include "extern.h"
35
36 /*
37 * Type of ASIdentifier (RFC 3779, 3.2.3).
38 */
39 #define ASID_TYPE_ASNUM 0x00
40 #define ASID_TYPE_RDI 0x01
41 #define ASID_TYPE_MAX ASID_TYPE_RDI
42
43 /*
44 * A parsing sequence of a file (which may just be <stdin>).
45 */
46 struct parse {
47 struct cert *res; /* result */
48 const char *fn; /* currently-parsed file */
49 };
50
51 extern ASN1_OBJECT *certpol_oid; /* id-cp-ipAddr-asNumber cert policy */
52 extern ASN1_OBJECT *carepo_oid; /* 1.3.6.1.5.5.7.48.5 (caRepository) */
53 extern ASN1_OBJECT *manifest_oid; /* 1.3.6.1.5.5.7.48.10 (rpkiManifest) */
54 extern ASN1_OBJECT *notify_oid; /* 1.3.6.1.5.5.7.48.13 (rpkiNotify) */
55
56 /*
57 * Append an IP address structure to our list of results.
58 * This will also constrain us to having at most one inheritance
59 * statement per AFI and also not have overlapping ranges (as prohibited
60 * in section 2.2.3.6).
61 * It does not make sure that ranges can't coalesce, that is, that any
62 * two ranges abut each other.
63 * This is warned against in section 2.2.3.6, but doesn't change the
64 * semantics of the system.
65 * Returns zero on failure (IP overlap) non-zero on success.
66 */
67 static int
append_ip(struct parse * p,const struct cert_ip * ip)68 append_ip(struct parse *p, const struct cert_ip *ip)
69 {
70 struct cert *res = p->res;
71
72 if (!ip_addr_check_overlap(ip, p->fn, p->res->ips, p->res->ipsz))
73 return 0;
74 if (res->ipsz >= MAX_IP_SIZE)
75 return 0;
76 res->ips = reallocarray(res->ips, res->ipsz + 1,
77 sizeof(struct cert_ip));
78 if (res->ips == NULL)
79 err(1, NULL);
80 res->ips[res->ipsz++] = *ip;
81 return 1;
82 }
83
84 /*
85 * Append an AS identifier structure to our list of results.
86 * Makes sure that the identifiers do not overlap or improperly inherit
87 * as defined by RFC 3779 section 3.3.
88 */
89 static int
append_as(struct parse * p,const struct cert_as * as)90 append_as(struct parse *p, const struct cert_as *as)
91 {
92
93 if (!as_check_overlap(as, p->fn, p->res->as, p->res->asz))
94 return 0;
95 if (p->res->asz >= MAX_AS_SIZE)
96 return 0;
97 p->res->as = reallocarray(p->res->as, p->res->asz + 1,
98 sizeof(struct cert_as));
99 if (p->res->as == NULL)
100 err(1, NULL);
101 p->res->as[p->res->asz++] = *as;
102 return 1;
103 }
104
105 /*
106 * Construct a RFC 3779 2.2.3.8 range by its bit string.
107 * Returns zero on failure, non-zero on success.
108 */
109 static int
sbgp_addr(struct parse * p,struct cert_ip * ip,const ASN1_BIT_STRING * bs)110 sbgp_addr(struct parse *p,
111 struct cert_ip *ip, const ASN1_BIT_STRING *bs)
112 {
113
114 if (!ip_addr_parse(bs, ip->afi, p->fn, &ip->ip)) {
115 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
116 "invalid IP address", p->fn);
117 return 0;
118 }
119 if (!ip_cert_compose_ranges(ip)) {
120 warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
121 "IP address range reversed", p->fn);
122 return 0;
123 }
124 return append_ip(p, ip);
125 }
126
127 /*
128 * Parse the SIA notify URL, 4.8.8.1.
129 * Returns zero on failure, non-zero on success.
130 */
131 static int
sbgp_sia_resource_notify(struct parse * p,const char * d,size_t dsz)132 sbgp_sia_resource_notify(struct parse *p, const char *d, size_t dsz)
133 {
134 if (p->res->notify != NULL) {
135 warnx("%s: RFC 6487 section 4.8.8: SIA: "
136 "Notify location already specified", p->fn);
137 return 0;
138 }
139
140 /* Make sure it's a https:// address. */
141 if (!valid_uri(d, dsz, "https://")) {
142 warnx("%s: RFC 8182 section 3.2: bad Notify URI", p->fn);
143 return 0;
144 }
145
146 if ((p->res->notify = strndup(d, dsz)) == NULL)
147 err(1, NULL);
148
149 return 1;
150 }
151
152 /*
153 * Parse the SIA manifest, 4.8.8.1.
154 * Returns zero on failure, non-zero on success.
155 */
156 static int
sbgp_sia_resource_mft(struct parse * p,const char * d,size_t dsz)157 sbgp_sia_resource_mft(struct parse *p, const char *d, size_t dsz)
158 {
159 if (p->res->mft != NULL) {
160 warnx("%s: RFC 6487 section 4.8.8: SIA: "
161 "MFT location already specified", p->fn);
162 return 0;
163 }
164
165 /* Make sure it's an MFT rsync address. */
166 if (!valid_uri(d, dsz, "rsync://")) {
167 warnx("%s: RFC 6487 section 4.8.8: bad MFT location", p->fn);
168 return 0;
169 }
170
171 if (dsz < 4 || strcasecmp(d + dsz - 4, ".mft") != 0) {
172 warnx("%s: RFC 6487 section 4.8.8: SIA: "
173 "not an MFT file", p->fn);
174 return 0;
175 }
176
177 if ((p->res->mft = strndup(d, dsz)) == NULL)
178 err(1, NULL);
179
180 return 1;
181 }
182
183 /*
184 * Parse the SIA manifest, 4.8.8.1.
185 * Returns zero on failure, non-zero on success.
186 */
187 static int
sbgp_sia_resource_carepo(struct parse * p,const char * d,size_t dsz)188 sbgp_sia_resource_carepo(struct parse *p, const char *d, size_t dsz)
189 {
190 if (p->res->repo != NULL) {
191 warnx("%s: RFC 6487 section 4.8.8: SIA: "
192 "CA repository already specified", p->fn);
193 return 0;
194 }
195
196 /* Make sure it's an rsync:// address. */
197 if (!valid_uri(d, dsz, "rsync://")) {
198 warnx("%s: RFC 6487 section 4.8.8: bad CA repository URI",
199 p->fn);
200 return 0;
201 }
202
203 if ((p->res->repo = strndup(d, dsz)) == NULL)
204 err(1, NULL);
205
206 return 1;
207 }
208
209 /*
210 * Parse the SIA entries, 4.8.8.1.
211 * There may be multiple different resources at this location, so throw
212 * out all but the matching resource type. Currently only two entries
213 * are of interest: rpkiManifest and rpkiNotify.
214 * Returns zero on failure, non-zero on success.
215 */
216 static int
sbgp_sia_resource_entry(struct parse * p,const unsigned char * d,size_t dsz)217 sbgp_sia_resource_entry(struct parse *p,
218 const unsigned char *d, size_t dsz)
219 {
220 ASN1_SEQUENCE_ANY *seq;
221 ASN1_OBJECT *oid;
222 const ASN1_TYPE *t;
223 int rc = 0, ptag;
224 long plen;
225
226 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
227 cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
228 "failed ASN.1 sequence parse", p->fn);
229 goto out;
230 }
231 if (sk_ASN1_TYPE_num(seq) != 2) {
232 warnx("%s: RFC 6487 section 4.8.8: SIA: "
233 "want 2 elements, have %d",
234 p->fn, sk_ASN1_TYPE_num(seq));
235 goto out;
236 }
237
238 /* Composed of an OID and its continuation. */
239
240 t = sk_ASN1_TYPE_value(seq, 0);
241 if (t->type != V_ASN1_OBJECT) {
242 warnx("%s: RFC 6487 section 4.8.8: SIA: "
243 "want ASN.1 object, have %s (NID %d)",
244 p->fn, ASN1_tag2str(t->type), t->type);
245 goto out;
246 }
247 oid = t->value.object;
248
249 t = sk_ASN1_TYPE_value(seq, 1);
250 if (t->type != V_ASN1_OTHER) {
251 warnx("%s: RFC 6487 section 4.8.8: SIA: "
252 "want ASN.1 external, have %s (NID %d)",
253 p->fn, ASN1_tag2str(t->type), t->type);
254 goto out;
255 }
256
257 /* FIXME: there must be a way to do this without ASN1_frame. */
258
259 d = t->value.asn1_string->data;
260 dsz = t->value.asn1_string->length;
261 if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag))
262 goto out;
263
264 if (OBJ_cmp(oid, carepo_oid) == 0)
265 rc = sbgp_sia_resource_carepo(p, d, plen);
266 else if (OBJ_cmp(oid, manifest_oid) == 0)
267 rc = sbgp_sia_resource_mft(p, d, plen);
268 else if (OBJ_cmp(oid, notify_oid) == 0)
269 rc = sbgp_sia_resource_notify(p, d, plen);
270 else
271 rc = 1; /* silently ignore */
272 out:
273 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
274 return rc;
275 }
276
277 /*
278 * Multiple locations as defined in RFC 6487, 4.8.8.1.
279 * Returns zero on failure, non-zero on success.
280 */
281 static int
sbgp_sia_resource(struct parse * p,const unsigned char * d,size_t dsz)282 sbgp_sia_resource(struct parse *p, const unsigned char *d, size_t dsz)
283 {
284 ASN1_SEQUENCE_ANY *seq;
285 const ASN1_TYPE *t;
286 int rc = 0, i;
287
288 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
289 cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
290 "failed ASN.1 sequence parse", p->fn);
291 goto out;
292 }
293
294 for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
295 t = sk_ASN1_TYPE_value(seq, i);
296 if (t->type != V_ASN1_SEQUENCE) {
297 warnx("%s: RFC 6487 section 4.8.8: SIA: "
298 "want ASN.1 sequence, have %s (NID %d)",
299 p->fn, ASN1_tag2str(t->type), t->type);
300 goto out;
301 }
302 d = t->value.asn1_string->data;
303 dsz = t->value.asn1_string->length;
304 if (!sbgp_sia_resource_entry(p, d, dsz))
305 goto out;
306 }
307
308 if (strstr(p->res->mft, p->res->repo) != p->res->mft) {
309 warnx("%s: RFC 6487 section 4.8.8: SIA: "
310 "conflicting URIs for caRepository and rpkiManifest",
311 p->fn);
312 goto out;
313 }
314 rc = 1;
315 out:
316 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
317 return rc;
318 }
319
320 /*
321 * Parse "Subject Information Access" extension, RFC 6487 4.8.8.
322 * Returns zero on failure, non-zero on success.
323 */
324 static int
sbgp_sia(struct parse * p,X509_EXTENSION * ext)325 sbgp_sia(struct parse *p, X509_EXTENSION *ext)
326 {
327 unsigned char *sv = NULL;
328 const unsigned char *d;
329 ASN1_SEQUENCE_ANY *seq = NULL;
330 const ASN1_TYPE *t;
331 int dsz, rc = 0;
332
333 if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
334 cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
335 "failed extension parse", p->fn);
336 goto out;
337 }
338 d = sv;
339
340 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
341 cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
342 "failed ASN.1 sequence parse", p->fn);
343 goto out;
344 }
345 if (sk_ASN1_TYPE_num(seq) != 2) {
346 warnx("%s: RFC 6487 section 4.8.8: SIA: "
347 "want 2 elements, have %d", p->fn,
348 sk_ASN1_TYPE_num(seq));
349 goto out;
350 }
351
352 t = sk_ASN1_TYPE_value(seq, 0);
353 if (t->type != V_ASN1_OBJECT) {
354 warnx("%s: RFC 6487 section 4.8.8: SIA: "
355 "want ASN.1 object, have %s (NID %d)",
356 p->fn, ASN1_tag2str(t->type), t->type);
357 goto out;
358 }
359 if (OBJ_obj2nid(t->value.object) != NID_sinfo_access) {
360 warnx("%s: RFC 6487 section 4.8.8: SIA: "
361 "incorrect OID, have %s (NID %d)", p->fn,
362 ASN1_tag2str(OBJ_obj2nid(t->value.object)),
363 OBJ_obj2nid(t->value.object));
364 goto out;
365 }
366
367 t = sk_ASN1_TYPE_value(seq, 1);
368 if (t->type != V_ASN1_OCTET_STRING) {
369 warnx("%s: RFC 6487 section 4.8.8: SIA: "
370 "want ASN.1 octet string, have %s (NID %d)",
371 p->fn, ASN1_tag2str(t->type), t->type);
372 goto out;
373 }
374
375 d = t->value.octet_string->data;
376 dsz = t->value.octet_string->length;
377 if (!sbgp_sia_resource(p, d, dsz))
378 goto out;
379
380 rc = 1;
381 out:
382 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
383 free(sv);
384 return rc;
385 }
386
387 /*
388 * Parse a range of addresses as in 3.2.3.8.
389 * Returns zero on failure, non-zero on success.
390 */
391 static int
sbgp_asrange(struct parse * p,const unsigned char * d,size_t dsz)392 sbgp_asrange(struct parse *p, const unsigned char *d, size_t dsz)
393 {
394 struct cert_as as;
395 ASN1_SEQUENCE_ANY *seq;
396 const ASN1_TYPE *t;
397 int rc = 0;
398
399 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
400 cryptowarnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
401 "failed ASN.1 sequence parse", p->fn);
402 goto out;
403 }
404 if (sk_ASN1_TYPE_num(seq) != 2) {
405 warnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
406 "want 2 elements, have %d", p->fn,
407 sk_ASN1_TYPE_num(seq));
408 goto out;
409 }
410
411 memset(&as, 0, sizeof(struct cert_as));
412 as.type = CERT_AS_RANGE;
413
414 t = sk_ASN1_TYPE_value(seq, 0);
415 if (t->type != V_ASN1_INTEGER) {
416 warnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
417 "want ASN.1 integer, have %s (NID %d)",
418 p->fn, ASN1_tag2str(t->type), t->type);
419 goto out;
420 }
421 if (!as_id_parse(t->value.integer, &as.range.min)) {
422 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
423 "malformed AS identifier", p->fn);
424 return 0;
425 }
426
427 t = sk_ASN1_TYPE_value(seq, 1);
428 if (t->type != V_ASN1_INTEGER) {
429 warnx("%s: RFC 3779 section 3.2.3.8: ASRange: "
430 "want ASN.1 integer, have %s (NID %d)",
431 p->fn, ASN1_tag2str(t->type), t->type);
432 goto out;
433 }
434 if (!as_id_parse(t->value.integer, &as.range.max)) {
435 warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
436 "malformed AS identifier", p->fn);
437 return 0;
438 }
439
440 if (as.range.max == as.range.min) {
441 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
442 "range is singular", p->fn);
443 goto out;
444 } else if (as.range.max < as.range.min) {
445 warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
446 "range is out of order", p->fn);
447 goto out;
448 }
449
450 if (!append_as(p, &as))
451 goto out;
452 rc = 1;
453 out:
454 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
455 return rc;
456 }
457
458 /*
459 * Parse an entire 3.2.3.10 integer type.
460 */
461 static int
sbgp_asid(struct parse * p,const ASN1_INTEGER * i)462 sbgp_asid(struct parse *p, const ASN1_INTEGER *i)
463 {
464 struct cert_as as;
465
466 memset(&as, 0, sizeof(struct cert_as));
467 as.type = CERT_AS_ID;
468
469 if (!as_id_parse(i, &as.id)) {
470 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
471 "malformed AS identifier", p->fn);
472 return 0;
473 }
474 if (as.id == 0) {
475 warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
476 "AS identifier zero is reserved", p->fn);
477 return 0;
478 }
479
480 return append_as(p, &as);
481 }
482
483 /*
484 * Parse one of RFC 3779 3.2.3.2.
485 * Returns zero on failure, non-zero on success.
486 */
487 static int
sbgp_asnum(struct parse * p,const unsigned char * d,size_t dsz)488 sbgp_asnum(struct parse *p, const unsigned char *d, size_t dsz)
489 {
490 struct cert_as as;
491 ASN1_TYPE *t, *tt;
492 ASN1_SEQUENCE_ANY *seq = NULL;
493 int i, rc = 0;
494 const unsigned char *sv = d;
495
496 /* We can either be a null (inherit) or sequence. */
497
498 if ((t = d2i_ASN1_TYPE(NULL, &d, dsz)) == NULL) {
499 cryptowarnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
500 "failed ASN.1 type parse", p->fn);
501 goto out;
502 }
503
504 /*
505 * Section 3779 3.2.3.3 is to inherit with an ASN.1 NULL type,
506 * which is the easy case.
507 */
508
509 switch (t->type) {
510 case V_ASN1_NULL:
511 memset(&as, 0, sizeof(struct cert_as));
512 as.type = CERT_AS_INHERIT;
513 if (!append_as(p, &as))
514 goto out;
515 rc = 1;
516 goto out;
517 case V_ASN1_SEQUENCE:
518 break;
519 default:
520 warnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
521 "want ASN.1 sequence or null, have %s (NID %d)",
522 p->fn, ASN1_tag2str(t->type), t->type);
523 goto out;
524 }
525
526 /* This is RFC 3779 3.2.3.4. */
527
528 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &sv, dsz)) == NULL) {
529 cryptowarnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
530 "failed ASN.1 sequence parse", p->fn);
531 goto out;
532 }
533
534 /* Accepts RFC 3779 3.2.3.6 or 3.2.3.7 (sequence). */
535
536 for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
537 tt = sk_ASN1_TYPE_value(seq, i);
538 switch (tt->type) {
539 case V_ASN1_INTEGER:
540 if (!sbgp_asid(p, tt->value.integer))
541 goto out;
542 break;
543 case V_ASN1_SEQUENCE:
544 d = tt->value.asn1_string->data;
545 dsz = tt->value.asn1_string->length;
546 if (!sbgp_asrange(p, d, dsz))
547 goto out;
548 break;
549 default:
550 warnx("%s: RFC 3779 section 3.2.3.5: ASIdOrRange: "
551 "want ASN.1 sequence or integer, have %s (NID %d)",
552 p->fn, ASN1_tag2str(tt->type), tt->type);
553 goto out;
554 }
555 }
556
557 rc = 1;
558 out:
559 ASN1_TYPE_free(t);
560 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
561 return rc;
562 }
563
564 /*
565 * Parse RFC 6487 4.8.11 X509v3 extension, with syntax documented in RFC
566 * 3779 starting in section 3.2.
567 * Returns zero on failure, non-zero on success.
568 */
569 static int
sbgp_assysnum(struct parse * p,X509_EXTENSION * ext)570 sbgp_assysnum(struct parse *p, X509_EXTENSION *ext)
571 {
572 unsigned char *sv = NULL;
573 const unsigned char *d;
574 ASN1_SEQUENCE_ANY *seq = NULL, *sseq = NULL;
575 const ASN1_TYPE *t;
576 int dsz, rc = 0, i, ptag;
577 long plen;
578
579 if (!X509_EXTENSION_get_critical(ext)) {
580 cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
581 "extension not critical", p->fn);
582 goto out;
583 }
584
585 if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
586 cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
587 "failed extension parse", p->fn);
588 goto out;
589 }
590
591 /* Start with RFC 3779, section 3.2 top-level. */
592
593 d = sv;
594 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
595 cryptowarnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
596 "failed ASN.1 sequence parse", p->fn);
597 goto out;
598 }
599 if (sk_ASN1_TYPE_num(seq) != 3) {
600 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
601 "want 3 elements, have %d", p->fn,
602 sk_ASN1_TYPE_num(seq));
603 goto out;
604 }
605
606 t = sk_ASN1_TYPE_value(seq, 0);
607 if (t->type != V_ASN1_OBJECT) {
608 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
609 "want ASN.1 object, have %s (NID %d)",
610 p->fn, ASN1_tag2str(t->type), t->type);
611 goto out;
612 }
613
614 /* FIXME: verify OID. */
615
616 t = sk_ASN1_TYPE_value(seq, 1);
617 if (t->type != V_ASN1_BOOLEAN) {
618 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
619 "want ASN.1 boolean, have %s (NID %d)",
620 p->fn, ASN1_tag2str(t->type), t->type);
621 goto out;
622 }
623
624 t = sk_ASN1_TYPE_value(seq, 2);
625 if (t->type != V_ASN1_OCTET_STRING) {
626 warnx("%s: RFC 6487 section 4.8.11: autonomousSysNum: "
627 "want ASN.1 octet string, have %s (NID %d)",
628 p->fn, ASN1_tag2str(t->type), t->type);
629 goto out;
630 }
631
632 /* Within RFC 3779 3.2.3, check 3.2.3.1. */
633
634 d = t->value.octet_string->data;
635 dsz = t->value.octet_string->length;
636
637 if ((sseq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
638 cryptowarnx("%s: RFC 3779 section 3.2.3.1: ASIdentifiers: "
639 "failed ASN.1 sequence parse", p->fn);
640 goto out;
641 }
642
643 /* Scan through for private 3.2.3.2 classes. */
644
645 for (i = 0; i < sk_ASN1_TYPE_num(sseq); i++) {
646 t = sk_ASN1_TYPE_value(sseq, i);
647 if (t->type != V_ASN1_OTHER) {
648 warnx("%s: RFC 3779 section 3.2.3.1: ASIdentifiers: "
649 "want ASN.1 explicit, have %s (NID %d)", p->fn,
650 ASN1_tag2str(t->type), t->type);
651 goto out;
652 }
653
654 /* Use the low-level ASN1_frame. */
655
656 d = t->value.asn1_string->data;
657 dsz = t->value.asn1_string->length;
658 if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag))
659 goto out;
660
661 /* Ignore bad AS identifiers and RDI entries. */
662
663 if (ptag > ASID_TYPE_MAX) {
664 warnx("%s: RFC 3779 section 3.2.3.1: ASIdentifiers: "
665 "unknown explicit tag 0x%02x", p->fn, ptag);
666 goto out;
667 } else if (ptag == ASID_TYPE_RDI)
668 continue;
669
670 if (!sbgp_asnum(p, d, plen))
671 goto out;
672 }
673
674 rc = 1;
675 out:
676 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
677 sk_ASN1_TYPE_pop_free(sseq, ASN1_TYPE_free);
678 free(sv);
679 return rc;
680 }
681
682 /*
683 * Parse RFC 3779 2.2.3.9 range of addresses.
684 * Returns zero on failure, non-zero on success.
685 */
686 static int
sbgp_addr_range(struct parse * p,struct cert_ip * ip,const unsigned char * d,size_t dsz)687 sbgp_addr_range(struct parse *p, struct cert_ip *ip,
688 const unsigned char *d, size_t dsz)
689 {
690 ASN1_SEQUENCE_ANY *seq;
691 const ASN1_TYPE *t;
692 int rc = 0;
693
694 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
695 cryptowarnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
696 "failed ASN.1 sequence parse", p->fn);
697 goto out;
698 }
699 if (sk_ASN1_TYPE_num(seq) != 2) {
700 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
701 "want 2 elements, have %d", p->fn, sk_ASN1_TYPE_num(seq));
702 goto out;
703 }
704
705 t = sk_ASN1_TYPE_value(seq, 0);
706 if (t->type != V_ASN1_BIT_STRING) {
707 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
708 "want ASN.1 bit string, have %s (NID %d)",
709 p->fn, ASN1_tag2str(t->type), t->type);
710 goto out;
711 }
712 if (!ip_addr_parse(t->value.bit_string,
713 ip->afi, p->fn, &ip->range.min)) {
714 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
715 "invalid IP address", p->fn);
716 goto out;
717 }
718
719 t = sk_ASN1_TYPE_value(seq, 1);
720 if (t->type != V_ASN1_BIT_STRING) {
721 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
722 "want ASN.1 bit string, have %s (NID %d)",
723 p->fn, ASN1_tag2str(t->type), t->type);
724 goto out;
725 }
726 if (!ip_addr_parse(t->value.bit_string,
727 ip->afi, p->fn, &ip->range.max)) {
728 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
729 "invalid IP address", p->fn);
730 goto out;
731 }
732
733 if (!ip_cert_compose_ranges(ip)) {
734 warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
735 "IP address range reversed", p->fn);
736 return 0;
737 }
738
739 rc = append_ip(p, ip);
740 out:
741 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
742 return rc;
743 }
744
745 /*
746 * Parse an IP address or range, RFC 3779 2.2.3.7.
747 * We don't constrain this parse (as specified in section 2.2.3.6) to
748 * having any kind of order.
749 * Returns zero on failure, non-zero on success.
750 */
751 static int
sbgp_addr_or_range(struct parse * p,struct cert_ip * ip,const unsigned char * d,size_t dsz)752 sbgp_addr_or_range(struct parse *p, struct cert_ip *ip,
753 const unsigned char *d, size_t dsz)
754 {
755 struct cert_ip nip;
756 ASN1_SEQUENCE_ANY *seq;
757 const ASN1_TYPE *t;
758 int i, rc = 0;
759
760 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
761 cryptowarnx("%s: RFC 3779 section 2.2.3.7: IPAddressOrRange: "
762 "failed ASN.1 sequence parse", p->fn);
763 goto out;
764 }
765
766 /* Either RFC 3779 2.2.3.8 or 2.2.3.9. */
767
768 for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
769 nip = *ip;
770 t = sk_ASN1_TYPE_value(seq, i);
771 switch (t->type) {
772 case V_ASN1_BIT_STRING:
773 nip.type = CERT_IP_ADDR;
774 if (!sbgp_addr(p, &nip, t->value.bit_string))
775 goto out;
776 break;
777 case V_ASN1_SEQUENCE:
778 nip.type = CERT_IP_RANGE;
779 d = t->value.asn1_string->data;
780 dsz = t->value.asn1_string->length;
781 if (!sbgp_addr_range(p, &nip, d, dsz))
782 goto out;
783 break;
784 default:
785 warnx("%s: RFC 3779 section 2.2.3.7: IPAddressOrRange: "
786 "want ASN.1 sequence or bit string, have %s (NID %d)",
787 p->fn, ASN1_tag2str(t->type), t->type);
788 goto out;
789 }
790 }
791
792 rc = 1;
793 out:
794 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
795 return rc;
796 }
797
798 /*
799 * Parse a sequence of address families as in RFC 3779 sec. 2.2.3.2.
800 * Ignore several stipulations of the RFC (2.2.3.3).
801 * Namely, we don't require entries to be ordered in any way (type, AFI
802 * or SAFI group, etc.).
803 * This is because it doesn't matter for our purposes: we're going to
804 * validate in the same way regardless.
805 * Returns zero no failure, non-zero on success.
806 */
807 static int
sbgp_ipaddrfam(struct parse * p,const unsigned char * d,size_t dsz)808 sbgp_ipaddrfam(struct parse *p, const unsigned char *d, size_t dsz)
809 {
810 struct cert_ip ip;
811 ASN1_SEQUENCE_ANY *seq;
812 const ASN1_TYPE *t;
813 int rc = 0;
814
815 memset(&ip, 0, sizeof(struct cert_ip));
816
817 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
818 cryptowarnx("%s: RFC 3779 section 2.2.3.2: IPAddressFamily: "
819 "failed ASN.1 sequence parse", p->fn);
820 goto out;
821 }
822 if (sk_ASN1_TYPE_num(seq) != 2) {
823 warnx("%s: RFC 3779 section 2.2.3.2: IPAddressFamily: "
824 "want 2 elements, have %d",
825 p->fn, sk_ASN1_TYPE_num(seq));
826 goto out;
827 }
828
829 /* Get address family, RFC 3779, 2.2.3.3. */
830
831 t = sk_ASN1_TYPE_value(seq, 0);
832 if (t->type != V_ASN1_OCTET_STRING) {
833 warnx("%s: RFC 3779 section 2.2.3.2: addressFamily: "
834 "want ASN.1 octet string, have %s (NID %d)",
835 p->fn, ASN1_tag2str(t->type), t->type);
836 goto out;
837 }
838
839 if (!ip_addr_afi_parse(p->fn, t->value.octet_string, &ip.afi)) {
840 warnx("%s: RFC 3779 section 2.2.3.2: addressFamily: "
841 "invalid AFI", p->fn);
842 goto out;
843 }
844
845 /* Either sequence or null (inherit), RFC 3779 sec. 2.2.3.4. */
846
847 t = sk_ASN1_TYPE_value(seq, 1);
848 switch (t->type) {
849 case V_ASN1_SEQUENCE:
850 d = t->value.asn1_string->data;
851 dsz = t->value.asn1_string->length;
852 if (!sbgp_addr_or_range(p, &ip, d, dsz))
853 goto out;
854 break;
855 case V_ASN1_NULL:
856 ip.type = CERT_IP_INHERIT;
857 if (!append_ip(p, &ip))
858 goto out;
859 break;
860 default:
861 warnx("%s: RFC 3779 section 2.2.3.2: IPAddressChoice: "
862 "want ASN.1 sequence or null, have %s (NID %d)",
863 p->fn, ASN1_tag2str(t->type), t->type);
864 goto out;
865 }
866
867 rc = 1;
868 out:
869 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
870 return rc;
871 }
872
873 /*
874 * Parse an sbgp-ipAddrBlock X509 extension, RFC 6487 4.8.10, with
875 * syntax documented in RFC 3779 starting in section 2.2.
876 * Returns zero on failure, non-zero on success.
877 */
878 static int
sbgp_ipaddrblk(struct parse * p,X509_EXTENSION * ext)879 sbgp_ipaddrblk(struct parse *p, X509_EXTENSION *ext)
880 {
881 int dsz, rc = 0;
882 unsigned char *sv = NULL;
883 const unsigned char *d;
884 ASN1_SEQUENCE_ANY *seq = NULL, *sseq = NULL;
885 const ASN1_TYPE *t = NULL;
886 int i;
887
888 if (!X509_EXTENSION_get_critical(ext)) {
889 cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
890 "extension not critical", p->fn);
891 goto out;
892 }
893
894 if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
895 cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
896 "failed extension parse", p->fn);
897 goto out;
898 }
899 d = sv;
900
901 if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
902 cryptowarnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
903 "failed ASN.1 sequence parse", p->fn);
904 goto out;
905 }
906 if (sk_ASN1_TYPE_num(seq) != 3) {
907 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
908 "want 3 elements, have %d",
909 p->fn, sk_ASN1_TYPE_num(seq));
910 goto out;
911 }
912
913 t = sk_ASN1_TYPE_value(seq, 0);
914 if (t->type != V_ASN1_OBJECT) {
915 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
916 "want ASN.1 object, have %s (NID %d)",
917 p->fn, ASN1_tag2str(t->type), t->type);
918 goto out;
919 }
920
921 /* FIXME: verify OID. */
922
923 t = sk_ASN1_TYPE_value(seq, 1);
924 if (t->type != V_ASN1_BOOLEAN) {
925 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
926 "want ASN.1 boolean, have %s (NID %d)",
927 p->fn, ASN1_tag2str(t->type), t->type);
928 goto out;
929 }
930
931 t = sk_ASN1_TYPE_value(seq, 2);
932 if (t->type != V_ASN1_OCTET_STRING) {
933 warnx("%s: RFC 6487 section 4.8.10: sbgp-ipAddrBlock: "
934 "want ASN.1 octet string, have %s (NID %d)",
935 p->fn, ASN1_tag2str(t->type), t->type);
936 goto out;
937 }
938
939 /* The blocks sequence, RFC 3779 2.2.3.1. */
940
941 d = t->value.octet_string->data;
942 dsz = t->value.octet_string->length;
943
944 if ((sseq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
945 cryptowarnx("%s: RFC 3779 section 2.2.3.1: IPAddrBlocks: "
946 "failed ASN.1 sequence parse", p->fn);
947 goto out;
948 }
949
950 /* Each sequence element contains RFC 3779 sec. 2.2.3.2. */
951
952 for (i = 0; i < sk_ASN1_TYPE_num(sseq); i++) {
953 t = sk_ASN1_TYPE_value(sseq, i);
954 if (t->type != V_ASN1_SEQUENCE) {
955 warnx("%s: RFC 3779 section 2.2.3.2: IPAddressFamily: "
956 "want ASN.1 sequence, have %s (NID %d)",
957 p->fn, ASN1_tag2str(t->type), t->type);
958 goto out;
959 }
960 d = t->value.asn1_string->data;
961 dsz = t->value.asn1_string->length;
962 if (!sbgp_ipaddrfam(p, d, dsz))
963 goto out;
964 }
965
966 rc = 1;
967 out:
968 sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
969 sk_ASN1_TYPE_pop_free(sseq, ASN1_TYPE_free);
970 free(sv);
971 return rc;
972 }
973
974 /*
975 * Parse the certificate policies extension and check that it follows RFC 7318.
976 * Returns zero on failure, non-zero on success.
977 */
978 static int
certificate_policies(struct parse * p,X509_EXTENSION * ext)979 certificate_policies(struct parse *p, X509_EXTENSION *ext)
980 {
981 STACK_OF(POLICYINFO) *policies = NULL;
982 POLICYINFO *policy;
983 STACK_OF(POLICYQUALINFO) *qualifiers;
984 POLICYQUALINFO *qualifier;
985 int nid;
986 int rc = 0;
987
988 if (!X509_EXTENSION_get_critical(ext)) {
989 cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
990 "extension not critical", p->fn);
991 goto out;
992 }
993
994 if ((policies = X509V3_EXT_d2i(ext)) == NULL) {
995 cryptowarnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
996 "failed extension parse", p->fn);
997 goto out;
998 }
999
1000 if (sk_POLICYINFO_num(policies) != 1) {
1001 warnx("%s: RFC 6487 section 4.8.9: certificatePolicies: "
1002 "want 1 policy, got %d", p->fn,
1003 sk_POLICYINFO_num(policies));
1004 goto out;
1005 }
1006
1007 policy = sk_POLICYINFO_value(policies, 0);
1008 assert(policy != NULL && policy->policyid != NULL);
1009
1010 if (OBJ_cmp(policy->policyid, certpol_oid) != 0) {
1011 char pbuf[128], cbuf[128];
1012
1013 OBJ_obj2txt(pbuf, sizeof(pbuf), policy->policyid, 1);
1014 OBJ_obj2txt(cbuf, sizeof(cbuf), certpol_oid, 1);
1015 warnx("%s: RFC 7318 section 2: certificatePolicies: "
1016 "unexpected OID: %s, want %s", p->fn, pbuf, cbuf);
1017 goto out;
1018 }
1019
1020 /* Policy qualifiers are optional. If they're absent, we're done. */
1021 if ((qualifiers = policy->qualifiers) == NULL) {
1022 rc = 1;
1023 goto out;
1024 }
1025
1026 if (sk_POLICYQUALINFO_num(qualifiers) != 1) {
1027 warnx("%s: RFC 7318 section 2: certificatePolicies: "
1028 "want 1 policy qualifier, got %d", p->fn,
1029 sk_POLICYQUALINFO_num(qualifiers));
1030 goto out;
1031 }
1032
1033 qualifier = sk_POLICYQUALINFO_value(qualifiers, 0);
1034 assert(qualifier != NULL && qualifier->pqualid != NULL);
1035
1036 if ((nid = OBJ_obj2nid(qualifier->pqualid)) != NID_id_qt_cps) {
1037 warnx("%s: RFC 7318 section 2: certificatePolicies: "
1038 "want CPS, got %d (%s)", p->fn, nid, OBJ_nid2sn(nid));
1039 goto out;
1040 }
1041
1042 if (verbose > 1)
1043 warnx("%s: CPS %.*s", p->fn, qualifier->d.cpsuri->length,
1044 qualifier->d.cpsuri->data);
1045
1046 rc = 1;
1047 out:
1048 sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
1049 return rc;
1050 }
1051
1052 /*
1053 * Parse and partially validate an RPKI X509 certificate (either a trust
1054 * anchor or a certificate) as defined in RFC 6487.
1055 * If "ta" is set, this is a trust anchor and must be self-signed.
1056 * Returns the parse results or NULL on failure ("xp" will be NULL too).
1057 * On success, free the pointer with cert_free() and make sure that "xp"
1058 * is also dereferenced.
1059 */
1060 static struct cert *
cert_parse_inner(const char * fn,const unsigned char * der,size_t len,int ta)1061 cert_parse_inner(const char *fn, const unsigned char *der, size_t len, int ta)
1062 {
1063 int rc = 0, extsz, c;
1064 int sia_present = 0;
1065 size_t i;
1066 X509 *x = NULL;
1067 X509_EXTENSION *ext = NULL;
1068 ASN1_OBJECT *obj;
1069 struct parse p;
1070
1071 /* just fail for empty buffers, the warning was printed elsewhere */
1072 if (der == NULL)
1073 return NULL;
1074
1075 memset(&p, 0, sizeof(struct parse));
1076 p.fn = fn;
1077 if ((p.res = calloc(1, sizeof(struct cert))) == NULL)
1078 err(1, NULL);
1079
1080 if ((x = d2i_X509(NULL, &der, len)) == NULL) {
1081 cryptowarnx("%s: d2i_X509_bio", p.fn);
1082 goto out;
1083 }
1084
1085 /* Look for X509v3 extensions. */
1086
1087 if ((extsz = X509_get_ext_count(x)) < 0)
1088 cryptoerrx("X509_get_ext_count");
1089
1090 for (i = 0; i < (size_t)extsz; i++) {
1091 ext = X509_get_ext(x, i);
1092 assert(ext != NULL);
1093 obj = X509_EXTENSION_get_object(ext);
1094 assert(obj != NULL);
1095 c = 1;
1096
1097 switch (OBJ_obj2nid(obj)) {
1098 case NID_sbgp_ipAddrBlock:
1099 c = sbgp_ipaddrblk(&p, ext);
1100 break;
1101 case NID_sbgp_autonomousSysNum:
1102 c = sbgp_assysnum(&p, ext);
1103 break;
1104 case NID_sinfo_access:
1105 sia_present = 1;
1106 c = sbgp_sia(&p, ext);
1107 break;
1108 case NID_certificate_policies:
1109 c = certificate_policies(&p, ext);
1110 break;
1111 case NID_crl_distribution_points:
1112 /* ignored here, handled later */
1113 break;
1114 case NID_info_access:
1115 break;
1116 case NID_authority_key_identifier:
1117 break;
1118 case NID_subject_key_identifier:
1119 break;
1120 case NID_ext_key_usage:
1121 break;
1122 default:
1123 /* {
1124 char objn[64];
1125 OBJ_obj2txt(objn, sizeof(objn), obj, 0);
1126 warnx("%s: ignoring %s (NID %d)",
1127 p.fn, objn, OBJ_obj2nid(obj));
1128 } */
1129 break;
1130 }
1131 if (c == 0)
1132 goto out;
1133 }
1134
1135 p.res->aki = x509_get_aki(x, ta, p.fn);
1136 p.res->ski = x509_get_ski(x, p.fn);
1137 if (!ta) {
1138 p.res->aia = x509_get_aia(x, p.fn);
1139 p.res->crl = x509_get_crl(x, p.fn);
1140 }
1141 if (!x509_get_expire(x, p.fn, &p.res->expires))
1142 goto out;
1143 p.res->purpose = x509_get_purpose(x, p.fn);
1144
1145 /* Validation on required fields. */
1146
1147 switch (p.res->purpose) {
1148 case CERT_PURPOSE_CA:
1149 if (p.res->mft == NULL) {
1150 warnx("%s: RFC 6487 section 4.8.8: missing SIA", p.fn);
1151 goto out;
1152 }
1153 if (p.res->asz == 0 && p.res->ipsz == 0) {
1154 warnx("%s: missing IP or AS resources", p.fn);
1155 goto out;
1156 }
1157 break;
1158 case CERT_PURPOSE_BGPSEC_ROUTER:
1159 p.res->pubkey = x509_get_pubkey(x, p.fn);
1160 if (p.res->pubkey == NULL) {
1161 warnx("%s: x509_get_pubkey failed", p.fn);
1162 goto out;
1163 }
1164 if (p.res->ipsz > 0) {
1165 warnx("%s: unexpected IP resources in BGPsec cert",
1166 p.fn);
1167 goto out;
1168 }
1169 if (sia_present) {
1170 warnx("%s: unexpected SIA extension in BGPsec cert",
1171 p.fn);
1172 goto out;
1173 }
1174 if (ta) {
1175 warnx("%s: BGPsec cert can not be a trust anchor",
1176 p.fn);
1177 goto out;
1178 }
1179 break;
1180 default:
1181 warnx("%s: x509_get_purpose failed in %s", p.fn, __func__);
1182 goto out;
1183 }
1184
1185 if (p.res->ski == NULL) {
1186 warnx("%s: RFC 6487 section 8.4.2: missing SKI", p.fn);
1187 goto out;
1188 }
1189
1190 if (ta && p.res->aki != NULL && strcmp(p.res->aki, p.res->ski)) {
1191 warnx("%s: RFC 6487 section 8.4.2: "
1192 "trust anchor AKI, if specified, must match SKI", p.fn);
1193 goto out;
1194 }
1195
1196 if (!ta && p.res->aki == NULL) {
1197 warnx("%s: RFC 6487 section 8.4.2: "
1198 "non-trust anchor missing AKI", p.fn);
1199 goto out;
1200 } else if (!ta && strcmp(p.res->aki, p.res->ski) == 0) {
1201 warnx("%s: RFC 6487 section 8.4.2: "
1202 "non-trust anchor AKI may not match SKI", p.fn);
1203 goto out;
1204 }
1205
1206 if (!ta && p.res->aia == NULL) {
1207 warnx("%s: RFC 6487 section 8.4.7: "
1208 "non-trust anchor missing AIA", p.fn);
1209 goto out;
1210 } else if (ta && p.res->aia != NULL) {
1211 warnx("%s: RFC 6487 section 8.4.7: "
1212 "trust anchor must not have AIA", p.fn);
1213 goto out;
1214 }
1215
1216 if (ta && p.res->crl != NULL) {
1217 warnx("%s: RFC 6487 section 8.4.2: "
1218 "trust anchor may not specify CRL resource", p.fn);
1219 goto out;
1220 }
1221
1222 p.res->x509 = x;
1223
1224 rc = 1;
1225 out:
1226 if (rc == 0) {
1227 cert_free(p.res);
1228 X509_free(x);
1229 }
1230 return (rc == 0) ? NULL : p.res;
1231 }
1232
1233 struct cert *
cert_parse(const char * fn,const unsigned char * der,size_t len)1234 cert_parse(const char *fn, const unsigned char *der, size_t len)
1235 {
1236 return cert_parse_inner(fn, der, len, 0);
1237 }
1238
1239 struct cert *
ta_parse(const char * fn,const unsigned char * der,size_t len,const unsigned char * pkey,size_t pkeysz)1240 ta_parse(const char *fn, const unsigned char *der, size_t len,
1241 const unsigned char *pkey, size_t pkeysz)
1242 {
1243 ASN1_TIME *notBefore, *notAfter;
1244 EVP_PKEY *pk = NULL, *opk = NULL;
1245 struct cert *p;
1246 int rc = 0;
1247
1248 if ((p = cert_parse_inner(fn, der, len, 1)) == NULL)
1249 return NULL;
1250
1251 /* first check pubkey against the one from the TAL */
1252 pk = d2i_PUBKEY(NULL, &pkey, pkeysz);
1253 if (pk == NULL) {
1254 cryptowarnx("%s: RFC 6487 (trust anchor): bad TAL pubkey", fn);
1255 goto badcert;
1256 }
1257 if ((opk = X509_get0_pubkey(p->x509)) == NULL) {
1258 cryptowarnx("%s: RFC 6487 (trust anchor): missing pubkey", fn);
1259 goto badcert;
1260 } else if (EVP_PKEY_cmp(pk, opk) != 1) {
1261 cryptowarnx("%s: RFC 6487 (trust anchor): "
1262 "pubkey does not match TAL pubkey", fn);
1263 goto badcert;
1264 }
1265
1266 if ((notBefore = X509_get_notBefore(p->x509)) == NULL) {
1267 warnx("%s: certificate has invalid notBefore", fn);
1268 goto badcert;
1269 }
1270 if ((notAfter = X509_get_notAfter(p->x509)) == NULL) {
1271 warnx("%s: certificate has invalid notAfter", fn);
1272 goto badcert;
1273 }
1274 if (X509_cmp_current_time(notBefore) != -1) {
1275 warnx("%s: certificate not yet valid", fn);
1276 goto badcert;
1277 }
1278 if (X509_cmp_current_time(notAfter) != 1) {
1279 warnx("%s: certificate has expired", fn);
1280 goto badcert;
1281 }
1282
1283 rc = 1;
1284
1285 badcert:
1286 EVP_PKEY_free(pk);
1287 if (rc == 0) {
1288 cert_free(p);
1289 p = NULL;
1290 }
1291
1292 return p;
1293 }
1294
1295 /*
1296 * Free parsed certificate contents.
1297 * Passing NULL is a noop.
1298 */
1299 void
cert_free(struct cert * p)1300 cert_free(struct cert *p)
1301 {
1302 if (p == NULL)
1303 return;
1304
1305 free(p->crl);
1306 free(p->repo);
1307 free(p->mft);
1308 free(p->notify);
1309 free(p->ips);
1310 free(p->as);
1311 free(p->aia);
1312 free(p->aki);
1313 free(p->ski);
1314 free(p->pubkey);
1315 X509_free(p->x509);
1316 free(p);
1317 }
1318
1319 /*
1320 * Write certificate parsed content into buffer.
1321 * See cert_read() for the other side of the pipe.
1322 */
1323 void
cert_buffer(struct ibuf * b,const struct cert * p)1324 cert_buffer(struct ibuf *b, const struct cert *p)
1325 {
1326 io_simple_buffer(b, &p->expires, sizeof(p->expires));
1327 io_simple_buffer(b, &p->purpose, sizeof(p->purpose));
1328 io_simple_buffer(b, &p->talid, sizeof(p->talid));
1329 io_simple_buffer(b, &p->ipsz, sizeof(p->ipsz));
1330 io_simple_buffer(b, &p->asz, sizeof(p->asz));
1331
1332 io_simple_buffer(b, p->ips, p->ipsz * sizeof(p->ips[0]));
1333 io_simple_buffer(b, p->as, p->asz * sizeof(p->as[0]));
1334
1335 io_str_buffer(b, p->mft);
1336 io_str_buffer(b, p->notify);
1337 io_str_buffer(b, p->repo);
1338 io_str_buffer(b, p->crl);
1339 io_str_buffer(b, p->aia);
1340 io_str_buffer(b, p->aki);
1341 io_str_buffer(b, p->ski);
1342 io_str_buffer(b, p->pubkey);
1343 }
1344
1345 /*
1346 * Allocate and read parsed certificate content from descriptor.
1347 * The pointer must be freed with cert_free().
1348 * Always returns a valid pointer.
1349 */
1350 struct cert *
cert_read(struct ibuf * b)1351 cert_read(struct ibuf *b)
1352 {
1353 struct cert *p;
1354
1355 if ((p = calloc(1, sizeof(struct cert))) == NULL)
1356 err(1, NULL);
1357
1358 io_read_buf(b, &p->expires, sizeof(p->expires));
1359 io_read_buf(b, &p->purpose, sizeof(p->purpose));
1360 io_read_buf(b, &p->talid, sizeof(p->talid));
1361 io_read_buf(b, &p->ipsz, sizeof(p->ipsz));
1362 io_read_buf(b, &p->asz, sizeof(p->asz));
1363
1364 p->ips = calloc(p->ipsz, sizeof(struct cert_ip));
1365 if (p->ips == NULL)
1366 err(1, NULL);
1367 io_read_buf(b, p->ips, p->ipsz * sizeof(p->ips[0]));
1368
1369 p->as = calloc(p->asz, sizeof(struct cert_as));
1370 if (p->as == NULL)
1371 err(1, NULL);
1372 io_read_buf(b, p->as, p->asz * sizeof(p->as[0]));
1373
1374 io_read_str(b, &p->mft);
1375 io_read_str(b, &p->notify);
1376 io_read_str(b, &p->repo);
1377 io_read_str(b, &p->crl);
1378 io_read_str(b, &p->aia);
1379 io_read_str(b, &p->aki);
1380 io_read_str(b, &p->ski);
1381 io_read_str(b, &p->pubkey);
1382
1383 assert(p->mft != NULL || p->purpose == CERT_PURPOSE_BGPSEC_ROUTER);
1384 assert(p->ski);
1385 return p;
1386 }
1387
1388 struct auth *
auth_find(struct auth_tree * auths,const char * aki)1389 auth_find(struct auth_tree *auths, const char *aki)
1390 {
1391 struct auth a;
1392 struct cert c;
1393
1394 /* we look up the cert where the ski == aki */
1395 c.ski = (char *)aki;
1396 a.cert = &c;
1397
1398 return RB_FIND(auth_tree, auths, &a);
1399 }
1400
1401 void
auth_insert(struct auth_tree * auths,struct cert * cert,struct auth * parent)1402 auth_insert(struct auth_tree *auths, struct cert *cert, struct auth *parent)
1403 {
1404 struct auth *na;
1405
1406 na = malloc(sizeof(*na));
1407 if (na == NULL)
1408 err(1, NULL);
1409
1410 na->parent = parent;
1411 na->cert = cert;
1412
1413 if (RB_INSERT(auth_tree, auths, na) != NULL)
1414 err(1, "auth tree corrupted");
1415 }
1416
1417 static inline int
authcmp(struct auth * a,struct auth * b)1418 authcmp(struct auth *a, struct auth *b)
1419 {
1420 return strcmp(a->cert->ski, b->cert->ski);
1421 }
1422
1423 RB_GENERATE(auth_tree, auth, entry, authcmp);
1424
1425 static void
insert_brk(struct brk_tree * tree,struct cert * cert,int asid)1426 insert_brk(struct brk_tree *tree, struct cert *cert, int asid)
1427 {
1428 struct brk *b, *found;
1429
1430 if ((b = calloc(1, sizeof(*b))) == NULL)
1431 err(1, NULL);
1432
1433 b->asid = asid;
1434 b->expires = cert->expires;
1435 b->talid = cert->talid;
1436 if ((b->ski = strdup(cert->ski)) == NULL)
1437 err(1, NULL);
1438 if ((b->pubkey = strdup(cert->pubkey)) == NULL)
1439 err(1, NULL);
1440
1441 /*
1442 * Check if a similar BRK already exists in the tree. If the found BRK
1443 * expires sooner, update it to this BRK's later expiry moment.
1444 */
1445 if ((found = RB_INSERT(brk_tree, tree, b)) != NULL) {
1446 if (found->expires < b->expires) {
1447 found->expires = b->expires;
1448 found->talid = b->talid;
1449 }
1450 free(b->ski);
1451 free(b->pubkey);
1452 free(b);
1453 }
1454 }
1455
1456 /*
1457 * Add each BGPsec Router Key into the BRK tree.
1458 */
1459 void
cert_insert_brks(struct brk_tree * tree,struct cert * cert)1460 cert_insert_brks(struct brk_tree *tree, struct cert *cert)
1461 {
1462 size_t i, asid;
1463
1464 for (i = 0; i < cert->asz; i++) {
1465 switch (cert->as[i].type) {
1466 case CERT_AS_ID:
1467 insert_brk(tree, cert, cert->as[i].id);
1468 break;
1469 case CERT_AS_RANGE:
1470 for (asid = cert->as[i].range.min;
1471 asid <= cert->as[i].range.max; asid++)
1472 insert_brk(tree, cert, asid);
1473 break;
1474 default:
1475 warnx("invalid AS identifier type");
1476 continue;
1477 }
1478 }
1479 }
1480
1481 static inline int
brkcmp(struct brk * a,struct brk * b)1482 brkcmp(struct brk *a, struct brk *b)
1483 {
1484 int rv;
1485
1486 if (a->asid > b->asid)
1487 return 1;
1488 if (a->asid < b->asid)
1489 return -1;
1490
1491 rv = strcmp(a->ski, b->ski);
1492 if (rv > 0)
1493 return 1;
1494 if (rv < 0)
1495 return -1;
1496
1497 return strcmp(a->pubkey, b->pubkey);
1498 }
1499
1500 RB_GENERATE(brk_tree, brk, entry, brkcmp);
1501