cert_parse_inner() now only uses the ta flag to change behaviour of loading the various x509 extensions (AKI, SKI, AIA und CRL DP).
This diff changes these functions to work always. Make AKI, AIA and CRL DP optional and have the code calling those functions check if they must have the extension. I modelled the functions after x509_get_expire() so they return 0 on failure and 1 on success. Adjust the code to work with these new functions. Most checks for the optional attributes are already present. -- :wq Claudio Index: cert.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v retrieving revision 1.58 diff -u -p -r1.58 cert.c --- cert.c 1 Apr 2022 13:27:38 -0000 1.58 +++ cert.c 1 Apr 2022 14:46:25 -0000 @@ -1058,7 +1058,7 @@ certificate_policies(struct parse *p, X5 * is also dereferenced. */ static struct cert * -cert_parse_inner(const char *fn, const unsigned char *der, size_t len, int ta) +cert_parse_inner(const char *fn, const unsigned char *der, size_t len) { int rc = 0, extsz, c; int sia_present = 0; @@ -1132,12 +1132,14 @@ cert_parse_inner(const char *fn, const u goto out; } - p.res->aki = x509_get_aki(x, ta, p.fn); - p.res->ski = x509_get_ski(x, p.fn); - if (!ta) { - p.res->aia = x509_get_aia(x, p.fn); - p.res->crl = x509_get_crl(x, p.fn); - } + if (!x509_get_aki(x, p.fn, &p.res->aki)) + goto out; + if (!x509_get_ski(x, p.fn, &p.res->ski)) + goto out; + if (!x509_get_aia(x, p.fn, &p.res->aia)) + goto out; + if (!x509_get_crl(x, p.fn, &p.res->crl)) + goto out; if (!x509_get_expire(x, p.fn, &p.res->expires)) goto out; p.res->purpose = x509_get_purpose(x, p.fn); @@ -1198,7 +1200,7 @@ cert_parse(const char *fn, const unsigne { struct cert *p; - if ((p = cert_parse_inner(fn, der, len, 0)) == NULL) + if ((p = cert_parse_inner(fn, der, len)) == NULL) return NULL; if (p->aki == NULL) { @@ -1212,8 +1214,12 @@ cert_parse(const char *fn, const unsigne goto badcert; } if (p->aia == NULL) { - warnx("%s: RFC 6487 section 8.4.7: " - "non-trust anchor missing AIA", fn); + warnx("%s: RFC 6487 section 8.4.7: AIA: extension missing", fn); + goto badcert; + } + if (p->crl == NULL) { + warnx("%s: RFC 6487 section 4.8.6: CRL: " + "no CRL distribution point extension", fn); goto badcert; } return p; @@ -1231,7 +1237,7 @@ ta_parse(const char *fn, const unsigned EVP_PKEY *pk = NULL, *opk = NULL; struct cert *p; - if ((p = cert_parse_inner(fn, der, len, 1)) == NULL) + if ((p = cert_parse_inner(fn, der, len)) == NULL) return NULL; /* first check pubkey against the one from the TAL */ Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.122 diff -u -p -r1.122 extern.h --- extern.h 31 Mar 2022 12:00:00 -0000 1.122 +++ extern.h 1 Apr 2022 13:46:32 -0000 @@ -578,11 +578,11 @@ struct ibuf *io_buf_recvfd(int, struct i /* X509 helpers. */ void x509_init_oid(void); -char *x509_get_aia(X509 *, const char *); -char *x509_get_aki(X509 *, int, const char *); -char *x509_get_ski(X509 *, const char *); +int x509_get_aia(X509 *, const char *, char **); +int x509_get_aki(X509 *, const char *, char **); +int x509_get_ski(X509 *, const char *, char **); int x509_get_expire(X509 *, const char *, time_t *); -char *x509_get_crl(X509 *, const char *); +int x509_get_crl(X509 *, const char *, char **); char *x509_crl_get_aki(X509_CRL *, const char *); char *x509_get_pubkey(X509 *, const char *); enum cert_purpose x509_get_purpose(X509 *, const char *); Index: gbr.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/gbr.c,v retrieving revision 1.14 diff -u -p -r1.14 gbr.c --- gbr.c 18 Jan 2022 16:24:55 -0000 1.14 +++ gbr.c 1 Apr 2022 14:53:47 -0000 @@ -63,19 +63,24 @@ gbr_parse(X509 **x509, const char *fn, c err(1, NULL); free(cms); - p.res->aia = x509_get_aia(*x509, fn); - p.res->aki = x509_get_aki(*x509, 0, fn); - p.res->ski = x509_get_ski(*x509, fn); + if (!x509_get_aia(*x509, fn, &p.res->aia)) + goto out; + if (!x509_get_aki(*x509, fn, &p.res->aki)) + goto out; + if (!x509_get_ski(*x509, fn, &p.res->ski)) + goto out; if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI or SKI X509 extension", fn); - gbr_free(p.res); - X509_free(*x509); - *x509 = NULL; - return NULL; + goto out; } - return p.res; + +out: + gbr_free(p.res); + X509_free(*x509); + *x509 = NULL; + return NULL; } /* Index: mft.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v retrieving revision 1.54 diff -u -p -r1.54 mft.c --- mft.c 31 Mar 2022 12:00:00 -0000 1.54 +++ mft.c 1 Apr 2022 13:52:47 -0000 @@ -444,9 +444,12 @@ mft_parse(X509 **x509, const char *fn, c if ((p.res = calloc(1, sizeof(struct mft))) == NULL) err(1, NULL); - p.res->aia = x509_get_aia(*x509, fn); - p.res->aki = x509_get_aki(*x509, 0, fn); - p.res->ski = x509_get_ski(*x509, fn); + if (!x509_get_aia(*x509, fn, &p.res->aia)) + goto out; + if (!x509_get_aki(*x509, fn, &p.res->aki)) + goto out; + if (!x509_get_ski(*x509, fn, &p.res->ski)) + goto out; if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI or SKI X509 extension", fn); Index: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v retrieving revision 1.64 diff -u -p -r1.64 parser.c --- parser.c 10 Feb 2022 15:33:47 -0000 1.64 +++ parser.c 1 Apr 2022 14:17:05 -0000 @@ -360,7 +360,11 @@ proc_parser_mft_pre(char *file, const un a = valid_ski_aki(file, &auths, mft->ski, mft->aki); /* load CRL by hand, since it is referenced by the MFT itself */ - c = x509_get_crl(x509, file); + if (!x509_get_crl(x509, file, &c) || c == NULL) { + mft_free(mft); + X509_free(x509); + return NULL; + } crlfile = strrchr(c, '/'); if (crlfile != NULL) crlfile++; @@ -1078,7 +1082,7 @@ proc_parser_file(char *file, unsigned ch struct crl *c; char *crl_uri; - crl_uri = x509_get_crl(x509, file); + x509_get_crl(x509, file, &crl_uri); parse_load_crl(crl_uri); free(crl_uri); if (auth_find(&auths, aki) == NULL) Index: roa.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v retrieving revision 1.38 diff -u -p -r1.38 roa.c --- roa.c 10 Feb 2022 15:33:47 -0000 1.38 +++ roa.c 1 Apr 2022 14:00:48 -0000 @@ -351,9 +351,12 @@ roa_parse(X509 **x509, const char *fn, c if ((p.res = calloc(1, sizeof(struct roa))) == NULL) err(1, NULL); - p.res->aia = x509_get_aia(*x509, fn); - p.res->aki = x509_get_aki(*x509, 0, fn); - p.res->ski = x509_get_ski(*x509, fn); + if (!x509_get_aia(*x509, fn, &p.res->aia)) + goto out; + if (!x509_get_aki(*x509, fn, &p.res->aki)) + goto out; + if (!x509_get_ski(*x509, fn, &p.res->ski)) + goto out; if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) { warnx("%s: RFC 6487 section 4.8: " "missing AIA, AKI or SKI X509 extension", fn); Index: x509.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v retrieving revision 1.37 diff -u -p -r1.37 x509.c --- x509.c 25 Mar 2022 08:19:04 -0000 1.37 +++ x509.c 1 Apr 2022 14:06:23 -0000 @@ -83,22 +83,18 @@ x509_init_oid(void) * Returns the AKI or NULL if it could not be parsed. * The AKI is formatted as a hex string. */ -char * -x509_get_aki(X509 *x, int ta, const char *fn) +int +x509_get_aki(X509 *x, const char *fn, char **aki) { const unsigned char *d; AUTHORITY_KEYID *akid; ASN1_OCTET_STRING *os; - int dsz, crit; - char *res = NULL; + int dsz, crit, rc = 0; + *aki = NULL; akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &crit, NULL); - if (akid == NULL) { - if (!ta) - warnx("%s: RFC 6487 section 4.8.3: AKI: " - "extension missing", fn); - return NULL; - } + if (akid == NULL) + return 1; if (crit != 0) { warnx("%s: RFC 6487 section 4.8.3: " "AKI: extension not non-critical", fn); @@ -128,11 +124,11 @@ x509_get_aki(X509 *x, int ta, const char goto out; } - res = hex_encode(d, dsz); - + *aki = hex_encode(d, dsz); + rc = 1; out: AUTHORITY_KEYID_free(akid); - return res; + return rc; } /* @@ -140,18 +136,18 @@ out: * Returns the SKI or NULL if it could not be parsed. * The SKI is formatted as a hex string. */ -char * -x509_get_ski(X509 *x, const char *fn) +int +x509_get_ski(X509 *x, const char *fn, char **ski) { const unsigned char *d; ASN1_OCTET_STRING *os; - int dsz, crit; - char *res = NULL; + int dsz, crit, rc = 0; + *ski = NULL; os = X509_get_ext_d2i(x, NID_subject_key_identifier, &crit, NULL); if (os == NULL) { warnx("%s: RFC 6487 section 4.8.2: SKI: extension missing", fn); - return NULL; + goto out; } if (crit != 0) { warnx("%s: RFC 6487 section 4.8.2: " @@ -169,10 +165,11 @@ x509_get_ski(X509 *x, const char *fn) goto out; } - res = hex_encode(d, dsz); + *ski = hex_encode(d, dsz); + rc = 1; out: ASN1_OCTET_STRING_free(os); - return res; + return rc; } /* @@ -281,19 +278,18 @@ x509_get_pubkey(X509 *x, const char *fn) * Returns NULL on failure, on success returns the AIA URI * (which has to be freed after use). */ -char * -x509_get_aia(X509 *x, const char *fn) +int +x509_get_aia(X509 *x, const char *fn, char **aia) { ACCESS_DESCRIPTION *ad; AUTHORITY_INFO_ACCESS *info; - char *aia = NULL; - int crit; + int crit, rc = 0; + *aia = NULL; info = X509_get_ext_d2i(x, NID_info_access, &crit, NULL); - if (info == NULL) { - warnx("%s: RFC 6487 section 4.8.7: AIA: extension missing", fn); - return NULL; - } + if (info == NULL) + return 1; + if (crit != 0) { warnx("%s: RFC 6487 section 4.8.7: " "AIA: extension not non-critical", fn); @@ -325,15 +321,16 @@ x509_get_aia(X509 *x, const char *fn) goto out; } - aia = strndup( + *aia = strndup( ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier), ASN1_STRING_length(ad->location->d.uniformResourceIdentifier)); - if (aia == NULL) + if (*aia == NULL) err(1, NULL); + rc = 1; out: AUTHORITY_INFO_ACCESS_free(info); - return aia; + return rc; } /* @@ -364,21 +361,19 @@ x509_get_expire(X509 *x, const char *fn, * Returns NULL on failure, the crl URI on success which has to be freed * after use. */ -char * -x509_get_crl(X509 *x, const char *fn) +int +x509_get_crl(X509 *x, const char *fn, char **crl) { CRL_DIST_POINTS *crldp; DIST_POINT *dp; GENERAL_NAME *name; - char *crl = NULL; - int crit; + int crit, rc = 0; + *crl = NULL; crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &crit, NULL); - if (crldp == NULL) { - warnx("%s: RFC 6487 section 4.8.6: CRL: " - "no CRL distribution point extension", fn); - return NULL; - } + if (crldp == NULL) + return 1; + if (crit != 0) { warnx("%s: RFC 6487 section 4.8.6: " "CRL distribution point: extension not non-critical", fn); @@ -425,14 +420,15 @@ x509_get_crl(X509 *x, const char *fn) goto out; } - crl = strndup(ASN1_STRING_get0_data(name->d.uniformResourceIdentifier), + *crl = strndup(ASN1_STRING_get0_data(name->d.uniformResourceIdentifier), ASN1_STRING_length(name->d.uniformResourceIdentifier)); - if (crl == NULL) + if (*crl == NULL) err(1, NULL); + rc = 1; out: CRL_DIST_POINTS_free(crldp); - return crl; + return rc; } /*