]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Postpone recursive traversal and validate Access Descriptions
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 25 Jan 2019 22:28:16 +0000 (16:28 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 25 Jan 2019 22:35:05 +0000 (16:35 -0600)
1. It was traversing through children before the current
   certificate's validation was done. It's fixed now.
2. Adds validation of CRL Distribution Points, AIA.caIssuers and
   SIA.signedObject.
   Man, those requirements looked deceively small. It was a
   freaking mess.
   I'm not actually sure this is the final version of this code,
   because several argument lists grew too much for my liking.

26 files changed:
src/Makefile.am
src/array_list.h [new file with mode: 0644]
src/asn1/signed_data.c
src/asn1/signed_data.h
src/certificate_refs.c [new file with mode: 0644]
src/certificate_refs.h [new file with mode: 0644]
src/common.c
src/common.h
src/main.c
src/object/certificate.c
src/object/certificate.h
src/object/manifest.c
src/object/manifest.h
src/object/roa.c
src/object/roa.h
src/object/signed_object.c
src/object/signed_object.h
src/object/tal.c
src/resource.c
src/resource.h
src/rpp.c [new file with mode: 0644]
src/rpp.h [new file with mode: 0644]
src/state.c
src/state.h
src/uri.c
src/uri.h

index aa3077e95e1fe1c58fd55583785f336e8916ccd9..1967fb2725371a3151bcbc5fcd5d936ee941d701 100644 (file)
@@ -7,6 +7,8 @@ bin_PROGRAMS = rpki_validator
 rpki_validator_SOURCES  = main.c
 
 rpki_validator_SOURCES += address.h address.c
+rpki_validator_SOURCES += array_list.h
+rpki_validator_SOURCES += certificate_refs.h certificate_refs.c
 rpki_validator_SOURCES += common.h common.c
 rpki_validator_SOURCES += debug.h debug.c
 rpki_validator_SOURCES += file.h file.c
@@ -14,6 +16,7 @@ rpki_validator_SOURCES += line_file.h line_file.c
 rpki_validator_SOURCES += log.h log.c
 rpki_validator_SOURCES += random.h random.c
 rpki_validator_SOURCES += resource.h resource.c
+rpki_validator_SOURCES += rpp.h rpp.c
 rpki_validator_SOURCES += sorted_array.h sorted_array.c
 rpki_validator_SOURCES += state.h state.c
 rpki_validator_SOURCES += thread_var.h thread_var.c
diff --git a/src/array_list.h b/src/array_list.h
new file mode 100644 (file)
index 0000000..e199414
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef SRC_ARRAY_LIST_H_
+#define SRC_ARRAY_LIST_H_
+
+#include <errno.h>
+
+#define ARRAY_LIST(name, elem_type)                                    \
+       struct name {                                                   \
+               /** Unidimensional array. */                            \
+               elem_type *array;                                       \
+               /** Number of elements in @array. */                    \
+               unsigned int len;                                       \
+               /** Actual allocated slots in @array. */                \
+               unsigned int capacity;                                  \
+       };                                                              \
+                                                                       \
+       static int                                                      \
+       name##_init(struct name *list)                                  \
+       {                                                               \
+               list->capacity = 8;                                     \
+               list->len = 0;                                          \
+               list->array = malloc(list->capacity                     \
+                   * sizeof(elem_type));                               \
+               return (list->array != NULL) ? 0 : -ENOMEM;             \
+       }                                                               \
+                                                                       \
+       static void                                                     \
+       name##_cleanup(struct name *list, void (*cb)(elem_type *))      \
+       {                                                               \
+               unsigned int i;                                         \
+               for (i = 0; i < list->len; i++)                         \
+                       cb(&list->array[i]);                            \
+               free(list->array);                                      \
+       }                                                               \
+                                                                       \
+       /* Will store a shallow copy, not @elem */                      \
+       static int                                                      \
+       name##_add(struct name *list, elem_type *elem)                  \
+       {                                                               \
+               elem_type *tmp;                                         \
+                                                                       \
+               list->len++;                                            \
+               while (list->len >= list->capacity) {                   \
+                       list->capacity *= 2;                            \
+                                                                       \
+                       tmp = realloc(list->array, list->capacity       \
+                           * sizeof(elem_type));                       \
+                       if (tmp == NULL)                                \
+                               return pr_enomem();                     \
+                       list->array = tmp;                              \
+               }                                                       \
+                                                                       \
+               list->array[list->len - 1] = *elem;                     \
+               return 0;                                               \
+       }                                                               \
+                                                                       \
+       static int                                                      \
+       name##_foreach(struct name *list,                               \
+           int (*cb)(elem_type const *, void *),                       \
+           void *arg)                                                  \
+       {                                                               \
+               unsigned int i;                                         \
+               int error;                                              \
+                                                                       \
+               for (i = 0; i < list->len; i++) {                       \
+                       error = cb(&list->array[i], arg);               \
+                       if (error)                                      \
+                               return error;                           \
+               }                                                       \
+                                                                       \
+               return 0;                                               \
+       }
+
+#endif /* SRC_ARRAY_LIST_H_ */
index 2081f8bddb4362ddd666a2ecbacb2c15f7044f7a..5004181ac52d760080068752a09fd39164dadd67 100644 (file)
@@ -50,14 +50,14 @@ get_sid(struct SignerInfo *sinfo, OCTET_STRING_t **result)
 }
 
 static int
-handle_sdata_certificate(ANY_t *any, STACK_OF(X509_CRL) *crls,
-    struct resources *res, OCTET_STRING_t *sid)
+handle_sdata_certificate(ANY_t *any, struct signed_object_args *args,
+    OCTET_STRING_t *sid)
 {
        const unsigned char *tmp;
        X509 *cert;
        int error;
 
-       pr_debug_add("(EE?) Certificate (embedded) {");
+       pr_debug_add("EE Certificate (embedded) {");
 
        /*
         * "If the call is successful *in is incremented to the byte following
@@ -74,20 +74,20 @@ handle_sdata_certificate(ANY_t *any, STACK_OF(X509_CRL) *crls,
                goto end1;
        }
 
-       error = certificate_validate_chain(cert, crls);
+       error = certificate_validate_chain(cert, args->crls);
        if (error)
                goto end2;
        error = certificate_validate_rfc6487(cert, false);
        if (error)
                goto end2;
 
-       if (res != NULL) {
-               error = certificate_get_resources(cert, res);
+       if (args->res != NULL) {
+               error = certificate_get_resources(cert, args->res);
                if (error)
                        goto end2;
        }
 
-       error = certificate_traverse_ee(cert, sid);
+       error = certificate_validate_extensions_ee(cert, sid, &args->refs);
 
 end2:
        X509_free(cert);
@@ -239,8 +239,7 @@ illegal_attrType:
 }
 
 static int
-validate(struct SignedData *sdata, STACK_OF(X509_CRL) *crls,
-    struct resources *res)
+validate(struct SignedData *sdata, struct signed_object_args *args)
 {
        struct SignerInfo *sinfo;
        OCTET_STRING_t *sid = NULL;
@@ -319,7 +318,7 @@ validate(struct SignedData *sdata, STACK_OF(X509_CRL) *crls,
        }
 
        error = handle_sdata_certificate(sdata->certificates->list.array[0],
-           crls, res, sid);
+           args, sid);
        if (error)
                return error;
 
@@ -368,8 +367,8 @@ validate(struct SignedData *sdata, STACK_OF(X509_CRL) *crls,
 }
 
 int
-signed_data_decode(ANY_t *coded, struct SignedData **result,
-    STACK_OF(X509_CRL) *crls, struct resources *res)
+signed_data_decode(ANY_t *coded, struct signed_object_args *args,
+    struct SignedData **result)
 {
        struct SignedData *sdata;
        int error;
@@ -379,7 +378,7 @@ signed_data_decode(ANY_t *coded, struct SignedData **result,
        if (error)
                return error;
 
-       error = validate(sdata, crls, res);
+       error = validate(sdata, args);
        if (error) {
                signed_data_free(sdata);
                return error;
index 4d06aa9c89d01f2055909ac57ebd766be15cd254..81643cf957fa3c871addb74cc259680e9837f140 100644 (file)
@@ -6,9 +6,21 @@
 #include <openssl/x509.h>
 #include <libcmscodec/SignedData.h>
 #include "resource.h"
+#include "object/certificate.h"
 
-int signed_data_decode(ANY_t *, struct SignedData **, STACK_OF(X509_CRL) *,
-    struct resources *);
+/*
+ * This only exists to reduce argument lists.
+ * TODO document fields.
+ */
+struct signed_object_args {
+       STACK_OF(X509_CRL) *crls;
+       struct resources *res;
+       struct rpki_uri const *uri;
+       struct certificate_refs refs;
+};
+
+int signed_data_decode(ANY_t *, struct signed_object_args *args,
+    struct SignedData **);
 void signed_data_free(struct SignedData *);
 
 int get_content_type_attr(struct SignedData *, OBJECT_IDENTIFIER_t **);
diff --git a/src/certificate_refs.c b/src/certificate_refs.c
new file mode 100644 (file)
index 0000000..45c91cb
--- /dev/null
@@ -0,0 +1,120 @@
+#include "certificate_refs.h"
+
+#include <errno.h>
+#include "log.h"
+#include "thread_var.h"
+
+void
+refs_init(struct certificate_refs *refs)
+{
+       memset(refs, 0, sizeof(struct certificate_refs));
+}
+
+void
+refs_cleanup(struct certificate_refs *refs)
+{
+       free(refs->crldp);
+       free(refs->caIssuers);
+       free(refs->signedObject);
+}
+
+static int
+validate_cdp(struct certificate_refs *refs, struct rpp const *pp)
+{
+       struct rpki_uri const *pp_crl;
+
+       if (refs->crldp == NULL)
+               return pr_err("Programming error: Certificate's CRL Distribution Point was not recorded.");
+
+       pp_crl = rpp_get_crl(pp);
+       if (pp_crl == NULL)
+               return pr_err("Programming error: Manifest's CRL was not recorded.");
+
+       if (strcmp(refs->crldp, pp_crl->global) != 0) {
+               return pr_err("Certificate's CRL Distribution Point ('%s') does not match manifest's CRL ('%s').",
+                   refs->crldp, pp_crl->global);
+       }
+
+       return 0;
+}
+
+static int
+validate_aia(struct certificate_refs *refs)
+{
+       struct validation *state;
+       struct rpki_uri const *parent;
+
+       if (refs->caIssuers == NULL)
+               return pr_err("Programming error: Certificate's AIA was not recorded.");
+
+       state = state_retrieve();
+       if (state == NULL)
+               return -EINVAL;
+       parent = validation_peek_cert_uri(state);
+       if (parent == NULL)
+               return pr_err("Programming error: CA certificate has no parent.");
+
+       if (strcmp(refs->caIssuers, parent->global) != 0) {
+               return pr_err("Certificate's AIA ('%s') does not match parent's URI ('%s').",
+                   refs->caIssuers, parent->global);
+       }
+
+       return 0;
+}
+
+static int
+validate_signedObject(struct certificate_refs *refs,
+    struct rpki_uri const *signedObject_uri)
+{
+       if (refs->signedObject == NULL)
+               return pr_err("Programming error: Certificate's signedObject was not recorded.");
+
+       if (strcmp(refs->signedObject, signedObject_uri->global) != 0) {
+               return pr_err("Certificate's signedObject ('%s') does not match the URI of its own signed object (%s).",
+                   refs->signedObject, signedObject_uri->global);
+       }
+
+       return 0;
+}
+
+int
+refs_validate_ca(struct certificate_refs *refs, bool is_ta,
+    struct rpp const *pp)
+{
+       int error;
+
+       if (is_ta)
+               return 0;
+
+       error = validate_cdp(refs, pp);
+       if (error)
+               return error;
+
+       error = validate_aia(refs);
+       if (error)
+               return error;
+
+       if (refs->signedObject != NULL) {
+               return pr_err("Programming error: CA summary has a signedObject ('%s').",
+                   refs->signedObject);
+       }
+
+       return 0;
+}
+
+int
+refs_validate_ee(struct certificate_refs *refs, struct rpp const *pp,
+    struct rpki_uri const *uri)
+{
+       int error;
+
+       error = validate_cdp(refs, pp);
+       if (error)
+               return error;
+
+       error = validate_aia(refs);
+       if (error)
+               return error;
+
+       return validate_signedObject(refs, uri);
+}
diff --git a/src/certificate_refs.h b/src/certificate_refs.h
new file mode 100644 (file)
index 0000000..55d55c3
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef SRC_CERTIFICATE_REFS_H_
+#define SRC_CERTIFICATE_REFS_H_
+
+#include <stdbool.h>
+#include "rpp.h"
+
+/**
+ * Some of the URLs defined in Access Descriptions of a certificate's
+ * extensions.
+ *
+ * It's intended to address some awkward RFC requirements:
+ * RFC 6487 defines that these "MUST reference" certain files. I think the best
+ * way to validate this is to check that they equal the respective URLs from the
+ * manifest (because these will at some point be validated as part of the
+ * traversal anyway). Problem is, these URLs are not guaranteed to be parsed by
+ * the time the extension validation kicks in. So we store them in this
+ * structure and handle them later.
+ *
+ * It makes a mess out of the code, and I'm not even sure that validating them
+ * is our responsibility, but there you go.
+ */
+struct certificate_refs {
+       /**
+        * CRL Distribution Points's fullName. Non-TA certificates only.
+        * RFC 6487, section 4.8.6.
+        */
+       char *crldp;
+       /**
+        * AIA's caIssuers. Non-TA certificates only.
+        * RFC 6487, section 4.8.7.
+        */
+       char *caIssuers;
+       /**
+        * SIA's signedObject. EE certificates only.
+        * RFC 6487, section 4.8.8.2.
+        */
+       char *signedObject;
+};
+
+void refs_init(struct certificate_refs *);
+void refs_cleanup(struct certificate_refs *);
+int refs_validate_ca(struct certificate_refs *, bool, struct rpp const *);
+int refs_validate_ee(struct certificate_refs *, struct rpp const *,
+    struct rpki_uri const *);
+
+#endif /* SRC_CERTIFICATE_REFS_H_ */
index 7b51730ac8ea6676295db473fdefa9a7763cb148..ff9f51e52e36125a02a3eee402de0e6227520fcc 100644 (file)
@@ -9,3 +9,27 @@ size_t repository_len;
 int NID_rpkiManifest;
 int NID_signedObject;
 int NID_rpkiNotify;
+
+int
+string_clone(void const *string, size_t size, char **clone)
+{
+       char *result;
+
+       result = malloc(size + 1);
+       if (result == NULL)
+               return pr_enomem();
+
+       memcpy(result, string, size);
+       result[size] = '\0';
+
+       *clone = result;
+       return 0;
+}
+
+int
+ia5s2string(ASN1_IA5STRING *ia5, char **result)
+{
+       return (ia5->flags & ASN1_STRING_FLAG_BITS_LEFT)
+           ? pr_err("CRL URI IA5String has unused bits.")
+           : string_clone(ia5->data, ia5->length, result);
+}
index af282730ac1fd7ff7ec8ae27ab55efd5980fe5c6..e068072285d25fc191dc25ec6e2fb56db7602c82 100644 (file)
@@ -24,4 +24,7 @@ extern int NID_rpkiNotify;
 
 #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
 
+int string_clone(void const *, size_t, char **);
+int ia5s2string(ASN1_IA5STRING *, char **);
+
 #endif /* SRC_RTR_COMMON_H_ */
index d5def1b693a1466d621bebbaa26de75e2f4cb4c0..4951ff9883e4f38efc66ef7d3551b9b202c65bdf 100644 (file)
@@ -5,8 +5,10 @@
 #include "common.h"
 #include "debug.h"
 #include "log.h"
+#include "rpp.h"
 #include "thread_var.h"
 #include "object/certificate.h"
+#include "object/manifest.h"
 #include "object/tal.h"
 #include "rsync/rsync.h"
 
@@ -33,29 +35,6 @@ add_rpki_oids(void)
        printf("rpkiNotify registered. Its nid is %d.\n", NID_rpkiNotify);
 }
 
-static int
-handle_tal_certificate(struct rpki_uri const *uri)
-{
-       X509 *cert;
-       int error;
-
-       fnstack_push(uri->global);
-       error = certificate_load(uri, &cert);
-       if (error)
-               goto end;
-
-       error = certificate_validate_rfc6487(cert, true);
-       if (error)
-               goto revert;
-       error = certificate_traverse_ta(cert, NULL);
-
-revert:
-       X509_free(cert);
-end:
-       fnstack_pop();
-       return error;
-}
-
 /**
  * Performs the whole validation walkthrough on uri @uri, which is assumed to
  * have been extracted from a TAL.
@@ -100,7 +79,7 @@ handle_tal_uri(struct tal *tal, struct rpki_uri const *uri)
                goto end;
        }
 
-       error = handle_tal_certificate(uri);
+       error = certificate_traverse(NULL, uri, NULL, true);
        if (error) {
                switch (validation_pubkey_state(state)) {
                case PKS_INVALID:
index bbf6b0b7ddc950befa94ee2f5496aff8de56acb1..f0bee2eb7a330f48c3e7c95ef4d80edb8e518c58 100644 (file)
@@ -15,6 +15,9 @@
 #include "crypto/hash.h"
 #include "rsync/rsync.h"
 
+/* Just to prevent some line breaking. */
+#define GN_URI uniformResourceIdentifier
+
 /*
  * The X509V3_EXT_METHOD that references NID_sinfo_access uses the AIA item.
  * The SIA's d2i function, therefore, returns AIAs.
@@ -96,11 +99,6 @@ struct ski_arguments {
        OCTET_STRING_t *sid;
 };
 
-struct sia_arguments {
-       X509 *cert;
-       STACK_OF(X509_CRL) *crls;
-};
-
 static int
 validate_serial_number(X509 *cert)
 {
@@ -593,19 +591,9 @@ is_rsync(ASN1_IA5STRING *uri)
 }
 
 static int
-handle_rpkiManifest(ACCESS_DESCRIPTION *ad, STACK_OF(X509_CRL) *crls)
+handle_rpkiManifest(ACCESS_DESCRIPTION *ad, struct rpki_uri *mft)
 {
-       struct rpki_uri uri;
-       int error;
-
-       error = uri_init_ad(&uri, ad);
-       if (error)
-               return error;
-
-       error = handle_manifest(&uri, crls);
-
-       uri_cleanup(&uri);
-       return error;
+       return uri_init_ad(mft, ad);
 }
 
 static int
@@ -626,17 +614,21 @@ handle_caRepository(ACCESS_DESCRIPTION *ad)
 }
 
 static int
-handle_signedObject(ACCESS_DESCRIPTION *ad)
+handle_signedObject(ACCESS_DESCRIPTION *ad, struct certificate_refs *refs)
 {
        struct rpki_uri uri;
        int error;
 
+       /* TODO all three of them probably need this treatment. */
        error = uri_init_ad(&uri, ad);
        if (error)
                return error;
 
        pr_debug("signedObject: %s", uri.global);
 
+       refs->signedObject = uri.global;
+       uri.global = NULL;
+
        uri_cleanup(&uri);
        return error;
 }
@@ -929,7 +921,8 @@ handle_ku_ee(X509_EXTENSION *ext, void *arg)
 static int
 handle_cdp(X509_EXTENSION *ext, void *arg)
 {
-       STACK_OF(DIST_POINT) *crldp = X509V3_EXT_d2i(ext);
+       struct certificate_refs *refs = arg;
+       STACK_OF(DIST_POINT) *crldp;
        DIST_POINT *dp;
        GENERAL_NAMES *names;
        GENERAL_NAME *name;
@@ -978,12 +971,23 @@ handle_cdp(X509_EXTENSION *ext, void *arg)
        names = dp->distpoint->name.fullname;
        for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
                name = sk_GENERAL_NAME_value(names, i);
-               if (name->type == GEN_URI && is_rsync(name->d.uniformResourceIdentifier)) {
+               if (name->type == GEN_URI && is_rsync(name->d.GN_URI)) {
                        /*
-                        * TODO (certext) check the URI matches what we rsync'd.
-                        * Also indent properly.
+                        * Since we're parsing and validating the manifest's CRL
+                        * at some point, I think that all we need to do now is
+                        * compare this CRL URI to that one's.
+                        *
+                        * But there is a problem:
+                        * The manifest's CRL might not have been parsed at this
+                        * point. In fact, it's guaranteed to not have been
+                        * parsed if the certificate we're validating is the EE
+                        * certificate of the manifest itself.
+                        *
+                        * So we will store the URI in @refs, and validate it
+                        * later.
                         */
-                       error = 0;
+                       error = ia5s2string(name->d.GN_URI, &refs->crldp);
+                       pr_debug("Certificate CRL: %s", refs->crldp);
                        goto end;
                }
        }
@@ -1002,6 +1006,7 @@ end:
 static int
 handle_aia(X509_EXTENSION *ext, void *arg)
 {
+       struct certificate_refs *refs = arg;
        AUTHORITY_INFO_ACCESS *aia;
        ACCESS_DESCRIPTION *ad;
        int i;
@@ -1013,9 +1018,19 @@ handle_aia(X509_EXTENSION *ext, void *arg)
        for (i = 0; i < sk_ACCESS_DESCRIPTION_num(aia); i++) {
                ad = sk_ACCESS_DESCRIPTION_value(aia, i);
                if (OBJ_obj2nid(ad->method) == NID_ad_ca_issuers) {
+                       if (ad->location->type != GEN_URI) {
+                               return pr_err("The AIA caIssuers is not an URI. (type: %d)",
+                                   ad->location->type);
+                       }
+
                        /*
-                        * TODO (certext) check the URI matches what we rsync'd.
+                        * Bringing the parent certificate's URI all the way
+                        * over here is too much trouble, so do the handle_cdp()
+                        * hack.
                         */
+
+                       return ia5s2string(ad->location->d.GN_URI,
+                           &refs->caIssuers);
                }
        }
 
@@ -1026,8 +1041,6 @@ handle_aia(X509_EXTENSION *ext, void *arg)
 static int
 handle_sia_ca(X509_EXTENSION *ext, void *arg)
 {
-       struct sia_arguments *args = arg;
-       struct validation *state;
        SIGNATURE_INFO_ACCESS *sia;
        ACCESS_DESCRIPTION *ad;
        bool rsync_found = false;
@@ -1039,15 +1052,6 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
        if (sia == NULL)
                return cannot_decode(&SIA);
 
-       state = state_retrieve();
-       if (state == NULL) {
-               error = -EINVAL;
-               goto end2;
-       }
-       error = validation_push_cert(state, args->cert, false);
-       if (error)
-               goto end2;
-
        /* rsync */
        for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
                ad = sk_ACCESS_DESCRIPTION_value(sia, i);
@@ -1056,7 +1060,7 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
                        if (error == ENOTRSYNC)
                                continue;
                        if (error)
-                               goto end1;
+                               goto end;
                        rsync_found = true;
                        break;
                }
@@ -1065,10 +1069,14 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
        if (!rsync_found) {
                pr_err("SIA extension lacks a caRepository RSYNC URI.");
                error = -ESRCH;
-               goto end1;
+               goto end;
        }
 
-       /* validate */
+       /*
+        * Store the manifest URI in @mft.
+        * (We won't actually touch the manifest until we know the certificate
+        * is fully valid.)
+        */
        for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
                ad = sk_ACCESS_DESCRIPTION_value(sia, i);
                if (OBJ_obj2nid(ad->method) == NID_rpkiManifest) {
@@ -1082,12 +1090,12 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
                         */
                        if (manifest_found) {
                                error = pr_err("SIA defines more than one manifest.");
-                               goto end1;
+                               goto end;
                        }
 
-                       error = handle_rpkiManifest(ad, args->crls);
+                       error = handle_rpkiManifest(ad, arg);
                        if (error)
-                               goto end1;
+                               goto end;
                        manifest_found = true;
                }
        }
@@ -1098,9 +1106,7 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
                error = -ESRCH;
        }
 
-end1:
-       validation_pop_cert(state); /* Error code is useless. */
-end2:
+end:
        AUTHORITY_INFO_ACCESS_free(sia);
        return error;
 }
@@ -1126,7 +1132,7 @@ handle_sia_ee(X509_EXTENSION *ext, void *arg)
                nid = OBJ_obj2nid(ad->method);
 
                if (nid == NID_signedObject) {
-                       error = handle_signedObject(ad);
+                       error = handle_signedObject(ad, arg);
                        /* TODO Unknown signedObjects are allowed. */
                        if (error)
                                goto end;
@@ -1240,55 +1246,49 @@ handle_cert_extensions(struct extension_handler *handlers, X509 *cert)
 }
 
 int
-certificate_traverse_ta(X509 *cert, STACK_OF(X509_CRL) *crls)
+certificate_validate_extensions_ta(X509 *cert, struct rpki_uri *mft)
 {
-       struct sia_arguments sia_args;
        struct extension_handler handlers[] = {
           /* ext   reqd   handler        arg       */
            { &BC,  true,  handle_bc,               },
            { &SKI, true,  handle_ski_ca, cert      },
            { &AKI, false, handle_aki_ta, cert      },
            { &KU,  true,  handle_ku_ca,            },
-           { &SIA, true,  handle_sia_ca, &sia_args },
+           { &SIA, true,  handle_sia_ca, mft       },
            { &CP,  true,  handle_cp,               },
            { &IR,  false, handle_ir,               },
            { &AR,  false, handle_ar,               },
            { NULL },
        };
 
-       sia_args.cert = cert;
-       sia_args.crls = crls;
-
        return handle_cert_extensions(handlers, cert);
 }
 
 int
-certificate_traverse_ca(X509 *cert, STACK_OF(X509_CRL) *crls)
+certificate_validate_extensions_ca(X509 *cert, struct rpki_uri *mft,
+    struct certificate_refs *refs)
 {
-       struct sia_arguments sia_args;
        struct extension_handler handlers[] = {
           /* ext   reqd   handler        arg       */
            { &BC,  true,  handle_bc,               },
            { &SKI, true,  handle_ski_ca, cert      },
            { &AKI, true,  handle_aki,              },
            { &KU,  true,  handle_ku_ca,            },
-           { &CDP, true,  handle_cdp,              },
-           { &AIA, true,  handle_aia,              },
-           { &SIA, true,  handle_sia_ca, &sia_args },
+           { &CDP, true,  handle_cdp,    refs      },
+           { &AIA, true,  handle_aia,    refs      },
+           { &SIA, true,  handle_sia_ca, mft       },
            { &CP,  true,  handle_cp,               },
            { &IR,  false, handle_ir,               },
            { &AR,  false, handle_ar,               },
            { NULL },
        };
 
-       sia_args.cert = cert;
-       sia_args.crls = crls;
-
        return handle_cert_extensions(handlers, cert);
 }
 
 int
-certificate_traverse_ee(X509 *cert, OCTET_STRING_t *sid)
+certificate_validate_extensions_ee(X509 *cert, OCTET_STRING_t *sid,
+    struct certificate_refs *refs)
 {
        struct ski_arguments ski_args;
        struct extension_handler handlers[] = {
@@ -1296,9 +1296,9 @@ certificate_traverse_ee(X509 *cert, OCTET_STRING_t *sid)
            { &SKI, true,  handle_ski_ee, &ski_args },
            { &AKI, true,  handle_aki,              },
            { &KU,  true,  handle_ku_ee,            },
-           { &CDP, true,  handle_cdp,              },
-           { &AIA, true,  handle_aia,              },
-           { &SIA, true,  handle_sia_ee,           },
+           { &CDP, true,  handle_cdp,    refs      },
+           { &AIA, true,  handle_aia,    refs      },
+           { &SIA, true,  handle_sia_ee, refs      },
            { &CP,  true,  handle_cp,               },
            { &IR,  false, handle_ir,               },
            { &AR,  false, handle_ar,               },
@@ -1310,3 +1310,73 @@ certificate_traverse_ee(X509 *cert, OCTET_STRING_t *sid)
 
        return handle_cert_extensions(handlers, cert);
 }
+
+/* Boilerplate code for CA certificate validation and recursive traversal. */
+int
+certificate_traverse(struct rpp *rpp_parent, struct rpki_uri const *cert_uri,
+    STACK_OF(X509_CRL) *crls, bool is_ta)
+{
+       struct validation *state;
+       X509 *cert;
+       struct rpki_uri mft;
+       struct certificate_refs refs;
+       struct rpp *pp;
+       int error;
+
+       pr_debug_add("%s Certificate %s {", is_ta ? "TA" : "CA",
+           cert_uri->global);
+       fnstack_push(cert_uri->global);
+       memset(&refs, 0, sizeof(refs));
+
+       /* -- Validate the certificate (@cert) -- */
+       error = certificate_load(cert_uri, &cert);
+       if (error)
+               goto end1;
+       if (!is_ta) {
+               error = certificate_validate_chain(cert, crls);
+               if (error)
+                       goto end2;
+       }
+       error = certificate_validate_rfc6487(cert, is_ta);
+       if (error)
+               goto end2;
+       error = is_ta
+           ? certificate_validate_extensions_ta(cert, &mft)
+           : certificate_validate_extensions_ca(cert, &mft, &refs);
+       if (error)
+               goto end2;
+
+       error = refs_validate_ca(&refs, is_ta, rpp_parent);
+       if (error)
+               goto end3;
+
+       /* -- Validate the manifest (@mft) pointed by the certificate -- */
+       state = state_retrieve();
+       if (state == NULL) {
+               error = -EINVAL;
+               goto end3;
+       }
+       error = validation_push_cert(state, cert_uri, cert, is_ta);
+       if (error)
+               goto end3;
+
+       error = handle_manifest(&mft, crls, &pp);
+       if (error)
+               goto end4;
+
+       /* -- Validate & traverse the RPP (@pp) described by the manifest -- */
+       error = rpp_traverse(pp);
+
+       rpp_destroy(pp);
+end4:
+       validation_pop_cert(state); /* Error code is useless. */
+end3:
+       uri_cleanup(&mft);
+       refs_cleanup(&refs);
+end2:
+       X509_free(cert);
+end1:
+       fnstack_pop();
+       pr_debug_rm("}");
+       return error;
+}
index 90c9050969a18cc60f638f6bf4d86a5b6bf1eeb5..57456834c62c417a42499d472a6e0293626ab9a6 100644 (file)
@@ -3,42 +3,59 @@
 
 #include <stdbool.h>
 #include <openssl/x509.h>
+#include "certificate_refs.h"
 #include "resource.h"
+#include "rpp.h"
 #include "uri.h"
 
 int certificate_load(struct rpki_uri const *, X509 **);
 
 /**
  * Performs the basic (RFC 5280, presumably) chain validation.
- * (Ignores the IP, AS and SIA extensions.)
+ * (Ignores the IP and AS extensions.)
  */
 int certificate_validate_chain(X509 *, STACK_OF(X509_CRL) *);
 /**
  * Validates RFC 6487 compliance.
- * (Except IP, AS and SIA extensions.)
+ * (Except extensions.)
  */
 int certificate_validate_rfc6487(X509 *, bool);
 
 /**
  * Returns the IP and AS resources declared in the respective extensions.
+ *
+ * TODO why is this not part of the certificate_validate*s, again?
  */
 int certificate_get_resources(X509 *, struct resources *);
 
 /**
- * Handles the SIA extension, Trust Anchor style.
- * (ie. Recursively walks through the certificate's children.)
+ * Validates the certificate extensions, Trust Anchor style.
+ *
+ * Also initializes the second argument as the URI of the rpkiManifest Access
+ * Description from the SIA extension.
  */
-int certificate_traverse_ta(X509 *, STACK_OF(X509_CRL) *);
+int certificate_validate_extensions_ta(X509 *, struct rpki_uri *);
 /**
- * Handles the SIA extension, (intermediate) CA style.
- * (ie. Recursively walks through the certificate's children.)
+ * Validates the certificate extensions, (intermediate) Certificate Authority
+ * style.
+ *
+ * Also initializes the second argument as the URI of the rpkiManifest Access
+ * Description from the SIA extension.
+ * Also initializes the third argument with the references found in the
+ * extensions.
  */
-int certificate_traverse_ca(X509 *, STACK_OF(X509_CRL) *);
+int certificate_validate_extensions_ca(X509 *, struct rpki_uri *,
+    struct certificate_refs *);
 /**
- * Handles the SIA extension, EE style.
- * (Doesn't actually "traverse" anything. The name is just for the sake of
- * mirroring.)
+ * Validates the certificate extensions, End-Entity style.
+ *
+ * Also initializes the second argument with the references found in the
+ * extensions.
  */
-int certificate_traverse_ee(X509 *, OCTET_STRING_t *);
+int certificate_validate_extensions_ee(X509 *, OCTET_STRING_t *,
+    struct certificate_refs *);
+
+int certificate_traverse(struct rpp *, struct rpki_uri const *,
+    STACK_OF(X509_CRL) *, bool);
 
 #endif /* SRC_OBJECT_CERTIFICATE_H_ */
index f73f8d9666d6099489f0b3fac668db6dcfdd0ae3..5cdf34fe53a670f7d18de0cae20e87d583af4c70 100644 (file)
@@ -102,27 +102,24 @@ validate_manifest(struct Manifest *manifest)
        return 0;
 }
 
-typedef int (*foreach_cb)(struct rpki_uri const *, void *);
-
 static int
-foreach_file(struct manifest *mft, char *extension, foreach_cb cb, void *arg)
+__handle_manifest(struct manifest *mft, struct rpp **pp)
 {
+       int i;
        struct FileAndHash *fah;
        struct rpki_uri uri;
-       int i;
        int error;
 
+       *pp = rpp_create();
+       if (*pp == NULL)
+               return pr_enomem();
+
        for (i = 0; i < mft->obj->fileList.list.count; i++) {
                fah = mft->obj->fileList.list.array[i];
 
-               error = uri_init_ia5(&uri, mft->file_path, &fah->file);
+               error = uri_init_mft(&uri, mft->file_path, &fah->file);
                if (error)
-                       return error;
-
-               if (!uri_has_extension(&uri, extension)) {
-                       uri_cleanup(&uri);
-                       continue;
-               }
+                       goto fail;
 
                error = hash_validate_file("sha256", &uri, &fah->hash);
                if (error) {
@@ -130,148 +127,71 @@ foreach_file(struct manifest *mft, char *extension, foreach_cb cb, void *arg)
                        continue;
                }
 
-               error = cb(&uri, arg);
-               uri_cleanup(&uri);
-               if (error)
-                       return error;
-       }
-
-       return 0;
-}
-
-static int
-pile_crls(struct rpki_uri const *uri, void *crls)
-{
-       X509_CRL *crl;
-       int error;
-       int idx;
-
-       /* rfc6481#section-2.2 */
-       if (sk_X509_CRL_num(crls) != 0)
-               return pr_err("The Manifest defines more than one CRL.");
-
-       fnstack_push(uri->global);
-
-       error = crl_load(uri, &crl);
-       if (error)
-               goto end;
+               if (uri_has_extension(&uri, ".cer"))
+                       error = rpp_add_cert(*pp, &uri);
+               else if (uri_has_extension(&uri, ".roa"))
+                       error = rpp_add_roa(*pp, &uri);
+               else if (uri_has_extension(&uri, ".crl"))
+                       error = rpp_add_crl(*pp, &uri);
+               else
+                       uri_cleanup(&uri); /* ignore it. */
 
-       idx = sk_X509_CRL_push(crls, crl);
-       if (idx <= 0) {
-               error = crypto_err("Could not add CRL to a CRL stack");
-               X509_CRL_free(crl);
-               goto end;
+               if (error) {
+                       uri_cleanup(&uri);
+                       goto fail;
+               } /* Otherwise ownership was transferred to @pp. */
        }
 
-end:
-       fnstack_pop();
-       return error;
-}
-
-/*
- * Speaking of CA certs: I still don't get the CA/EE cert duality at the
- * implementation level.
- *
- * Right now, I'm assuming that file certs are CA certs, and CMS-embedded certs
- * are EE certs. None of the RFCs seem to mandate this, but I can't think of any
- * other way to interpret it.
- *
- * It's really weird because the RFCs actually define requirements like "other
- * AccessMethods MUST NOT be used for an EE certificates's SIA," (RFC6481) which
- * seems to imply that there's some contextual way to already know whether a
- * certificate is CA or EE. But it just doesn't exist.
- */
-static int
-traverse_ca_certs(struct rpki_uri const *uri, void *crls)
-{
-       X509 *cert;
-
-       pr_debug_add("(CA?) Certificate {");
-       fnstack_push(uri->global);
-
-       /*
-        * Errors on at least some of these functions should not interrupt the
-        * traversal of sibling nodes, so ignore them.
-        * (Error messages should have been printed in stderr.)
-        */
-
-       if (certificate_load(uri, &cert))
-               goto revert1; /* Fine */
-
-       if (certificate_validate_chain(cert, crls))
-               goto revert2; /* Fine */
-       if (certificate_validate_rfc6487(cert, false))
-               goto revert2; /* Fine */
-       certificate_traverse_ca(cert, crls); /* Error code is useless. */
-
-revert2:
-       X509_free(cert);
-revert1:
-       pr_debug_rm("}");
-       fnstack_pop();
-       return 0;
-}
-
-static int
-print_roa(struct rpki_uri const *uri, void *arg)
-{
-       handle_roa(uri, arg);
        return 0;
-}
 
-static int
-__handle_manifest(struct manifest *mft)
-{
-       STACK_OF(X509_CRL) *crls;
-       int error;
-
-       /* Init */
-       crls = sk_X509_CRL_new_null();
-       if (crls == NULL)
-               return pr_enomem();
-
-       /* Get the one CRL as a stack. */
-       error = foreach_file(mft, ".crl", pile_crls, crls);
-       if (error)
-               goto end;
-
-       /* Use CRL stack to validate certificates, and also traverse them. */
-       error = foreach_file(mft, ".cer", traverse_ca_certs, crls);
-       if (error)
-               goto end;
-
-       /* Use valid address ranges to print ROAs that match them. */
-       error = foreach_file(mft, ".roa", print_roa, crls);
-
-end:
-       sk_X509_CRL_pop_free(crls, X509_CRL_free);
+fail:
+       rpp_destroy(*pp);
        return error;
 }
 
+/**
+ * Validates the manifest pointed by @uri, returns the RPP described by it in
+ * @pp.
+ */
 int
-handle_manifest(struct rpki_uri const *uri, STACK_OF(X509_CRL) *crls)
+handle_manifest(struct rpki_uri const *uri, STACK_OF(X509_CRL) *crls,
+    struct rpp **pp)
 {
        static OID oid = OID_MANIFEST;
        struct oid_arcs arcs = OID2ARCS(oid);
+       struct signed_object_args sobj_args;
        struct manifest mft;
        int error;
 
        pr_debug_add("Manifest %s {", uri->global);
        fnstack_push(uri->global);
 
+       sobj_args.uri = uri;
+       sobj_args.crls = crls;
+       sobj_args.res = NULL;
+       memset(&sobj_args.refs, 0, sizeof(sobj_args.refs));
        mft.file_path = uri->global;
 
-       error = signed_object_decode(uri, &asn_DEF_Manifest, &arcs,
-           (void **) &mft.obj, crls, NULL);
+       error = signed_object_decode(&sobj_args, &asn_DEF_Manifest, &arcs,
+           (void **) &mft.obj); /* mft.obj and sobj_args.refs in the heap */
        if (error)
-               goto end;
+               goto end1;
 
        error = validate_manifest(mft.obj);
-       if (!error)
-               error = __handle_manifest(&mft);
+       if (error)
+               goto end2;
+       error = __handle_manifest(&mft, pp); /* pp in the heap */
+       if (error)
+               goto end2;
+
+       error = refs_validate_ee(&sobj_args.refs, *pp, uri);
+       if (error)
+               rpp_destroy(*pp);
 
+end2:
        ASN_STRUCT_FREE(asn_DEF_Manifest, mft.obj);
-end:
+       refs_cleanup(&sobj_args.refs);
+end1:
        pr_debug_rm("}");
        fnstack_pop();
        return error;
index fc3e07caeae316c7b21b7ac39a696d49867fe81f..3bc894bd9d0f660df7a32f2b918a8b231957c147 100644 (file)
@@ -3,7 +3,9 @@
 
 #include <openssl/x509.h>
 #include "uri.h"
+#include "rpp.h"
 
-int handle_manifest(struct rpki_uri const *, STACK_OF(X509_CRL) *);
+int handle_manifest(struct rpki_uri const *, STACK_OF(X509_CRL) *,
+    struct rpp **);
 
 #endif /* SRC_OBJECT_MANIFEST_H_ */
index 3707f845b157eecaf2d11f2060eb81b5ec550df6..5e6c3762c50cf1f2bad07525229408f52723fe29 100644 (file)
@@ -168,33 +168,43 @@ family_error:
        return pr_err("ROA's IP family is not v4 or v6.");
 }
 
-int handle_roa(struct rpki_uri const *uri, STACK_OF(X509_CRL) *crls)
+int handle_roa(struct rpki_uri const *uri, struct rpp *pp,
+    STACK_OF(X509_CRL) *crls)
 {
        static OID oid = OID_ROA;
        struct oid_arcs arcs = OID2ARCS(oid);
+       struct signed_object_args sobj_args;
        struct RouteOriginAttestation *roa;
-       /* Resources contained in the ROA certificate, not in the ROA itself. */
-       struct resources *cert_resources;
        int error;
 
        pr_debug_add("ROA %s {", uri->global);
        fnstack_push(uri->global);
 
-       cert_resources = resources_create();
-       if (cert_resources == NULL) {
+       sobj_args.uri = uri;
+       sobj_args.crls = crls;
+       sobj_args.res = resources_create();
+       if (sobj_args.res == NULL) {
                error = pr_enomem();
                goto end1;
        }
+       memset(&sobj_args.refs, 0, sizeof(sobj_args.refs));
 
-       error = signed_object_decode(uri, &asn_DEF_RouteOriginAttestation,
-           &arcs, (void **) &roa, crls, cert_resources);
+       error = signed_object_decode(&sobj_args,
+           &asn_DEF_RouteOriginAttestation, &arcs, (void **) &roa);
        if (error)
                goto end2;
-       error = __handle_roa(roa, cert_resources);
-       ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
 
+       error = __handle_roa(roa, sobj_args.res);
+       if (error)
+               goto end3;
+
+       error = refs_validate_ee(&sobj_args.refs, pp, sobj_args.uri);
+
+end3:
+       ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
+       refs_cleanup(&sobj_args.refs);
 end2:
-       resources_destroy(cert_resources);
+       resources_destroy(sobj_args.res);
 end1:
        pr_debug_rm("}");
        fnstack_pop();
index 9638b17b62b692fefad1affcfaf52dd51eeecac2..c77b7da1db270844e3b00a3f0482a409404d0ca2 100644 (file)
@@ -2,8 +2,9 @@
 #define SRC_OBJECT_ROA_H_
 
 #include <openssl/x509.h>
+#include "rpp.h"
 #include "uri.h"
 
-int handle_roa(struct rpki_uri const *uri, STACK_OF(X509_CRL) *);
+int handle_roa(struct rpki_uri const *, struct rpp *, STACK_OF(X509_CRL) *);
 
 #endif /* SRC_OBJECT_ROA_H_ */
index 5c05e46119879bccf4f3ab084faa21849a5eae18..644c6be132ec1b72b9e92af4300097908d78463b 100644 (file)
@@ -4,7 +4,6 @@
 #include "log.h"
 #include "asn1/content_info.h"
 #include "asn1/decode.h"
-#include "asn1/signed_data.h"
 
 static int
 validate_eContentType(struct SignedData *sdata,
@@ -56,22 +55,20 @@ validate_content_type(struct SignedData *sdata,
 }
 
 int
-signed_object_decode(struct rpki_uri const *uri,
+signed_object_decode(struct signed_object_args *args,
     asn_TYPE_descriptor_t const *descriptor,
     struct oid_arcs const *oid,
-    void **result,
-    STACK_OF(X509_CRL) *crls,
-    struct resources *res)
+    void **result)
 {
        struct ContentInfo *cinfo;
        struct SignedData *sdata;
        int error;
 
-       error = content_info_load(uri, &cinfo);
+       error = content_info_load(args->uri, &cinfo);
        if (error)
                goto end1;
 
-       error = signed_data_decode(&cinfo->content, &sdata, crls, res);
+       error = signed_data_decode(&cinfo->content, args, &sdata);
        if (error)
                goto end2;
 
index 55db7d27122ad3268e067f96dc7e93ff825b9713..6898a6373e2af3f181629df0d9fac1fd079a1777 100644 (file)
@@ -3,10 +3,9 @@
 
 #include <openssl/x509.h>
 #include "asn1/oid.h"
-#include "resource.h"
-#include "uri.h"
+#include "asn1/signed_data.h"
 
-int signed_object_decode(struct rpki_uri const *, asn_TYPE_descriptor_t const *,
-    struct oid_arcs const *, void **, STACK_OF(X509_CRL) *, struct resources *);
+int signed_object_decode(struct signed_object_args *args,
+    asn_TYPE_descriptor_t const *, struct oid_arcs const *, void **);
 
 #endif /* SRC_OBJECT_SIGNED_OBJECT_H_ */
index 7000d1175c2b2bddb94209a4b642a715b44cd2fe..4022b6ccfaf9a90290eacec56e0a8c6c0554f1c7 100644 (file)
@@ -199,7 +199,7 @@ foreach_uri(struct tal *tal, foreach_uri_cb cb)
        int error;
 
        for (i = 0; i < tal->uris.count; i++) {
-               error = uri_init(&uri, tal->uris.array[i]);
+               error = uri_init_str(&uri, tal->uris.array[i]);
                if (error)
                        return error;
 
index 22eabbcbedced0c34bffba2309159514a4710d4a..f5573e9fed1f693c5179a52c66e0f33ea0cb91e3 100644 (file)
@@ -2,7 +2,6 @@
 
 #include <errno.h>
 #include <arpa/inet.h>
-#include <sys/queue.h>
 
 #include "address.h"
 #include "log.h"
@@ -17,19 +16,8 @@ struct resources {
        struct resources_ipv4 *ip4s;
        struct resources_ipv6 *ip6s;
        struct resources_asn *asns;
-
-       /*
-        * Used by restack. Points to the resources of the parent certificate.
-        */
-       SLIST_ENTRY(resources) next;
 };
 
-/*
- * "Resource stack". It's a chain of resources, to complement a chain of
- * certificates.
- */
-SLIST_HEAD(restack, resources);
-
 struct resources *
 resources_create(void)
 {
@@ -522,60 +510,3 @@ resources_contains_ipv6(struct resources *res, struct ipv6_prefix *prefix)
        return res6_contains_prefix(res->ip6s, prefix);
 }
 
-struct restack *
-restack_create(void)
-{
-       struct restack *result;
-
-       result = malloc(sizeof(struct restack));
-       if (result == NULL) {
-               pr_enomem();
-               return NULL;
-       }
-
-       SLIST_INIT(result);
-       return result;
-}
-
-void
-restack_destroy(struct restack *stack)
-{
-       struct resources *resources;
-       unsigned int r = 0;
-
-       while (!SLIST_EMPTY(stack)) {
-               resources = SLIST_FIRST(stack);
-               SLIST_REMOVE_HEAD(stack, next);
-               resources_destroy(resources);
-               r++;
-       }
-
-       free(stack);
-       pr_debug("Deleted %u resources from the stack.", r);
-}
-
-void
-restack_push(struct restack *stack, struct resources *new)
-{
-       SLIST_INSERT_HEAD(stack, new, next);
-}
-
-struct resources *
-restack_pop(struct restack *stack)
-{
-       struct resources *res;
-
-       res = SLIST_FIRST(stack);
-       if (res != NULL) {
-               SLIST_REMOVE_HEAD(stack, next);
-               SLIST_NEXT(res, next) = NULL;
-       }
-
-       return res;
-}
-
-struct resources *
-restack_peek(struct restack *stack)
-{
-       return SLIST_FIRST(stack);
-}
index d488860673ebf62db5d09d8561ce82f29ccf3bff..25cbc63702b543ffeb6b21b3b0f1a9ad14b4cc93 100644 (file)
@@ -21,14 +21,4 @@ bool resources_contains_asn(struct resources *, ASId_t);
 bool resources_contains_ipv4(struct resources *, struct ipv4_prefix *);
 bool resources_contains_ipv6(struct resources *, struct ipv6_prefix *);
 
-/* "Resource stack." Stack of struct resources. */
-struct restack;
-
-struct restack *restack_create(void);
-void restack_destroy(struct restack *);
-
-void restack_push(struct restack *, struct resources *);
-struct resources *restack_pop(struct restack *);
-struct resources *restack_peek(struct restack *);
-
 #endif /* SRC_RESOURCE_H_ */
diff --git a/src/rpp.c b/src/rpp.c
new file mode 100644 (file)
index 0000000..7f4c5e4
--- /dev/null
+++ b/src/rpp.c
@@ -0,0 +1,165 @@
+#include "rpp.h"
+
+#include <stdlib.h>
+#include "array_list.h"
+#include "log.h"
+#include "thread_var.h"
+#include "uri.h"
+#include "object/certificate.h"
+#include "object/crl.h"
+#include "object/roa.h"
+
+ARRAY_LIST(uris, struct rpki_uri)
+
+/** A Repository Publication Point (RFC 6481), as described by some manifest. */
+struct rpp {
+       struct uris certs; /* Certificates */
+
+       struct rpki_uri crl; /* Certificate Revocation List */
+       bool crl_set;
+
+       /* The Manifest is not needed for now. */
+
+       struct uris roas; /* Route Origin Attestations */
+};
+
+struct foreach_args {
+       struct rpp *pp;
+       STACK_OF(X509_CRL) *crls;
+};
+
+struct rpp *
+rpp_create(void)
+{
+       struct rpp *result;
+
+       result = malloc(sizeof(struct rpp));
+       if (result == NULL)
+               goto fail1;
+
+       if (uris_init(&result->certs) != 0)
+               goto fail2;
+       result->crl_set = false;
+       if (uris_init(&result->roas) != 0)
+               goto fail3;
+
+       return result;
+
+fail3:
+       uris_cleanup(&result->certs, uri_cleanup);
+fail2:
+       free(result);
+fail1:
+       return NULL;
+}
+
+void
+rpp_destroy(struct rpp *pp)
+{
+       uris_cleanup(&pp->certs, uri_cleanup);
+       uris_cleanup(&pp->roas, uri_cleanup);
+       free(pp);
+}
+
+int
+rpp_add_cert(struct rpp *pp, struct rpki_uri *uri)
+{
+       return uris_add(&pp->certs, uri);
+}
+
+int
+rpp_add_roa(struct rpp *pp, struct rpki_uri *uri)
+{
+       return uris_add(&pp->roas, uri);
+}
+
+int
+rpp_add_crl(struct rpp *pp, struct rpki_uri *uri)
+{
+       /* rfc6481#section-2.2 */
+       if (pp->crl_set)
+               return pr_err("Repository Publication Point has more than one CRL.");
+
+       pp->crl = *uri;
+       pp->crl_set = true;
+       pr_debug("Manifest CRL: %s", uri->global);
+       return 0;
+}
+
+static int
+add_crl_to_stack(struct rpp *pp, STACK_OF(X509_CRL) *crls)
+{
+       X509_CRL *crl;
+       int error;
+       int idx;
+
+       pr_debug("MANIFEST.CRL: %s", pp->crl.global);
+       fnstack_push(pp->crl.global);
+
+       error = crl_load(&pp->crl, &crl);
+       if (error)
+               goto end;
+
+       idx = sk_X509_CRL_push(crls, crl);
+       if (idx <= 0) {
+               error = crypto_err("Could not add CRL to a CRL stack");
+               X509_CRL_free(crl);
+               goto end;
+       }
+
+end:
+       fnstack_pop();
+       return error;
+}
+
+static int
+traverse_ca_certs(struct rpki_uri const *uri, void *arg)
+{
+       struct foreach_args *args = arg;
+       return certificate_traverse(args->pp, uri, args->crls, false);
+}
+
+static int
+print_roa(struct rpki_uri const *uri, void *arg)
+{
+       struct foreach_args *args = arg;
+       handle_roa(uri, args->pp, args->crls);
+       return 0;
+}
+
+struct rpki_uri const *
+rpp_get_crl(struct rpp const *pp)
+{
+       return pp->crl_set ? &pp->crl : NULL;
+}
+
+int
+rpp_traverse(struct rpp *pp)
+{
+       /*
+        * TODO is the stack supposed to have only the CRLs of this layer,
+        * or all of them?
+        */
+       struct foreach_args args;
+       int error;
+
+       args.pp = pp;
+       args.crls = sk_X509_CRL_new_null();
+       if (args.crls == NULL)
+               return pr_enomem();
+       error = add_crl_to_stack(pp, args.crls);
+       if (error)
+               goto end;
+
+       /* Use CRL stack to validate certificates, and also traverse them. */
+       error = uris_foreach(&pp->certs, traverse_ca_certs, &args);
+       if (error)
+               goto end;
+
+       /* Use valid address ranges to print ROAs that match them. */
+       error = uris_foreach(&pp->roas, print_roa, &args);
+
+end:
+       sk_X509_CRL_pop_free(args.crls, X509_CRL_free);
+       return error;
+}
diff --git a/src/rpp.h b/src/rpp.h
new file mode 100644 (file)
index 0000000..6b687f5
--- /dev/null
+++ b/src/rpp.h
@@ -0,0 +1,19 @@
+#ifndef SRC_RPP_H_
+#define SRC_RPP_H_
+
+#include "uri.h"
+
+struct rpp;
+
+struct rpp *rpp_create(void);
+void rpp_destroy(struct rpp *);
+
+int rpp_add_cert(struct rpp *, struct rpki_uri *);
+int rpp_add_crl(struct rpp *, struct rpki_uri *);
+int rpp_add_roa(struct rpp *, struct rpki_uri *);
+
+struct rpki_uri const *rpp_get_crl(struct rpp const *);
+
+int rpp_traverse(struct rpp *);
+
+#endif /* SRC_RPP_H_ */
index 9c4c08d6855f68e963a2acdc455a4d514e15a01f..1f038197f01c46ad43c865a92c60e2c9167672df 100644 (file)
@@ -1,10 +1,24 @@
 #include "state.h"
 
 #include <errno.h>
+#include <sys/queue.h>
 #include "log.h"
 #include "thread_var.h"
 #include "object/certificate.h"
 
+/**
+ * Cached certificate data.
+ */
+struct certificate {
+       struct rpki_uri uri;
+       struct resources *resources;
+
+       /** Used by certstack. Points to the next stacked certificate. */
+       SLIST_ENTRY(certificate) next;
+};
+
+SLIST_HEAD(certstack, certificate);
+
 /**
  * The current state of the validation cycle.
  *
@@ -20,19 +34,19 @@ struct validation {
 
        /** Certificates we've already validated. */
        STACK_OF(X509) *trusted;
+
        /**
-        * The resources owned by the certificates from @trusted.
+        * Stacked additional data to each @trusted certificate.
         *
-        * (One for each certificate; these two stacks should practically always
-        * have the same size. The reason why I don't combine them is because
-        * libcrypto's validation function wants the stack of X509 and I'm not
-        * creating it over and over again.)
+        * (These two stacks should always have the same size. The reason why I
+        * don't combine them is because libcrypto's validation function needs
+        * the X509 stack, and I'm not creating it over and over again.)
         *
         * (This is a SLIST and not a STACK_OF because the OpenSSL stack
         * implementation is different than the LibreSSL one, and the latter is
         * seemingly not intended to be used outside of its library.)
         */
-       struct restack *rsrcs;
+       struct certstack certs;
 
        /* Did the TAL's public key match the root certificate's public key? */
        enum pubkey_state pubkey_state;
@@ -104,19 +118,12 @@ validation_prepare(struct validation **out, struct tal *tal)
                goto abort2;
        }
 
-       result->rsrcs = restack_create();
-       if (!result->rsrcs) {
-               error = -ENOMEM;
-               goto abort3;
-       }
-
+       SLIST_INIT(&result->certs);
        result->pubkey_state = PKS_UNTESTED;
 
        *out = result;
        return 0;
 
-abort3:
-       sk_X509_pop_free(result->trusted, X509_free);
 abort2:
        X509_STORE_free(result->store);
 abort1:
@@ -128,6 +135,8 @@ void
 validation_destroy(struct validation *state)
 {
        int cert_num;
+       struct certificate *cert;
+       unsigned int c;
 
        cert_num = sk_X509_num(state->trusted);
        if (cert_num != 0) {
@@ -135,7 +144,16 @@ validation_destroy(struct validation *state)
                    cert_num);
        }
 
-       restack_destroy(state->rsrcs);
+       c = 0;
+       while (!SLIST_EMPTY(&state->certs)) {
+               cert = SLIST_FIRST(&state->certs);
+               SLIST_REMOVE_HEAD(&state->certs, next);
+               resources_destroy(cert->resources);
+               free(cert);
+               c++;
+       }
+       pr_debug("Deleted %u certificates from the stack.", c);
+
        sk_X509_pop_free(state->trusted, X509_free);
        X509_STORE_free(state->store);
        free(state);
@@ -159,12 +177,6 @@ validation_certs(struct validation *state)
        return state->trusted;
 }
 
-struct restack *
-validation_resources(struct validation *state)
-{
-       return state->rsrcs;
-}
-
 void validation_pubkey_valid(struct validation *state)
 {
        state->pubkey_state = PKS_VALID;
@@ -180,20 +192,34 @@ enum pubkey_state validation_pubkey_state(struct validation *state)
        return state->pubkey_state;
 }
 
+/**
+ * Ownership of @cert_uri's members will NOT be transferred to @state on
+ * success, and they will be expected to outlive @x509.
+ */
 int
-validation_push_cert(struct validation *state, X509 *cert, bool is_ta)
+validation_push_cert(struct validation *state, struct rpki_uri const *cert_uri,
+    X509 *x509, bool is_ta)
 {
-       struct resources *resources;
+       struct certificate *cert;
        int ok;
        int error;
 
-       resources = resources_create();
-       if (resources == NULL)
-               return pr_enomem();
+       cert = malloc(sizeof(struct certificate));
+       if (cert == NULL) {
+               error = pr_enomem();
+               goto end1;
+       }
+
+       cert->uri = *cert_uri;
+       cert->resources = resources_create();
+       if (cert->resources == NULL) {
+               error = pr_enomem();
+               goto end2;
+       }
 
-       error = certificate_get_resources(cert, resources);
+       error = certificate_get_resources(x509, cert->resources);
        if (error)
-               goto fail;
+               goto end3;
 
        /*
         * rfc7730#section-2.2
@@ -202,36 +228,41 @@ validation_push_cert(struct validation *state, X509 *cert, bool is_ta)
         * The "It MUST NOT use the "inherit" form of the INR extension(s)"
         * part is already handled in certificate_get_resources().
         */
-       if (is_ta && resources_empty(resources))
-               return pr_err("Trust Anchor certificate does not define any number resources.");
+       if (is_ta && resources_empty(cert->resources)) {
+               error = pr_err("Trust Anchor certificate does not define any number resources.");
+               goto end3;
+       }
 
-       ok = sk_X509_push(state->trusted, cert);
+       ok = sk_X509_push(state->trusted, x509);
        if (ok <= 0) {
                error = crypto_err(
                    "Couldn't add certificate to trusted stack: %d", ok);
-               goto fail;
+               goto end3;
        }
 
-       restack_push(state->rsrcs, resources);
+       SLIST_INSERT_HEAD(&state->certs, cert, next);
+
        return 0;
 
-fail:
-       resources_destroy(resources);
-       return error;
+end3:  resources_destroy(cert->resources);
+end2:  free(cert);
+end1:  return error;
 }
 
 int
 validation_pop_cert(struct validation *state)
 {
-       struct resources *resources;
+       struct certificate *cert;
 
        if (sk_X509_pop(state->trusted) == NULL)
-               return pr_crit("Attempted to pop empty certificate stack");
+               return pr_crit("Attempted to pop empty certificate stack (1)");
 
-       resources = restack_pop(state->rsrcs);
-       if (resources == NULL)
-               return pr_crit("Attempted to pop empty resource stack");
-       resources_destroy(resources);
+       cert = SLIST_FIRST(&state->certs);
+       if (cert == NULL)
+               return pr_crit("Attempted to pop empty certificate stack (2)");
+       SLIST_REMOVE_HEAD(&state->certs, next);
+       resources_destroy(cert->resources);
+       free(cert);
 
        return 0;
 }
@@ -242,8 +273,16 @@ validation_peek_cert(struct validation *state)
        return sk_X509_value(state->trusted, sk_X509_num(state->trusted) - 1);
 }
 
+struct rpki_uri const *
+validation_peek_cert_uri(struct validation *state)
+{
+       struct certificate *cert = SLIST_FIRST(&state->certs);
+       return (cert != NULL) ? &cert->uri : NULL;
+}
+
 struct resources *
 validation_peek_resource(struct validation *state)
 {
-       return restack_peek(state->rsrcs);
+       struct certificate *cert = SLIST_FIRST(&state->certs);
+       return (cert != NULL) ? cert->resources : NULL;
 }
index 0c97b0f4520fb98bd4677e221713ecf8a7cbe5a3..44e4f3fe70623e2e24f3a47b25064c67205b317e 100644 (file)
@@ -13,7 +13,6 @@ void validation_destroy(struct validation *);
 struct tal *validation_tal(struct validation *);
 X509_STORE *validation_store(struct validation *);
 STACK_OF(X509) *validation_certs(struct validation *);
-struct restack *validation_resources(struct validation *);
 
 enum pubkey_state {
        PKS_VALID,
@@ -25,9 +24,11 @@ void validation_pubkey_valid(struct validation *);
 void validation_pubkey_invalid(struct validation *);
 enum pubkey_state validation_pubkey_state(struct validation *);
 
-int validation_push_cert(struct validation *, X509 *, bool);
+int validation_push_cert(struct validation *, struct rpki_uri const *, X509 *,
+    bool);
 int validation_pop_cert(struct validation *);
 X509 *validation_peek_cert(struct validation *);
+struct rpki_uri const *validation_peek_cert_uri(struct validation *);
 
 struct resources *validation_peek_resource(struct validation *);
 
index 58f6c266bf9624b501e6ae016aef25f8a3cc8e0a..8fa68e13984a5bb14711797e9006cfd3952cd2e2 100644 (file)
--- a/src/uri.c
+++ b/src/uri.c
@@ -8,17 +8,10 @@
  * This function does not assume that @str is null-terminated.
  */
 static int
-str2global(char const *str, size_t str_len, struct rpki_uri *uri)
+str2global(void const *str, size_t str_len, struct rpki_uri *uri)
 {
-       uri->global = malloc(str_len + 1);
-       if (uri->global == NULL)
-               return pr_enomem();
-       strncpy(uri->global, str, str_len);
-       uri->global[str_len] = '\0';
-
        uri->global_len = str_len;
-
-       return 0;
+       return string_clone(str, str_len, &uri->global);
 }
 
 /**
@@ -124,11 +117,11 @@ autocomplete_local(struct rpki_uri *uri)
 }
 
 int
-uri_init(struct rpki_uri *uri, char const *guri)
+uri_init(struct rpki_uri *uri, void const *guri, size_t guri_len)
 {
        int error;
 
-       error = str2global(guri, strlen(guri), uri);
+       error = str2global(guri, guri_len, uri);
        if (error)
                return error;
 
@@ -141,8 +134,19 @@ uri_init(struct rpki_uri *uri, char const *guri)
        return 0;
 }
 
+/**
+ * Do not call this function unless you're sure that @guri is NULL-terminated.
+ */
+int uri_init_str(struct rpki_uri *uri, char const *guri)
+{
+       return uri_init(uri, guri, strlen(guri));
+}
+
+/*
+ * Manifests URIs are a little special in that they are relative.
+ */
 int
-uri_init_ia5(struct rpki_uri *uri, char const *mft, IA5String_t *ia5)
+uri_init_mft(struct rpki_uri *uri, char const *mft, IA5String_t *ia5)
 {
        int error;
 
@@ -162,7 +166,6 @@ uri_init_ad(struct rpki_uri *uri, ACCESS_DESCRIPTION *ad)
 {
        ASN1_STRING *asn1_string;
        int type;
-       int error;
 
        asn1_string = GENERAL_NAME_get0_value(ad->location, &type);
 
@@ -201,16 +204,8 @@ uri_init_ad(struct rpki_uri *uri, ACCESS_DESCRIPTION *ad)
         * directory our g2l version of @asn1_string should contain.
         * But ask the testers to keep an eye on it anyway.
         */
-       error = str2global((char *) ASN1_STRING_get0_data(asn1_string),
-           ASN1_STRING_length(asn1_string), uri);
-       if (error)
-               return error;
-
-       error = autocomplete_local(uri);
-       if (error)
-               free(uri->global);
-
-       return error;
+       return uri_init(uri, ASN1_STRING_get0_data(asn1_string),
+           ASN1_STRING_length(asn1_string));
 }
 
 void
index 62c6ed55c8c5dff453cc7d631956ce0ee89351ac..e5e6b7c838a0d7ff4ecc517fc6dede45381aef9d 100644 (file)
--- a/src/uri.h
+++ b/src/uri.h
@@ -28,8 +28,9 @@ struct rpki_uri {
        /* "local_len" is not needed for now. */
 };
 
-int uri_init(struct rpki_uri *, char const *guri);
-int uri_init_ia5(struct rpki_uri *, char const *, IA5String_t *);
+int uri_init(struct rpki_uri *, void const *, size_t);
+int uri_init_str(struct rpki_uri *uri, char const *guri);
+int uri_init_mft(struct rpki_uri *, char const *, IA5String_t *);
 int uri_init_ad(struct rpki_uri *, ACCESS_DESCRIPTION *ad);
 void uri_cleanup(struct rpki_uri *);