Split certificate parsing in two steps. cert_parse_pre() which does
authorclaudio <claudio@openbsd.org>
Sat, 2 Apr 2022 12:17:53 +0000 (12:17 +0000)
committerclaudio <claudio@openbsd.org>
Sat, 2 Apr 2022 12:17:53 +0000 (12:17 +0000)
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
usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/main.c
usr.sbin/rpki-client/parser.c

index 9ad6b4e..0b7ad5d 100644 (file)
@@ -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 <job@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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;
index 3e18b45..4c13758 100644 (file)
@@ -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 <kristaps@bsd.lv>
  *
@@ -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
index 5e1581d..03c126c 100644 (file)
@@ -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 <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
 #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];
index c57c226..34ed08a 100644 (file)
@@ -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 <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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);