Download raw body.
rpki-client: handle SKI and AKI in cert_parse_extensions()
This completes the parsing switch by adding versions of x509_get_ski() and
x509_get_aki(). There's not much to say. I think the new implementations
are slightly less tricky and cert_aki() benefits from removing superfluous
variables. The old versions will be promoted to the attic soon.
With this diff all cert types finally inspect all the extensions relevant
to the RPKI.
Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
diff -u -p -r1.180 cert.c
--- cert.c 2 Jul 2025 11:23:25 -0000 1.180
+++ cert.c 2 Jul 2025 11:25:01 -0000
@@ -501,6 +501,96 @@ sbgp_ipaddrblk(const char *fn, struct ce
return rc;
}
+static int
+cert_ski(const char *fn, struct cert *cert, X509_EXTENSION *ext)
+{
+ ASN1_OCTET_STRING *os = NULL;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ unsigned int md_len = EVP_MAX_MD_SIZE;
+ int rc = 0;
+
+ assert(cert->ski == NULL);
+
+ if (X509_EXTENSION_get_critical(ext)) {
+ warnx("%s: RFC 6487 section 4.8.2: "
+ "SKI: extension not non-critical", fn);
+ goto out;
+ }
+
+ if ((os = X509V3_EXT_d2i(ext)) == NULL) {
+ warnx("%s: RFC 6487 section 4.8.2: error parsing SKI", fn);
+ goto out;
+ }
+
+ if (!X509_pubkey_digest(cert->x509, EVP_sha1(), md, &md_len)) {
+ warnx("%s: X509_pubkey_digest", fn);
+ goto out;
+ }
+
+ if (os->length < 0 || md_len != (unsigned int)os->length) {
+ warnx("%s: RFC 6487 section 4.8.2: SKI: "
+ "want %u bytes SHA1 hash, have %d bytes",
+ fn, md_len, os->length);
+ goto out;
+ }
+
+ if (memcmp(os->data, md, md_len) != 0) {
+ warnx("%s: SKI does not match SHA1 hash of SPK", fn);
+ goto out;
+ }
+
+ cert->ski = hex_encode(md, md_len);
+
+ rc = 1;
+ out:
+ ASN1_OCTET_STRING_free(os);
+ return rc;
+}
+
+static int
+cert_aki(const char *fn, struct cert *cert, X509_EXTENSION *ext)
+{
+ AUTHORITY_KEYID *akid = NULL;
+ int rc = 0;
+
+ assert(cert->aki == NULL);
+
+ if (X509_EXTENSION_get_critical(ext)) {
+ warnx("%s: RFC 6487 section 4.8.3: "
+ "AKI extension not non-critical", fn);
+ goto out;
+ }
+
+ if ((akid = X509V3_EXT_d2i(ext)) == NULL) {
+ warnx("%s: RFC 6487 section 4.8.3: error parsing AKI", fn);
+ goto out;
+ }
+ if (akid->issuer != NULL || akid->serial != NULL) {
+ warnx("%s: RFC 6487 section 4.8.3: AKI: authorityCertIssuer or "
+ "authorityCertSerialNumber present", fn);
+ goto out;
+ }
+
+ if (akid->keyid == NULL || akid->keyid->data == NULL) {
+ warnx("%s: RFC 6487 section 4.8.3: AKI: Key Identifier missing",
+ fn);
+ goto out;
+ }
+ if (akid->keyid->length != SHA_DIGEST_LENGTH) {
+ warnx("%s: RFC 6487 section 4.8.3: AKI: "
+ "want %d bytes SHA1 hash, have %d bytes",
+ fn, SHA_DIGEST_LENGTH, akid->keyid->length);
+ goto out;
+ }
+
+ cert->aki = hex_encode(akid->keyid->data, akid->keyid->length);
+
+ rc = 1;
+ out:
+ AUTHORITY_KEYID_free(akid);
+ return rc;
+}
+
/*
* Parse CRL distribution point per RFC 6487, section 4.8.6.
*/
@@ -1237,10 +1327,14 @@ cert_parse_extensions(const char *fn, st
case NID_subject_key_identifier:
if (ski++ > 0)
goto dup;
+ if (!cert_ski(fn, cert, ext))
+ goto out;
break;
case NID_authority_key_identifier:
if (aki++ > 0)
goto dup;
+ if (!cert_aki(fn, cert, ext))
+ goto out;
break;
case NID_key_usage:
if (ku++ > 0)
@@ -1440,10 +1534,6 @@ cert_parse_pre(const char *fn, const uns
if (!cert_parse_extensions(fn, cert))
goto out;
- if (!x509_get_aki(x, fn, &cert->aki))
- goto out;
- if (!x509_get_ski(x, fn, &cert->ski))
- goto out;
if (!x509_get_notbefore(x, fn, &cert->notbefore))
goto out;
if (!x509_get_notafter(x, fn, &cert->notafter))
rpki-client: handle SKI and AKI in cert_parse_extensions()