From ba153bd8ee8e25e97360186636b4f6b4fb7d6b8a Mon Sep 17 00:00:00 2001 From: claudio Date: Sat, 2 Apr 2022 12:17:53 +0000 Subject: [PATCH] Split certificate parsing in two steps. cert_parse_pre() which does the parse and some checks and cert_parse() or ta_parse() to do the additional checks for regular certs or TAs. With this adjust the cert parser in -f mode to identify TAs (by checking if it is self signed) and adjust the validation in that case. Now -f should be able to parse and show all object correctly. With and OK tb@ --- usr.sbin/rpki-client/cert.c | 26 +++++-------- usr.sbin/rpki-client/extern.h | 12 ++++-- usr.sbin/rpki-client/main.c | 7 +--- usr.sbin/rpki-client/parser.c | 71 +++++++++++++++++++++++++++++++---- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/usr.sbin/rpki-client/cert.c b/usr.sbin/rpki-client/cert.c index 9ad6b4e2e1e..0b7ad5d40cb 100644 --- a/usr.sbin/rpki-client/cert.c +++ b/usr.sbin/rpki-client/cert.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cert.c,v 1.59 2022/04/01 17:22:07 claudio Exp $ */ +/* $OpenBSD: cert.c,v 1.60 2022/04/02 12:17:53 claudio Exp $ */ /* * Copyright (c) 2021 Job Snijders * Copyright (c) 2019 Kristaps Dzonsons @@ -1054,8 +1054,8 @@ certificate_policies(struct parse *p, X509_EXTENSION *ext) * anchor or a certificate) as defined in RFC 6487. * Returns the parse results or NULL on failure. */ -static struct cert * -cert_parse_inner(const char *fn, const unsigned char *der, size_t len) +struct cert * +cert_parse_pre(const char *fn, const unsigned char *der, size_t len) { int rc = 0, extsz, c; int sia_present = 0; @@ -1193,13 +1193,8 @@ out: } struct cert * -cert_parse(const char *fn, const unsigned char *der, size_t len) +cert_parse(const char *fn, struct cert *p) { - struct cert *p; - - if ((p = cert_parse_inner(fn, der, len)) == NULL) - return NULL; - if (p->aki == NULL) { warnx("%s: RFC 6487 section 8.4.2: " "non-trust anchor missing AKI", fn); @@ -1227,15 +1222,11 @@ badcert: } struct cert * -ta_parse(const char *fn, const unsigned char *der, size_t len, - const unsigned char *pkey, size_t pkeysz) +ta_parse(const char *fn, struct cert *p, const unsigned char *pkey, + size_t pkeysz) { ASN1_TIME *notBefore, *notAfter; - EVP_PKEY *pk = NULL, *opk = NULL; - struct cert *p; - - if ((p = cert_parse_inner(fn, der, len)) == NULL) - return NULL; + EVP_PKEY *pk, *opk; /* first check pubkey against the one from the TAL */ pk = d2i_PUBKEY(NULL, &pkey, pkeysz); @@ -1246,7 +1237,8 @@ ta_parse(const char *fn, const unsigned char *der, size_t len, if ((opk = X509_get0_pubkey(p->x509)) == NULL) { cryptowarnx("%s: RFC 6487 (trust anchor): missing pubkey", fn); goto badcert; - } else if (EVP_PKEY_cmp(pk, opk) != 1) { + } + if (EVP_PKEY_cmp(pk, opk) != 1) { cryptowarnx("%s: RFC 6487 (trust anchor): " "pubkey does not match TAL pubkey", fn); goto badcert; diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index 3e18b455907..4c13758baf9 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.123 2022/04/01 17:22:07 claudio Exp $ */ +/* $OpenBSD: extern.h,v 1.124 2022/04/02 12:17:53 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -422,9 +422,10 @@ struct tal *tal_read(struct ibuf *); void cert_buffer(struct ibuf *, const struct cert *); void cert_free(struct cert *); -struct cert *cert_parse(const char *, const unsigned char *, size_t); -struct cert *ta_parse(const char *, const unsigned char *, size_t, - const unsigned char *, size_t); +struct cert *cert_parse_pre(const char *, const unsigned char *, size_t); +struct cert *cert_parse(const char *, struct cert *); +struct cert *ta_parse(const char *, struct cert *, const unsigned char *, + size_t); struct cert *cert_read(struct ibuf *); void cert_insert_brks(struct brk_tree *, struct cert *); @@ -631,6 +632,9 @@ int mkpath(const char *); #define RPKI_PATH_OUT_DIR "/var/db/rpki-client" #define RPKI_PATH_BASE_DIR "/var/cache/rpki-client" +/* Maximum number of TAL files we'll load. */ +#define TALSZ_MAX 8 + /* Maximum number of IP and AS ranges accepted in any single file */ #define MAX_IP_SIZE 200000 #define MAX_AS_SIZE 200000 diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c index 5e1581da377..03c126cc0f5 100644 --- a/usr.sbin/rpki-client/main.c +++ b/usr.sbin/rpki-client/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.189 2022/02/10 18:58:46 tb Exp $ */ +/* $OpenBSD: main.c,v 1.190 2022/04/02 12:17:53 claudio Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -44,11 +44,6 @@ #include "extern.h" #include "version.h" -/* - * Maximum number of TAL files we'll load. - */ -#define TALSZ_MAX 8 - const char *tals[TALSZ_MAX]; const char *taldescs[TALSZ_MAX]; unsigned int talrepocnt[TALSZ_MAX]; diff --git a/usr.sbin/rpki-client/parser.c b/usr.sbin/rpki-client/parser.c index c57c226e007..34ed08abeab 100644 --- a/usr.sbin/rpki-client/parser.c +++ b/usr.sbin/rpki-client/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.65 2022/04/01 17:22:07 claudio Exp $ */ +/* $OpenBSD: parser.c,v 1.66 2022/04/02 12:17:53 claudio Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -48,6 +48,8 @@ static X509_STORE_CTX *ctx; static struct auth_tree auths = RB_INITIALIZER(&auths); static struct crl_tree crlt = RB_INITIALIZER(&crlt); +struct tal *talobj[TALSZ_MAX]; + extern ASN1_OBJECT *certpol_oid; struct parse_repo { @@ -479,7 +481,10 @@ proc_parser_cert(char *file, const unsigned char *der, size_t len) /* Extract certificate data. */ - cert = cert_parse(file, der, len); + cert = cert_parse_pre(file, der, len); + if (cert == NULL) + return NULL; + cert = cert_parse(file, cert); if (cert == NULL) return NULL; @@ -504,7 +509,10 @@ proc_parser_root_cert(char *file, const unsigned char *der, size_t len, /* Extract certificate data. */ - cert = ta_parse(file, der, len, pkey, pkeysz); + cert = cert_parse_pre(file, der, len); + if (cert == NULL) + return NULL; + cert = ta_parse(file, cert, pkey, pkeysz); if (cert == NULL) return NULL; @@ -896,7 +904,7 @@ parse_load_cert(char *uri) goto done; } - cert = cert_parse(uri, f, flen); + cert = cert_parse_pre(uri, f, flen); free(f); if (cert == NULL) @@ -994,6 +1002,35 @@ parse_load_ta(struct tal *tal) free(f); } +static struct tal * +find_tal(struct cert *cert) +{ + EVP_PKEY *pk, *opk; + struct tal *tal; + int i; + + if ((opk = X509_get0_pubkey(cert->x509)) == NULL) + return NULL; + + for (i = 0; i < TALSZ_MAX; i++) { + const unsigned char *pkey; + + if (talobj[i] == NULL) + break; + tal = talobj[i]; + pkey = tal->pkey; + pk = d2i_PUBKEY(NULL, &pkey, tal->pkeysz); + if (pk == NULL) + continue; + if (EVP_PKEY_cmp(pk, opk) == 1) { + EVP_PKEY_free(pk); + return tal; + } + EVP_PKEY_free(pk); + } + return NULL; +} + /* * Parse file passed with -f option. */ @@ -1008,8 +1045,9 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) struct roa *roa = NULL; struct gbr *gbr = NULL; struct tal *tal = NULL; - enum rtype type; char *aia = NULL, *aki = NULL; + enum rtype type; + int is_ta = 0; if (num++ > 0) printf("--\n"); @@ -1029,7 +1067,12 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) switch (type) { case RTYPE_CER: - cert = cert_parse(file, buf, len); + cert = cert_parse_pre(file, buf, len); + if (cert == NULL) + break; + is_ta = X509_get_extension_flags(cert->x509) & EXFLAG_SS; + if (!is_ta) + cert = cert_parse(file, cert); if (cert == NULL) break; cert_print(cert); @@ -1097,6 +1140,20 @@ proc_parser_file(char *file, unsigned char *buf, size_t len) printf("Validation: OK\n"); else printf("Validation: Failed\n"); + } else if (is_ta) { + if ((tal = find_tal(cert)) != NULL) { + cert = ta_parse(file, cert, tal->pkey, tal->pkeysz); + printf("TAL: %s\n", tal->descr); + tal = NULL; + } else { + cert_free(cert); + cert = NULL; + printf("TAL: not found\n"); + } + if (cert != NULL) + printf("Validation: OK\n"); + else + printf("Validation: Failed\n"); } X509_free(x509); @@ -1131,8 +1188,8 @@ parse_file(struct entityq *q, struct msgbuf *msgq) errx(1, "%s: could not parse tal file", entp->file); tal->id = entp->talid; + talobj[tal->id] = tal; parse_load_ta(tal); - tal_free(tal); break; default: errx(1, "unhandled entity type %d", entp->type); -- 2.20.1