]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Hard-linked fallback (Design 5)
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Sat, 28 Sep 2024 02:53:03 +0000 (20:53 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Sat, 28 Sep 2024 02:53:03 +0000 (20:53 -0600)
Testing and course correcting, week 3. Unstable.

49 files changed:
src/Makefile.am
src/asn1/signed_data.c
src/asn1/signed_data.h
src/cache.c
src/cache.h
src/cachent.c [deleted file]
src/cachent.h [deleted file]
src/cert_stack.c [deleted file]
src/cert_stack.h [deleted file]
src/certificate_refs.c
src/certificate_refs.h
src/common.c
src/extension.c
src/incidence.c
src/incidence.h
src/object/certificate.c
src/object/certificate.h
src/object/crl.c
src/object/crl.h
src/object/ghostbusters.c
src/object/ghostbusters.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/print_file.c
src/resource.c
src/resource.h
src/rpp.c
src/rpp.h
src/rrdp.c
src/rrdp.h
src/rsync.c
src/rsync.h
src/state.c
src/state.h
src/thread_var.h
src/types/map.c
src/types/map.h
src/types/name.c
src/types/name.h
test/cache_util.c
test/cachent_test.c
test/object/manifest_test.c
test/object/tal_test.c
test/rrdp_test.c

index 83ae4720882c89dd0fe21ad08455ce32551f9c50..2674517a61ef56abf67a3027e985bb2f0d41c6a1 100644 (file)
@@ -10,10 +10,8 @@ fort_SOURCES += asn1/oid.h asn1/oid.c
 fort_SOURCES += asn1/signed_data.h asn1/signed_data.c
 fort_SOURCES += base64.h base64.c
 fort_SOURCES += cache.c cache.h
-fort_SOURCES += cachent.c cachent.h
 fort_SOURCES += cachetmp.c cachetmp.h
 fort_SOURCES += certificate_refs.h certificate_refs.c
-fort_SOURCES += cert_stack.h cert_stack.c
 fort_SOURCES += common.c common.h
 fort_SOURCES += config/boolean.c config/boolean.h
 fort_SOURCES += config/filename_format.h config/filename_format.c
@@ -40,7 +38,7 @@ fort_SOURCES += json_util.c json_util.h
 fort_SOURCES += libcrypto_util.h libcrypto_util.c
 fort_SOURCES += log.h log.c
 fort_SOURCES += nid.h nid.c
-fort_SOURCES += object/bgpsec.h object/bgpsec.c
+#fort_SOURCES += object/bgpsec.h object/bgpsec.c
 fort_SOURCES += object/certificate.h object/certificate.c
 fort_SOURCES += object/crl.h object/crl.c
 fort_SOURCES += object/ghostbusters.h object/ghostbusters.c
index 05f120b15951b895c2cdbb557d15b3d22de04f4f..3f37ae4c1aeb5787dac680af3fb784a58dc6c46b 100644 (file)
@@ -16,21 +16,6 @@ static const OID oid_cta = OID_CONTENT_TYPE_ATTR;
 static const OID oid_mda = OID_MESSAGE_DIGEST_ATTR;
 static const OID oid_sta = OID_SIGNING_TIME_ATTR;
 
-void
-eecert_init(struct ee_cert *ee, STACK_OF(X509_CRL) *crls, bool force_inherit)
-{
-       ee->res = resources_create(RPKI_POLICY_RFC6484, force_inherit);
-       ee->crls = crls;
-       memset(&ee->refs, 0, sizeof(ee->refs));
-}
-
-void
-eecert_cleanup(struct ee_cert *ee)
-{
-       resources_destroy(ee->res);
-       refs_cleanup(&ee->refs);
-}
-
 static int
 get_sid(struct SignerInfo *sinfo, OCTET_STRING_t **result)
 {
@@ -48,12 +33,10 @@ get_sid(struct SignerInfo *sinfo, OCTET_STRING_t **result)
 }
 
 static int
-handle_sdata_certificate(ANY_t *cert_encoded, struct ee_cert *ee,
+handle_sdata_certificate(ANY_t *cert_encoded, struct rpki_certificate *ee,
     OCTET_STRING_t *sid, ANY_t *signedData, SignatureValue_t *signature)
 {
        const unsigned char *otmp, *tmp;
-       X509 *cert;
-       enum rpki_policy policy;
        int error;
 
        /*
@@ -70,40 +53,31 @@ handle_sdata_certificate(ANY_t *cert_encoded, struct ee_cert *ee,
         */
        tmp = (const unsigned char *) cert_encoded->buf;
        otmp = tmp;
-       cert = d2i_X509(NULL, &tmp, cert_encoded->size);
-       if (cert == NULL) {
-               error = val_crypto_err("Signed object's 'certificate' element does not decode into a Certificate");
-               goto end1;
-       }
-       if (tmp != otmp + cert_encoded->size) {
-               error = val_crypto_err("Signed object's 'certificate' element contains trailing garbage");
-               goto end2;
-       }
+       ee->x509 = d2i_X509(NULL, &tmp, cert_encoded->size);
+       if (ee->x509 == NULL)
+               return val_crypto_err("Signed object's 'certificate' element does not decode into a Certificate");
+       if (tmp != otmp + cert_encoded->size)
+               return val_crypto_err("Signed object's 'certificate' element contains trailing garbage");
 
-       x509_name_pr_debug("Issuer", X509_get_issuer_name(cert));
+       x509_name_pr_debug("Issuer", X509_get_issuer_name(ee->x509));
 
-       error = certificate_validate_chain(cert, ee->crls);
+       error = certificate_validate_chain(ee);
        if (error)
-               goto end2;
-       error = certificate_validate_rfc6487(cert, CERTYPE_EE);
+               return error;
+       error = certificate_validate_rfc6487(ee);
        if (error)
-               goto end2;
-       error = certificate_validate_extensions_ee(cert, sid, &ee->refs,
-           &policy);
+               return error;
+       error = certificate_validate_extensions_ee(ee, sid);
        if (error)
-               goto end2;
-       error = certificate_validate_aia(ee->refs.caIssuers, cert);
+               return error;
+       error = certificate_validate_aia(ee);
        if (error)
-               goto end2;
-       error = certificate_validate_signature(cert, signedData, signature);
+               return error;
+       error = certificate_validate_signature(ee->x509, signedData, signature);
        if (error)
-               goto end2;
-
-       resources_set_policy(ee->res, policy);
-       error = certificate_get_resources(cert, ee->res, CERTYPE_EE);
-
-end2:  X509_free(cert);
-end1:  return error;
+               return error;
+       resources_set_policy(ee->resources, ee->policy);
+       return certificate_get_resources(ee);
 }
 
 /* rfc6488#section-2.1.6.4.1 */
@@ -240,7 +214,7 @@ illegal_attrType:
 
 int
 signed_data_validate(ANY_t *encoded, struct SignedData *sdata,
-                    struct ee_cert *ee)
+     struct rpki_certificate *ee)
 {
        struct SignerInfo *sinfo;
        OCTET_STRING_t *sid = NULL;
index fe3f6266a8bf91bfc1d3723d8765d382f9ded073..fc22061c777aa5febb63128af6cd1926402e3b7d 100644 (file)
@@ -4,26 +4,11 @@
 /* Some wrappers for asn1/asn1c/SignedData.h. */
 
 #include "asn1/asn1c/SignedData.h"
-#include "certificate_refs.h"
-#include "resource.h"
-
-struct ee_cert {
-       /** CRL that might or might not revoke the EE certificate. */
-       STACK_OF(X509_CRL) *crls;
-       /** A copy of the resources carried by the EE certificate. */
-       struct resources *res;
-       /**
-        * A bunch of URLs found in the EE certificate's extensions,
-        * recorded for future validation.
-        */
-       struct certificate_refs refs;
-};
-
-void eecert_init(struct ee_cert *, STACK_OF(X509_CRL) *, bool);
-void eecert_cleanup(struct ee_cert *);
+#include "object/certificate.h"
 
 int signed_data_decode(ANY_t *, struct SignedData **);
-int signed_data_validate(ANY_t *, struct SignedData *, struct ee_cert *);
+int signed_data_validate(ANY_t *, struct SignedData *,
+    struct rpki_certificate *);
 
 int get_content_type_attr(struct SignedData *, OBJECT_IDENTIFIER_t **);
 
index 5b07e973949752b0e062540ce4bc0cea38f19a14..472f731e1c27e703464ae57609835617aafaa2e7 100644 (file)
@@ -1,14 +1,10 @@
-/*
- * - We only need to keep nodes for the rsync root.
- * - The tree traverse only needs to touch files.
- * - RRDP needs caging.
- */
-
 #include "cache.h"
 
 #include <ftw.h>
+#include <stdbool.h>
+#include <sys/stat.h>
 
-#include "cachent.h"
+#include "alloc.h"
 #include "cachetmp.h"
 #include "common.h"
 #include "config.h"
 #include "http.h"
 #include "log.h"
 #include "rpp.h"
+#include "rrdp.h"
 #include "rsync.h"
 #include "types/path.h"
 #include "types/url.h"
+#include "types/uthash.h"
 
-/* XXX force RRDP if one RPP fails to validate by rsync? */
+struct cache_node {
+       struct cache_mapping map;
 
-typedef int (*dl_cb)(struct cache_node *rpp);
+       int fresh;              /* Refresh already attempted? */
+       int dlerr;              /* Result code of recent download attempt */
+       time_t mtim;            /* Last successful download time, or zero */
 
-struct cached_file {
-       char *url;
-       char *path;
-       UT_hash_handle hh; /* Hash table hook */
+       struct rrdp_state *rrdp;
+
+       UT_hash_handle hh;      /* Hash table hook */
 };
 
-struct cached_rpp {
-       struct cached_file *ht;
+typedef int (*dl_cb)(struct cache_node *rpp);
+
+struct cache_table {
+       char const *name;
+       bool enabled;
+       unsigned int next_id;
+       size_t pathlen;
+       struct cache_node *nodes; /* Hash Table */
+       dl_cb download;
 };
 
 static struct rpki_cache {
-       struct cache_node *rsync;
-       struct cache_node *https;
-//     time_t startup_ts; /* When we started the last validation */
+       /* Latest view of the remote rsync modules */
+       struct cache_table rsync;
+       /* Latest view of the remote HTTPS TAs */
+       struct cache_table https;
+       /* Latest view of the remote RRDP cages */
+       struct cache_table rrdp;
+       /* Committed RPPs and TAs (offline fallback hard links) */
+       struct cache_table fallback;
 } cache;
 
+struct cache_cage {
+       struct cache_node *refresh;
+       struct cache_node *fallback;
+};
+
 #define CACHE_METAFILE "cache.json"
 #define TAGNAME_VERSION "fort-version"
 
@@ -58,6 +75,26 @@ static struct rpki_cache {
 #define TYPEVALUE_RPP "RPP"
 #define TYPEVALUE_NOTIF "RRDP Notification"
 
+#ifdef UNIT_TESTING
+static void __delete_node_cb(struct cache_node const *);
+#endif
+
+static void
+delete_node(struct cache_table *tbl, struct cache_node *node)
+{
+#ifdef UNIT_TESTING
+       __delete_node_cb(node);
+#endif
+
+       HASH_DEL(tbl->nodes, node);
+
+       free(node->map.url);
+       free(node->map.path);
+       if (node->rrdp)
+               rrdp_state_cleanup(node->rrdp);
+       free(node);
+}
+
 static char *
 get_cache_filename(char const *name, bool fatal)
 {
@@ -103,6 +140,29 @@ fail:
        return error;
 }
 
+static int dl_rsync(struct cache_node *);
+static int dl_http(struct cache_node *);
+static int dl_rrdp(struct cache_node *);
+
+static void
+init_table(struct cache_table *tbl, char const *name, bool enabled, dl_cb dl)
+{
+       memset(tbl, 0, sizeof(*tbl));
+       tbl->name = name;
+       tbl->enabled = enabled;
+       tbl->pathlen = strlen(config_get_local_repository()) + strlen(name) + 6;
+       tbl->download = dl;
+}
+
+static void
+init_tables(void)
+{
+       init_table(&cache.rsync, "rsync", config_get_rsync_enabled(), dl_rsync);
+       init_table(&cache.rsync, "https", config_get_http_enabled(), dl_http);
+       init_table(&cache.rsync, "rrdp", config_get_http_enabled(), dl_rrdp);
+       init_table(&cache.fallback, "fallback", true, NULL);
+}
+
 static void
 init_cache_metafile(void)
 {
@@ -188,6 +248,7 @@ init_tmp_dir(void)
 int
 cache_setup(void)
 {
+       init_tables();
        init_cache_metafile();
        init_tmp_dir();
        init_cachedir_tag();
@@ -303,9 +364,6 @@ cache_teardown(void)
 static void
 load_tal_json(void)
 {
-       cache.rsync = cachent_root_rsync();
-       cache.https = cachent_root_https();
-
 //     char *filename;
 //     json_t *root;
 //     json_error_t jerror;
@@ -447,355 +505,283 @@ write_tal_json(void)
 //     free(filename);
 }
 
-/*
- * The "rsync module" is the component immediately after the domain.
- *
- * get_rsync_module(rsync://a.b.c/d/e/f/potato.mft) = d
- */
-static struct cache_node *
-get_rsync_module(struct cache_node *node)
-{
-       struct cache_node *gp; /* Grandparent */
-
-       if (!node || !node->parent || !node->parent->parent)
-               return NULL;
-
-       for (gp = node->parent->parent; gp->parent != NULL; gp = gp->parent)
-               node = node->parent;
-       return node;
-}
-
 static int
-dl_rrdp(struct cache_node *rpp)
+dl_rsync(struct cache_node *module)
 {
        int error;
 
-       if (!config_get_http_enabled()) {
-               pr_val_debug("HTTP is disabled.");
-               return 1;
-       }
-
-       // XXX needs to add all files to node.
-       // Probably also update node itself.
-       // XXX maybe pr_crit() on !mft->parent?
-       error = rrdp_update(rpp);
+       error = rsync_download(&module->map);
        if (error)
-               pr_val_debug("RRDP RPP: Failed refresh.");
+               return error;
 
-       return error;
+       module->mtim = time_nonfatal(); /* XXX probably not needed */
+       return 0;
 }
 
 static int
-dl_rsync(struct cache_node *rpp)
+dl_rrdp(struct cache_node *notif)
 {
-       struct cache_node *module, *node;
-       char *tmppath;
+       time_t mtim;
+       bool changed;
        int error;
 
-       if (!config_get_rsync_enabled()) {
-               pr_val_debug("rsync is disabled.");
-               return 1;
-       }
-
-       module = get_rsync_module(rpp);
-       if (module == NULL)
-               return -EINVAL; // XXX
+       mtim = time_nonfatal();
 
-       error = cache_tmpfile(&tmppath);
+       error = rrdp_update(&notif->map, notif->mtim, &changed, &notif->rrdp);
        if (error)
                return error;
 
-       error = rsync_download(module->url, tmppath,
-           (module->flags & CNF_CACHED) ? module->path : NULL);
-       if (error) {
-               free(tmppath);
-               return error;
-       }
-
-       module->flags |= CNF_RSYNC | CNF_CACHED | CNF_FRESH | CNF_FREE_TMPPATH;
-       module->mtim = time_nonfatal();
-       module->tmppath = tmppath;
-
-       for (node = rpp; node != module; node = node->parent) {
-               node->flags |= RSYNC_INHERIT;
-               node->mtim = module->mtim;
-       }
-
+       if (changed)
+               notif->mtim = mtim;
        return 0;
 }
 
 static int
-dl_http(struct cache_node *node)
+dl_http(struct cache_node *file)
 {
-       char *tmppath;
        time_t mtim;
        bool changed;
        int error;
 
-       if (!config_get_http_enabled()) {
-               pr_val_debug("HTTP is disabled.");
-               return 1;
-       }
-
-       error = cache_tmpfile(&tmppath);
-       if (error)
-               return error;
-
        mtim = time_nonfatal();
 
-       error = http_download(node->url, tmppath, node->mtim, &changed);
-       if (error) {
-               free(tmppath);
+       error = http_download(file->map.url, file->map.path,
+           file->mtim, &changed);
+       if (error)
                return error;
-       }
 
-       node->flags |= CNF_CACHED | CNF_FRESH | CNF_FREE_TMPPATH;
        if (changed)
-               node->mtim = mtim;
-       node->tmppath = tmppath;
+               file->mtim = mtim;
        return 0;
 }
 
-static char *
-get_tmppath(struct cache_node *node)
+static struct cache_node *
+find_node(struct cache_table *tbl, char const *url, size_t urlen)
 {
-       struct cache_node *ancestor;
-       struct path_builder pb;
-       size_t skiplen;
+       struct cache_node *node;
+       HASH_FIND(hh, tbl->nodes, url, urlen, node);
+       return node;
+}
 
-       if (node->tmppath != NULL)
-               return node->tmppath;
+static char *
+create_path(struct cache_table *tbl)
+{
+       char *path;
+       int len;
 
-       ancestor = node;
        do {
-               ancestor = ancestor->parent;
-               if (ancestor == NULL) {
-                       /* May warrant pr_crit(), but I'm chickening out. */
-                       pr_val_err("The download function did not set any tmppaths.");
+               path = pmalloc(tbl->pathlen);
+
+               len = snprintf(path, tbl->pathlen, "%s/%s/%X",
+                   config_get_local_repository(), tbl->name, tbl->next_id);
+               if (len < 0) {
+                       pr_val_err("Cannot compute new cache path: Unknown cause.");
                        return NULL;
                }
-       } while (ancestor->tmppath == NULL);
+               if (len < tbl->pathlen) {
+                       tbl->next_id++;
+                       return path; /* Happy path */
+               }
 
-       skiplen = strlen(ancestor->path);
-       if (strncmp(ancestor->path, node->path, skiplen) != 0)
-               pr_crit("???"); // XXX
+               tbl->pathlen++;
+               free(path);
+       } while (true);
+}
 
-       pb_init(&pb);
-       if (pb_append(&pb, ancestor->tmppath) != 0)
-               goto cancel;
-       if (pb_append(&pb, node->path + skiplen) != 0)
-               goto cancel;
+static struct cache_node *
+provide_node(struct cache_table *tbl, char const *url)
+{
+       size_t urlen;
+       struct cache_node *node;
 
-       node->flags |= CNF_FREE_TMPPATH;
-       node->tmppath = pb.string;
-       return pb.string;
+       urlen = strlen(url);
+       node = find_node(tbl, url, urlen);
+       if (node)
+               return node;
+
+       node = pzalloc(sizeof(struct cache_node));
+       node->map.url = pstrdup(url);
+       node->map.path = create_path(tbl);
+       if (!node->map.path) {
+               free(node->map.url);
+               free(node);
+               return NULL;
+       }
+       HASH_ADD_KEYPTR(hh, tbl->nodes, node->map.url, urlen, node);
 
-cancel:        pb_cleanup(&pb);
-       return NULL;
+       return node;
 }
 
 /* @uri is either a caRepository or a rpkiNotify */
 static struct cache_node *
-do_refresh(char const *uri, struct cache_node *root, dl_cb download)
+do_refresh(struct cache_table *tbl, char const *uri)
 {
        struct cache_node *node;
 
-       if (!uri)
-               return NULL; /* Protocol unavailable; ignore */
+       if (!tbl->enabled)
+               return NULL;
 
        pr_val_debug("Trying %s (online)...", uri);
 
-       node = cachent_provide(root, uri);
-       if (!node) {
-               pr_val_err("Malformed URL: %s", uri);
+       node = provide_node(tbl, uri);
+       if (!node)
                return NULL;
-       }
 
-       if (!(node->flags & CNF_FRESH)) {
-               node->flags |= CNF_FRESH;
-               node->dlerr = download(node);
+       if (!node->fresh) {
+               node->fresh = true;
+               node->dlerr = tbl->download(node);
        }
-       if (node->dlerr)
-               pr_val_debug("Refresh failed.");
 
+       pr_val_debug(node->dlerr ? "Refresh failed." : "Refresh succeeded.");
        return node;
 }
 
-/* @url needs to outlive @map. */
-int
-cache_refresh_url(char *url, struct cache_mapping *map)
+static struct cache_node *
+get_fallback(char const *caRepository)
+{
+       struct cache_node *node;
+
+       pr_val_debug("Retrieving %s fallback...", caRepository);
+       node = find_node(&cache.fallback, caRepository, strlen(caRepository));
+       pr_val_debug(node ? "Fallback found." : "Fallback unavailable.");
+
+       return node;
+}
+
+/* Do not free nor modify the result. */
+char *
+cache_refresh_url(char const *url)
 {
        struct cache_node *node = NULL;
 
        // XXX mutex
        // XXX review result signs
+       // XXX Normalize @url
 
        if (url_is_https(url))
-               node = do_refresh(url, cache.https, dl_http);
+               node = do_refresh(&cache.https, url);
        else if (url_is_rsync(url))
-               node = do_refresh(url, cache.rsync, dl_rsync);
-       if (!node)
-               return EINVAL;
+               node = do_refresh(&cache.rsync, url);
 
-       // XXX might want to const url and path.
-       // Alternatively, strdup path so the caller can't corrupt our string.
-       map->url = url;
-       map->path = get_tmppath(node);
-       return (map->path != NULL) ? 0 : EINVAL;
+       // XXX Maybe strdup path so the caller can't corrupt our string
+       return node ? node->map.path : NULL;
 }
 
-/* @url needs to outlive @map. */
-int
-cache_fallback_url(char *url, struct cache_mapping *map)
+/* Do not free nor modify the result. */
+char *
+cache_fallback_url(char const *url)
 {
-       struct cache_node *node = NULL;
-
-       if (url_is_https(url))
-               node = cachent_provide(cache.https, url);
-       else if (url_is_rsync(url))
-               node = cachent_provide(cache.rsync, url);
-       if (!node)
-               return EINVAL;
-
-       map->url = url;
-       map->path = node->path;
-       return 0;
+       struct cache_node *node;
+       node = find_node(&cache.fallback, url, strlen(url));
+       return node ? node->map.path : NULL;
 }
 
 /*
  * Attempts to refresh the RPP described by @sias, returns the resulting
  * repository's mapping.
+ *
+ * XXX Need to normalize the sias.
+ * XXX Fallback only if parent is fallback
  */
-int
-cache_refresh_sias(struct sia_uris *sias, struct cache_mapping *map)
+struct cache_cage *
+cache_refresh_sias(struct sia_uris *sias)
 {
-       struct cache_node *hnode;
-       struct cache_node *rnode;
+       struct cache_cage *cage;
+       struct cache_node *node;
 
        // XXX Make sure somewhere validates rpkiManifest matches caRepository.
        // XXX mutex
        // XXX review result signs
        // XXX normalize rpkiNotify & caRepository?
+       // XXX do module if rsync
 
-       hnode = do_refresh(sias->rpkiNotify, cache.https, dl_rrdp);
-       if (hnode && !hnode->dlerr) {
-               map->url = hnode->url;
-               map->path = hnode->tmppath;
-               return 0;
-       }
+       cage = pzalloc(sizeof(struct cache_cage));
+       cage->fallback = get_fallback(sias->caRepository);
 
-       rnode = do_refresh(sias->caRepository, cache.rsync, dl_rsync);
-       if (rnode && !rnode->dlerr) {
-               map->url = rnode->url;
-               map->path = rnode->tmppath;
-               return 0;
+       if (sias->rpkiNotify) {
+               node = do_refresh(&cache.rrdp, sias->rpkiNotify);
+               if (node && !node->dlerr) {
+                       cage->refresh = node;
+                       return cage; /* RRDP + optional fallback happy path */
+               }
        }
 
-       if (hnode && cachent_is_cached(hnode)) {
-               map->url = hnode->url;
-               map->path = hnode->path;
-               return 0;
+       node = do_refresh(&cache.rsync, sias->caRepository);
+       if (node && !node->dlerr) {
+               cage->refresh = node;
+               return cage; /* rsync + optional fallback happy path */
        }
 
-       if (hnode && cachent_is_cached(rnode)) {
-               map->url = hnode->url;
-               map->path = hnode->path;
-               return 0;
+       if (cage->fallback == NULL) {
+               free(cage);
+               return NULL;
        }
 
-       return EINVAL;
-}
-
-void
-cache_print(void)
-{
-       cachent_print(cache.rsync);
-       cachent_print(cache.https);
+       return cage; /* fallback happy path */
 }
 
-static void
-prune_rsync(void)
+char const *
+node2file(struct cache_node *node, char const *url)
 {
-       struct cache_node *domain, *tmp1;
-       struct cache_node *module, *tmp2;
-       struct cache_node *child, *tmp3;
-
-       HASH_ITER(hh, cache.rsync->children, domain, tmp1)
-               HASH_ITER(hh, domain->children, module, tmp2)
-                       HASH_ITER(hh, module->children, child, tmp3) {
-                               pr_op_debug("Removing leftover: %s", child->url);
-                               module->flags |= cachent_delete(child);
-                       }
+       if (node == NULL)
+               return NULL;
+       return (node->rrdp)
+           ? /* RRDP  */ rrdp_file(node->rrdp, url)
+           : /* rsync */ join_paths(node->map.path, url + RPKI_SCHEMA_LEN); // XXX wrong; need to get the module.
 }
 
-static bool
-commit_rpp_delta(struct cache_node *node)
+char const *
+cage_map_file(struct cache_cage *cage, char const *url)
 {
-       struct cache_node *child, *tmp;
-       int error;
+       char const *file;
 
-       pr_op_debug("Commiting %s", node->url);
+       file = node2file(cage->refresh, url);
+       if (!file)
+               file = node2file(cage->fallback, url);
 
-       if (node == cache.rsync || node == cache.https) {
-               pr_op_debug("Root; nothing to commit.");
-               goto branch;
-       }
-
-       if (node->tmppath == NULL) {
-               if (node->children) {
-                       pr_op_debug("Branch.");
-                       goto branch;
-               } else {
-                       pr_op_debug("Unchanged leaf; nothing to commit.");
-                       return true;
-               }
-       }
-
-       if (node->flags & CNF_VALID) {
-               pr_op_debug("Validation successful; committing.");
-               error = file_merge_into(node->tmppath, node->path);
-               if (error)
-                       printf("rename errno: %d\n", error); // XXX
-               /* XXX Think more about the implications of this. */
-               HASH_ITER(hh, node->children, child, tmp)
-                       cachent_delete(child);
-       } else {
-               pr_op_debug("Validation unsuccessful; rollbacking.");
-               /* XXX just do remove()? */
-               file_rm_f(node->tmppath);
-       }
-
-       free(node->tmppath);
-       node->tmppath = NULL;
-       return true;
+       return file;
+}
 
-branch:        /* Clean up state flags */
-       node->flags &= ~(CNF_CACHED | CNF_FRESH | CNF_TOUCHED | CNF_VALID);
-       if (node->tmppath) {
-               free(node->tmppath);
-               node->tmppath = NULL;
-       }
-       return true;
+/* Returns true if previously enabled */
+bool
+cage_disable_refresh(struct cache_cage *cage)
+{
+       bool enabled = (cage->refresh != NULL);
+       cage->refresh = NULL;
+       return enabled;
 }
 
-static int
-rmf(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
+static void
+cachent_print(struct cache_node *node)
 {
-       if (remove(fpath) < 0)
-               pr_op_warn("Can't remove %s: %s", fpath, strerror(errno));
+       if (!node)
+               return;
+
+       printf("\t%s (%s): ", node->map.url, node->map.path);
+       if (node->fresh)
+               printf("fresh (errcode %d)", node->dlerr);
        else
-               pr_op_debug("Removed %s.", fpath);
-       return 0;
+               printf("stale");
+       printf("\n");
 }
 
 static void
-cleanup_tmp(void)
+table_print(struct cache_table *tbl)
 {
-       char *tmpdir = get_cache_filename(CACHE_TMPDIR, true);
-       if (nftw(tmpdir, rmf, 32, FTW_DEPTH | FTW_PHYS))
-               pr_op_warn("Cannot empty the cache's tmp directory: %s",
-                   strerror(errno));
-       free(tmpdir);
+       struct cache_node *node, *tmp;
+
+       printf("%s (%s):", tbl->name, tbl->enabled ? "enabled" : "disabled");
+       HASH_ITER(hh, tbl->nodes, node, tmp)
+               cachent_print(node);
+}
+
+void
+cache_print(void)
+{
+       table_print(&cache.rsync);
+       table_print(&cache.https);
+       table_print(&cache.rrdp);
+       table_print(&cache.fallback);
 }
 
 //static void
@@ -866,88 +852,31 @@ cleanup_tmp(void)
 //     return false;
 //}
 
-static struct cache_node *nftw_root;
-
 static int
-nftw_remove_abandoned(const char *path, const struct stat *st,
-    int typeflag, struct FTW *ftw)
+rmf(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
 {
-       char const *lookup;
-       struct cache_node *pm; /* Perfect Match */
-       struct cache_node *msm; /* Most Specific Match */
-       struct timespec now;
-
-       // XXX
-       lookup = path + strlen(config_get_local_repository());
-       while (lookup[0] == '/')
-               lookup++;
-       pr_op_debug("Removing if abandoned: %s", lookup);
-
-       pm = cachent_find(nftw_root, lookup, &msm);
-       if (pm == cache.rsync || pm == cache.https) {
-               pr_op_debug("Root; skipping.");
-               return 0;
-       }
-       if (!msm) {
-               pr_op_debug("Not matched by the tree; unknown.");
-               goto unknown;
-       }
-       if (!pm && !(msm->flags & CNF_RSYNC)) {
-               /* XXX what about HTTP? */
-               pr_op_debug("RRDP and no perfect match; unknown.");
-               goto unknown; /* The traversal is depth-first */
-       }
-
-       if (S_ISDIR(st->st_mode)) {
-               /*
-                * rmdir() fails if the directory is not empty.
-                * This will happen most of the time.
-                */
-               if (rmdir(path) == 0) {
-                       pr_op_debug("Directory empty; purging node.");
-                       cachent_delete(pm);
-               } else if (errno == ENOENT) {
-                       pr_op_debug("Directory does not exist; purging node.");
-                       cachent_delete(pm);
-               } else {
-                       pr_op_debug("Directory exists and has contents; preserving.");
-               }
-
-       } else if (S_ISREG(st->st_mode)) {
-
-//             if ((msm->flags & CNF_RSYNC) || !pm || (pm->flags & CNF_WITHDRAWN))
-               clock_gettime(CLOCK_REALTIME, &now); // XXX
-               PR_DEBUG_MSG("%ld > %ld", now.tv_sec - st->st_atim.tv_sec, cfg_cache_threshold());
-               if (now.tv_sec - st->st_atim.tv_sec > cfg_cache_threshold()) {
-                       pr_op_debug("Too old; abandoned.");
-                       goto abandoned;
-               }
-               pr_op_debug("Still young; preserving.");
-
-       } else {
-               pr_op_debug("Unknown type; abandoned.");
-               goto abandoned;
-       }
-
+       if (remove(fpath) < 0)
+               pr_op_warn("Can't remove %s: %s", fpath, strerror(errno));
+       else
+               pr_op_debug("Removed %s.", fpath);
        return 0;
+}
 
-abandoned:
-       if (pm)
-               cachent_delete(pm);
-unknown:
-       if (remove(path) < 0)
-               PR_DEBUG_MSG("remove(): %s", strerror(errno)); // XXX
-       return 0;
+static void
+cleanup_tmp(void)
+{
+       char *tmpdir = get_cache_filename(CACHE_TMPDIR, true);
+       if (nftw(tmpdir, rmf, 32, FTW_DEPTH | FTW_PHYS))
+               pr_op_warn("Cannot empty the cache's tmp directory: %s",
+                   strerror(errno));
+       free(tmpdir);
 }
 
-/*
- * Note: It'll probably be healthy if touched nodes also touch their parents.
- * You don't always need to go up all the way to the root.
- * But I'm afraid this will hit the mutexes.
- */
 static void
 remove_abandoned(void)
 {
+       // XXX no need to recurse anymore.
+       /*
        char *rootpath;
 
        rootpath = join_paths(config_get_local_repository(), "rsync");
@@ -961,24 +890,31 @@ remove_abandoned(void)
        nftw(rootpath, nftw_remove_abandoned, 32, FTW_DEPTH | FTW_PHYS); // XXX
 
        free(rootpath);
+       */
 }
 
-static bool
-remove_orphaned(struct cache_node *node)
+static void
+remove_orphaned(struct cache_table *table, struct cache_node *node)
 {
-       if (file_exists(node->path) == ENOENT) {
-               pr_op_debug("Missing file; deleting node: %s", node->path);
-               cachent_delete(node);
-
-               if (node == cache.https)
-                       cache.https = NULL;
-               else if (node == cache.rsync)
-                       cache.rsync = NULL;
-
-               return false;
+       if (file_exists(node->map.path) == ENOENT) {
+               pr_op_debug("Missing file; deleting node: %s", node->map.path);
+               delete_node(table, node);
        }
+}
 
-       return true;
+static void
+cache_foreach(void (*cb)(struct cache_table *, struct cache_node *))
+{
+       struct cache_node *node, *tmp;
+
+       HASH_ITER(hh, cache.rsync.nodes, node, tmp)
+               cb(&cache.rsync, node);
+       HASH_ITER(hh, cache.https.nodes, node, tmp)
+               cb(&cache.https, node);
+       HASH_ITER(hh, cache.rrdp.nodes, node, tmp)
+               cb(&cache.rrdp, node);
+       HASH_ITER(hh, cache.fallback.nodes, node, tmp)
+               cb(&cache.fallback, node);
 }
 
 /*
@@ -987,12 +923,7 @@ remove_orphaned(struct cache_node *node)
 static void
 cleanup_cache(void)
 {
-       pr_op_debug("Ditching redundant rsync nodes.");
-       prune_rsync();
-
-       pr_op_debug("Committing successful RPPs.");
-       cachent_traverse(cache.rsync, commit_rpp_delta);
-       cachent_traverse(cache.https, commit_rpp_delta);
+       // XXX Review
 
        pr_op_debug("Cleaning up temporal files.");
        cleanup_tmp();
@@ -1001,8 +932,7 @@ cleanup_cache(void)
        remove_abandoned();
 
        pr_op_debug("Cleaning up orphaned nodes.");
-       cachent_traverse(cache.rsync, remove_orphaned);
-       cachent_traverse(cache.https, remove_orphaned);
+       cache_foreach(remove_orphaned);
 }
 
 void
@@ -1010,8 +940,7 @@ cache_commit(void)
 {
        cleanup_cache();
        write_tal_json();
-       cachent_delete(cache.rsync);
-       cachent_delete(cache.https);
+       cache_foreach(delete_node);
 }
 
 void
@@ -1026,4 +955,7 @@ sias_cleanup(struct sia_uris *sias)
        free(sias->caRepository);
        free(sias->rpkiNotify);
        free(sias->rpkiManifest);
+       free(sias->crldp);
+       free(sias->caIssuers);
+       free(sias->signedObject);
 }
index 4cfbf321a24c8497d056646daff8f3f175f85eab..fc4ecb4939429cde1d6c4a2b55ef24382afc13ae 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef SRC_CACHE_LOCAL_CACHE_H_
 #define SRC_CACHE_LOCAL_CACHE_H_
 
+#include <stdbool.h>
 #include "types/map.h"
 
 int cache_setup(void);         /* Init this module */
@@ -9,19 +10,40 @@ void cache_teardown(void);   /* Destroy this module */
 void cache_prepare(void);      /* Prepare cache for new validation cycle */
 void cache_commit(void);       /* Finish validation cycle */
 
+/* XXX might wanna rename */
 struct sia_uris {
        char *caRepository;     /* RPP cage */
        char *rpkiNotify;       /* RRDP Notification */
        char *rpkiManifest;
+
+       /**
+        * 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 sias_init(struct sia_uris *);
 void sias_cleanup(struct sia_uris *);
 
-int cache_refresh_url(char *, struct cache_mapping *);
-int cache_fallback_url(char *, struct cache_mapping *);
-int cache_refresh_sias(struct sia_uris *, struct cache_mapping *);
+char *cache_refresh_url(char const *);
+char *cache_fallback_url(char const *);
+
+struct cache_cage;
+struct cache_cage *cache_refresh_sias(struct sia_uris *);
+char const *cage_map_file(struct cache_cage *, char const *);
+bool cage_disable_refresh(struct cache_cage *);
 
-void cache_print(void); /* Dump cache in stdout. Recursive; tests only */
+void cache_print(void);                /* Dump cache in stdout */
 
 #endif /* SRC_CACHE_LOCAL_CACHE_H_ */
diff --git a/src/cachent.c b/src/cachent.c
deleted file mode 100644 (file)
index 46c593e..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-#include "cachent.h"
-
-#include "alloc.h"
-#include "config.h"
-#include "log.h"
-#include "types/array.h"
-#include "types/path.h"
-#include "types/url.h"
-
-static struct cache_node *
-cachent_root(char const *schema, char const *dir)
-{
-       struct cache_node *root;
-
-       root = pzalloc(sizeof(struct cache_node));
-       root->url = (char *)schema;
-       root->path = join_paths(config_get_local_repository(), dir);
-       root->name = path_filename(root->path);
-       root->flags = CNF_FREE_PATH;
-
-       return root;
-}
-
-struct cache_node *
-cachent_root_rsync(void)
-{
-       return cachent_root("rsync://", "rsync");
-}
-
-struct cache_node *
-cachent_root_https(void)
-{
-       return cachent_root("https://", "https");
-}
-
-bool
-cachent_is_cached(struct cache_node *node)
-{
-       if (cachent_is_https(node))
-               return node->flags & CNF_CACHED;
-
-       for (; node != NULL; node = node->parent)
-               if (node->flags & CNF_CACHED)
-                       return true;
-       return false;
-}
-
-/* Preorder. @cb returns whether the children should be traversed. */
-void
-cachent_traverse(struct cache_node *root, bool (*cb)(struct cache_node *))
-{
-       struct cache_node *iter_start;
-       struct cache_node *parent, *child;
-       struct cache_node *tmp;
-
-       if (!root)
-               return;
-
-       if (!cb(root))
-               return;
-
-       parent = root;
-       iter_start = parent->children; /* aka "first child" */
-       if (iter_start == NULL)
-               return;
-
-reloop:        /* iter_start must not be NULL */
-       HASH_ITER(hh, iter_start, child, tmp) {
-               if (cb(child) && (child->children != NULL)) {
-                       parent = child;
-                       iter_start = parent->children;
-                       goto reloop;
-               }
-       }
-
-       do {
-               if (parent == NULL)
-                       return;
-               iter_start = parent->hh.next;
-               parent = parent->parent;
-       } while (iter_start == NULL);
-
-       goto reloop;
-}
-
-static struct cache_node *
-find_child(struct cache_node *parent, char const *name, size_t namelen)
-{
-       struct cache_node *child;
-       HASH_FIND(hh, parent->children, name, namelen, child);
-       return child;
-}
-
-/*
- * Returns perfect match or NULL. @msm will point to the Most Specific Match.
- * Assumes @path is normalized.
- */
-struct cache_node *
-cachent_find(struct cache_node *root, char const *path, struct cache_node **msm)
-{
-       struct tokenizer tkn;
-       struct cache_node *parent;
-       struct cache_node *child;
-
-       token_init(&tkn, path);
-
-       if (!token_next(&tkn) || strncmp(root->name, tkn.str, tkn.len) != 0) {
-               *msm = NULL;
-               return NULL;
-       }
-
-       for (parent = child = root; token_next(&tkn); parent = child) {
-               child = find_child(parent, tkn.str, tkn.len);
-               if (!child) {
-                       if (parent->flags & CNF_NOTIFICATION) {
-                               child = find_child(parent->rrdp.subtree,
-                                   tkn.str, tkn.len);
-                               if (!child)
-                                       goto nochild;
-                       } else {
-nochild:                       *msm = parent;
-                               return NULL;
-                       }
-               }
-       }
-
-       *msm = parent;
-       return child;
-}
-
-// XXX path_childn() dup
-static char *
-inherit_path(char const *parent, char const *name, size_t nlen)
-{
-       char *child;
-       size_t clen;
-
-       clen = strlen(parent) + nlen + 2;
-       child = pmalloc(clen);
-       if (snprintf(child, clen, "%s/%.*s", parent, (int)nlen, name) >= clen)
-               pr_crit("aaaaaa"); // XXX
-
-       return child;
-}
-
-/* Get or create parent's child. */
-static struct cache_node *
-provide(struct cache_node *parent, char const *url,
-    char const *name, size_t namelen)
-{
-       struct cache_node *child;
-
-       child = find_child(parent, name, namelen);
-       if (child != NULL)
-               return child;
-
-       child = pzalloc(sizeof(struct cache_node));
-       child->url = pstrndup(url, name - url + namelen);
-       child->path = inherit_path(parent->path, name, namelen);
-       child->name = child->url + (name - url);
-       child->flags = CNF_FREE_URL | CNF_FREE_PATH;
-       if ((parent->flags & RSYNC_INHERIT) == RSYNC_INHERIT)
-               child->flags |= RSYNC_INHERIT;
-       if (parent->tmppath && !(parent->flags & CNF_RSYNC)) {
-               child->tmppath = inherit_path(parent->tmppath, name, namelen);
-               child->flags |= CNF_FREE_TMPPATH;
-       }
-       child->parent = parent;
-       HASH_ADD_KEYPTR(hh, parent->children, child->name, namelen, child);
-
-       return child;
-}
-
-/*
- * Get or create ancestor's descendant.
- *
- * Suppose @url is "rsync://a.b.c/d/e/f.cer": @ancestor has to be either
- * "rsync:", "rsync://a.b.c", "rsync://a.b.c/d", "rsync://a.b.c/d/e" or
- * "rsync://a.b.c/d/e/f.cer".
- *
- * Returns NULL if @ancestor doesn't match @url.
- *
- * The point of @ancestor is caging. @url will not be allowed to point to
- * anything that is not @ancestor or one of its descendants. (ie. dot-dotting is
- * allowed, but the end result must not land outside of @ancestor.)
- *
- * XXX In the end, it seems this is only being used by root ancestors.
- * Should probably separate the caging to a simple get.
- */
-struct cache_node *
-cachent_provide(struct cache_node *ancestor, char const *url)
-{
-       char *normal;
-       array_index i;
-       struct tokenizer tkn;
-
-       normal = url_normalize(url);
-       if (!normal)
-               return NULL;
-
-       for (i = 0; ancestor->url[i] != 0; i++)
-               if (ancestor->url[i] != normal[i])
-                       goto fail;
-       if (i != RPKI_SCHEMA_LEN && normal[i] != '/' && normal[i] != '\0')
-               goto fail;
-
-       token_init(&tkn, normal + i);
-       while (token_next(&tkn))
-               ancestor = provide(ancestor, normal, tkn.str, tkn.len);
-       free(normal);
-       return ancestor;
-
-fail:  free(normal);
-       return NULL;
-}
-
-#ifdef UNIT_TESTING
-static void __delete_node_cb(struct cache_node const *);
-#endif
-
-static int
-__delete_node(struct cache_node *node)
-{
-       int valid = node->flags & CNF_VALID;
-
-#ifdef UNIT_TESTING
-       __delete_node_cb(node);
-#endif
-
-       if (node->parent != NULL)
-               HASH_DEL(node->parent->children, node);
-       if (node->flags & CNF_FREE_URL)
-               free(node->url);
-       if (node->flags & CNF_FREE_PATH)
-               free(node->path);
-       if (node->flags & CNF_FREE_TMPPATH)
-               free(node->tmppath);
-       if (node->flags & CNF_NOTIFICATION)
-               rrdp_notif_cleanup(&node->rrdp);
-       free(node);
-
-       return valid;
-}
-
-int
-cachent_delete(struct cache_node *node)
-{
-       struct cache_node *parent;
-       int valid;
-
-       if (!node)
-               return 0;
-
-       valid = node->flags & CNF_VALID;
-
-       parent = node->parent;
-       if (parent != NULL) {
-               HASH_DEL(parent->children, node);
-               node->parent = NULL;
-       }
-
-       do {
-               while (node->children)
-                       node = node->children;
-
-               parent = node->parent;
-               valid |= __delete_node(node);
-               node = parent;
-       } while (node != NULL);
-
-       return valid;
-}
-
-static void
-print_node(struct cache_node *node, unsigned int tabs)
-{
-       unsigned int i;
-       struct cache_node *child, *tmp;
-
-       for (i = 0; i < tabs; i++)
-               printf("\t");
-
-       printf("%s -- ", node->name);
-       printf("%s", (node->flags & CNF_RSYNC) ? "rsync " : "");
-       printf("%s", (node->flags & CNF_CACHED) ? "cached " : "");
-       printf("%s", (node->flags & CNF_FRESH) ? "fresh " : "");
-       printf("%s", (node->flags & CNF_TOUCHED) ? "touched " : "");
-       printf("%s", (node->flags & CNF_VALID) ? "valid " : "");
-       printf("%s", (node->flags & CNF_NOTIFICATION) ? "notification " : "");
-       printf("%s", (node->flags & CNF_WITHDRAWN) ? "withdrawn " : "");
-       printf(" -- %s", node->tmppath);
-
-       printf("\n");
-       HASH_ITER(hh, node->children, child, tmp)
-               print_node(child, tabs + 1);
-}
-
-void
-cachent_print(struct cache_node *node)
-{
-       if (node)
-               print_node(node, 0);
-}
diff --git a/src/cachent.h b/src/cachent.h
deleted file mode 100644 (file)
index 2bed18f..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef SRC_CACHE_CACHENT_H_
-#define SRC_CACHE_CACHENT_H_
-
-/* CACHE ENTity, CACHE elemENT, CACHE componENT */
-
-#include <stdbool.h>
-#include <sys/stat.h>
-
-#include "rrdp.h"
-#include "types/uthash.h"
-
-/* XXX rename "touched" and "valid" into "preserve"? */
-
-// XXX trees now separated; consider removing this flag
-#define CNF_RSYNC              (1 << 0)
-/*
- * Do we have a (full) copy in the cache?
- * If disabled, we don't know (because an ancestor was recursively rsync'd).
- */
-#define CNF_CACHED             (1 << 1)
-/*
- * Was it (allegedly) downloaded during the current cycle?
- * "Allegedly" because we might have rsync'd an ancestor.
- */
-#define CNF_FRESH              (1 << 2)
-/* Was it read during the current cycle? */
-#define CNF_TOUCHED            (1 << 4)
-/*
- * Did it validate successfully (at least once) during the current cycle?
- * (It's technically possible for two different repositories to map to the same
- * cache node. One of them is likely going to fail validation.)
- * This only refers to the tmp path; The final path, if it exists, always
- * contains valid objects (until expiration).
- */
-#define CNF_VALID              (1 << 5)
-/* Is the node an RRDP Update Notification? */
-#define CNF_NOTIFICATION       (1 << 6)
-/* Withdrawn by RRDP? */
-#define CNF_WITHDRAWN          (1 << 7)
-
-#define CNF_FREE_URL           (1 << 8)
-#define CNF_FREE_PATH          (1 << 9)
-#define CNF_FREE_TMPPATH       (1 << 10)
-
-/*
- * Flags for children of downloaded rsync nodes that should be cleaned later.
- * (FRESH prevents redownload.)
- * XXX useful?
- */
-#define RSYNC_INHERIT          (CNF_RSYNC | CNF_FRESH)
-
-struct cache_node {
-       char *url;              /* rsync://a.b.c/d/e (normalized) */
-       char *path;             /* path/to/cache/rsync/a.b.c/d/e */
-       char const *name;       /* Points to the last component of @url or @path XXX redundant */
-       int flags;              /* CNF_* */
-
-       int dlerr;              /* Result code of recent download attempt */
-       time_t mtim;            /* Last successful download time, or zero */
-
-       /*
-        * If download attempted, path to the temporal directory where the
-        * refresh was dumped.
-        * (See --compare-dest at rsync(1). RRDP is basically the same.)
-        * Otherwise NULL.
-        */
-       char *tmppath;          /* path/to/cache/tmp/1234 */
-
-       /* Only if flags & CNF_NOTIFICATION */
-       struct cachefile_notification rrdp;
-
-       struct cache_node *parent;      /* Tree parent */
-       struct cache_node *children;    /* Tree children */
-
-       UT_hash_handle hh;              /* Hash table hook */
-};
-
-struct cache_node *cachent_root_rsync(void);
-struct cache_node *cachent_root_https(void);
-
-#define cachent_is_rsync(node) ((node)->flags & CNF_RSYNC)
-#define cachent_is_https(node) (!cachent_is_rsync(node))
-
-bool cachent_is_cached(struct cache_node *);
-
-void cachent_traverse(struct cache_node *, bool (*cb)(struct cache_node *));
-
-struct cache_node *cachent_find(struct cache_node *, char const *,
-    struct cache_node **);
-struct cache_node *cachent_provide(struct cache_node *, char const *);
-int cachent_delete(struct cache_node *);
-
-/* Recursive; tests only. */
-void cachent_print(struct cache_node *);
-
-#endif /* SRC_CACHE_CACHENT_H_ */
diff --git a/src/cert_stack.c b/src/cert_stack.c
deleted file mode 100644 (file)
index dbce828..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-#include "cert_stack.h"
-
-#include <errno.h>
-#include <sys/queue.h>
-
-#include "log.h"
-#include "thread_var.h"
-#include "types/str.h"
-
-enum defer_node_type {
-       DNT_SEPARATOR,
-       DNT_CERT,
-};
-
-struct defer_node {
-       enum defer_node_type type;
-
-       /*
-        * This field is only relevant if @type == DNT_CERT.
-        * Do not dereference members otherwise.
-        */
-       struct deferred_cert deferred;
-
-       /* Used by certstack. Points to the next stacked certificate. */
-       SLIST_ENTRY(defer_node) next;
-};
-
-SLIST_HEAD(defer_stack, defer_node);
-
-struct serial_number {
-       BIGNUM *number;
-       char *file; /* File where this serial number was found. */
-};
-
-STATIC_ARRAY_LIST(serial_numbers, struct serial_number)
-
-/* Cached certificate data */
-struct metadata_node {
-       struct cache_mapping map;
-       struct resources *resources;
-       /*
-        * Serial numbers of the children.
-        * This is an unsorted array list for two reasons: Certificates usually
-        * don't have many children, and I'm running out of time.
-        */
-       struct serial_numbers serials;
-
-       /* Used by certstack. Points to the next stacked certificate. */
-       SLIST_ENTRY(metadata_node) next;
-};
-
-/* Certificates that need to be remembered during a validation cycle. */
-struct cert_stack {
-       /*
-        * Defer stack; certificates whose validation has been postponed.
-        * (Postponing certificates avoids us recursion and stack overflow.)
-        */
-       struct defer_stack defers;
-
-       /*
-        * X509 stack. Ancestor certificates of the current certificate.
-        * Formatted for immediate libcrypto consumption.
-        */
-       STACK_OF(X509) *x509s;
-
-       /*
-        * Metadata for each X509. Stuff that doesn't fit in libcrypto's struct.
-        *
-        * (This is a SLIST and not a STACK_OF because the LibreSSL STACK_OF
-        * is seemingly private.)
-        */
-       SLIST_HEAD(, metadata_node) metas;
-};
-
-int
-certstack_create(struct cert_stack **result)
-{
-       struct cert_stack *stack;
-
-       stack = pmalloc(sizeof(struct cert_stack));
-
-       stack->x509s = sk_X509_new_null();
-       if (stack->x509s == NULL) {
-               free(stack);
-               return val_crypto_err("sk_X509_new_null() returned NULL");
-       }
-
-       SLIST_INIT(&stack->defers);
-       SLIST_INIT(&stack->metas);
-
-       *result = stack;
-       return 0;
-}
-
-static void
-defer_pop(struct cert_stack *stack)
-{
-       struct defer_node *defer;
-
-       defer = SLIST_FIRST(&stack->defers);
-       if (defer == NULL)
-               pr_crit("Attempted to pop empty defer stack");
-
-       SLIST_REMOVE_HEAD(&stack->defers, next);
-       if (defer->type == DNT_CERT) {
-               map_cleanup(&defer->deferred.map);
-               rpp_refput(defer->deferred.pp);
-       }
-       free(defer);
-}
-
-static void
-serial_cleanup(struct serial_number *serial)
-{
-       BN_free(serial->number);
-       free(serial->file);
-}
-
-static void
-meta_pop(struct cert_stack *stack)
-{
-       struct metadata_node *meta;
-
-       meta = SLIST_FIRST(&stack->metas);
-       if (meta == NULL)
-               pr_crit("Attempted to pop empty metadata stack");
-
-       SLIST_REMOVE_HEAD(&stack->metas, next);
-       map_cleanup(&meta->map);
-       resources_destroy(meta->resources);
-       serial_numbers_cleanup(&meta->serials, serial_cleanup);
-       free(meta);
-}
-
-void
-certstack_destroy(struct cert_stack *stack)
-{
-       int n;
-
-       for (n = 0; !SLIST_EMPTY(&stack->defers); n++)
-               defer_pop(stack);
-       pr_val_debug("Deleted %d deferred certificates.", n);
-
-       n = sk_X509_num(stack->x509s);
-       sk_X509_pop_free(stack->x509s, X509_free);
-       pr_val_debug("Deleted %d stacked x509s.", n);
-
-       for (n = 0; !SLIST_EMPTY(&stack->metas); n++)
-               meta_pop(stack);
-       pr_val_debug("Deleted %u metadatas.", n);
-
-       free(stack);
-}
-
-void
-deferstack_push(struct cert_stack *stack, struct cache_mapping *map,
-    struct rpp *pp)
-{
-       struct defer_node *node;
-
-       node = pmalloc(sizeof(struct defer_node));
-
-       node->type = DNT_CERT;
-       map_copy(&node->deferred.map, map);
-       node->deferred.pp = pp;
-       rpp_refget(pp);
-       SLIST_INSERT_HEAD(&stack->defers, node, next);
-}
-
-static void
-x509stack_pop(struct cert_stack *stack)
-{
-       X509 *cert;
-
-       cert = sk_X509_pop(stack->x509s);
-       if (cert == NULL)
-               pr_crit("Attempted to pop empty X509 stack");
-       X509_free(cert);
-
-       meta_pop(stack);
-}
-
-/* Contract: Returns either 0 or -ENOENT. No other outcomes. */
-int
-deferstack_pop(struct cert_stack *stack, struct deferred_cert *result)
-{
-       struct defer_node *node;
-
-again: node = SLIST_FIRST(&stack->defers);
-       if (node == NULL)
-               return -ENOENT;
-
-       if (node->type == DNT_SEPARATOR) {
-               x509stack_pop(stack);
-               defer_pop(stack);
-               goto again;
-       }
-
-       *result = node->deferred;
-
-       SLIST_REMOVE_HEAD(&stack->defers, next);
-       free(node);
-       return 0;
-}
-
-static int
-init_resources(X509 *x509, enum rpki_policy policy, enum cert_type type,
-    struct resources **_result)
-{
-       struct resources *result;
-       int error;
-
-       result = resources_create(policy, false);
-
-       error = certificate_get_resources(x509, result, type);
-       if (error)
-               goto fail;
-
-       /*
-        * rfc8630#section-2.3
-        * "The INR extension(s) of this TA MUST contain a non-empty set of
-        * number resources."
-        * The "It MUST NOT use the "inherit" form of the INR extension(s)"
-        * part is already handled in certificate_get_resources().
-        */
-       if (type == CERTYPE_TA && resources_empty(result)) {
-               error = pr_val_err("Trust Anchor certificate does not define any number resources.");
-               goto fail;
-       }
-
-       *_result = result;
-       return 0;
-
-fail:
-       resources_destroy(result);
-       return error;
-}
-
-static struct defer_node *
-create_separator(void)
-{
-       struct defer_node *result;
-
-       result = pmalloc(sizeof(struct defer_node));
-       result->type = DNT_SEPARATOR;
-
-       return result;
-}
-
-/* Steals ownership of @x509 on success. */
-int
-x509stack_push(struct cert_stack *stack, struct cache_mapping const *map,
-    X509 *x509, enum rpki_policy policy, enum cert_type type)
-{
-       struct metadata_node *meta;
-       struct defer_node *defer_separator;
-       int ok;
-       int error;
-
-       meta = pmalloc(sizeof(struct metadata_node));
-
-       map_copy(&meta->map, map);
-       serial_numbers_init(&meta->serials);
-
-       error = init_resources(x509, policy, type, &meta->resources);
-       if (error)
-               goto cleanup_serial;
-
-       defer_separator = create_separator();
-
-       ok = sk_X509_push(stack->x509s, x509);
-       if (ok <= 0) {
-               error = val_crypto_err(
-                   "Could not add certificate to trusted stack: %d", ok);
-               goto destroy_separator;
-       }
-
-       SLIST_INSERT_HEAD(&stack->defers, defer_separator, next);
-       SLIST_INSERT_HEAD(&stack->metas, meta, next);
-
-       return 0;
-
-destroy_separator:
-       free(defer_separator);
-       resources_destroy(meta->resources);
-cleanup_serial:
-       serial_numbers_cleanup(&meta->serials, serial_cleanup);
-       free(meta->map.url);
-       free(meta->map.path);
-       free(meta);
-       return error;
-}
-
-/*
- * This one is intended to revert a recent x509 push.
- * Reverts that particular push.
- *
- * (x509 stack elements are otherwise indirectly popped through
- * deferstack_pop().)
- */
-void
-x509stack_cancel(struct cert_stack *stack)
-{
-       x509stack_pop(stack);
-       defer_pop(stack);
-}
-
-X509 *
-x509stack_peek(struct cert_stack *stack)
-{
-       return sk_X509_value(stack->x509s, sk_X509_num(stack->x509s) - 1);
-}
-
-struct resources *
-x509stack_peek_resources(struct cert_stack *stack)
-{
-       struct metadata_node *meta = SLIST_FIRST(&stack->metas);
-       return (meta != NULL) ? meta->resources : NULL;
-}
-
-static char *
-get_current_file_name(void)
-{
-       char const *file_name;
-
-       file_name = fnstack_peek();
-       if (file_name == NULL)
-               pr_crit("The file name stack is empty.");
-
-       return pstrdup(file_name);
-}
-
-/*
- * Intended to validate serial number uniqueness.
- * "Stores" the serial number in the current relevant certificate metadata,
- * and complains if there's a collision. That's all.
- *
- * This function will steal ownership of @number on success.
- */
-void
-x509stack_store_serial(struct cert_stack *stack, BIGNUM *number)
-{
-       struct metadata_node *meta;
-       struct serial_number *cursor;
-       struct serial_number duplicate;
-       char *string;
-
-       /* Remember to free @number if you return 0 but don't store it. */
-
-       meta = SLIST_FIRST(&stack->metas);
-       if (meta == NULL) {
-               BN_free(number);
-               return; /* The TA lacks siblings, so serial is unique. */
-       }
-
-       /*
-        * Note: This is is reported as a warning, even though duplicate serial
-        * numbers are clearly a violation of the RFC and common sense.
-        *
-        * But it cannot be simply upgraded into an error because we are
-        * realizing the problem too late; our traversal is depth-first, so we
-        * already approved the other bogus certificate and its children.
-        * (I don't think changing to a breath-first traversal would be a good
-        * idea; the RAM usage would skyrocket because, since we need the entire
-        * certificate path to the root to validate any certificate, we would
-        * end up having the entire tree loaded in memory by the time we're done
-        * traversing.)
-        *
-        * So instead of arbitrarily approving one certificate but not the
-        * other, we will accept both but report a warning.
-        *
-        * Also: It's pretty odd; a significant amount of certificates seem to
-        * be breaking this rule. Maybe we're the only ones catching it?
-        *
-        * TODO I haven't seen this warning in a while. Review.
-        */
-       ARRAYLIST_FOREACH(&meta->serials, cursor) {
-               if (BN_cmp(cursor->number, number) == 0) {
-                       BN2string(number, &string);
-                       pr_val_warn("Serial number '%s' is not unique. (Also found in '%s'.)",
-                           string, cursor->file);
-                       BN_free(number);
-                       free(string);
-                       return;
-               }
-       }
-
-       duplicate.number = number;
-       duplicate.file = get_current_file_name();
-
-       serial_numbers_add(&meta->serials, &duplicate);
-}
-
-STACK_OF(X509) *
-certstack_get_x509s(struct cert_stack *stack)
-{
-       return stack->x509s;
-}
-
-int
-certstack_get_x509_num(struct cert_stack *stack)
-{
-       return sk_X509_num(stack->x509s);
-}
diff --git a/src/cert_stack.h b/src/cert_stack.h
deleted file mode 100644 (file)
index 411bac3..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef SRC_CERT_STACK_H_
-#define SRC_CERT_STACK_H_
-
-#include <openssl/bn.h>
-
-#include "object/certificate.h"
-#include "types/name.h"
-
-struct cert_stack;
-
-struct deferred_cert {
-       struct cache_mapping map;
-       struct rpp *pp;
-};
-
-int certstack_create(struct cert_stack **);
-void certstack_destroy(struct cert_stack *);
-
-void deferstack_push(struct cert_stack *, struct cache_mapping *, struct rpp *);
-int deferstack_pop(struct cert_stack *, struct deferred_cert *cert);
-
-int x509stack_push(struct cert_stack *, struct cache_mapping const *,
-    X509 *, enum rpki_policy, enum cert_type);
-void x509stack_cancel(struct cert_stack *);
-X509 *x509stack_peek(struct cert_stack *);
-struct resources *x509stack_peek_resources(struct cert_stack *);
-void x509stack_store_serial(struct cert_stack *, BIGNUM *);
-
-STACK_OF(X509) *certstack_get_x509s(struct cert_stack *);
-int certstack_get_x509_num(struct cert_stack *);
-
-#endif /* SRC_CERT_STACK_H_ */
index a5b2d6426f69f8e23b393452d9f6ded9b3c3e7df..0f3403bfd5729e158af1359e759feadfcc8a142b 100644 (file)
@@ -6,97 +6,53 @@
 
 #include "log.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);
-       if (refs->caIssuers != NULL)
-               free(refs->caIssuers);
-       if (refs->signedObject != NULL)
-               free(refs->signedObject);
-}
-
-static int
-validate_cdp(struct certificate_refs *refs, struct rpp const *pp)
+int
+validate_cdp(struct sia_uris *sias, char const *crl_url)
 {
-       char const *crl_url;
-
-       if (refs->crldp == NULL)
+       if (sias->crldp == NULL)
                pr_crit("Certificate's CRL Distribution Point was not recorded.");
 
-       crl_url = rpp_get_crl_url(pp);
        if (crl_url == NULL)
                pr_crit("Manifest's CRL was not recorded.");
 
-       if (strcmp(refs->crldp, crl_url) != 0) {
+       if (strcmp(sias->crldp, crl_url) != 0) {
                return pr_val_err("Certificate's CRL Distribution Point ('%s') does not match manifest's CRL ('%s').",
-                   refs->crldp, crl_url);
+                   sias->crldp, crl_url);
        }
 
        return 0;
 }
 
 static int
-validate_signedObject(struct certificate_refs *refs, char const *url)
+validate_signedObject(struct sia_uris *sias, char const *url)
 {
-       if (refs->signedObject == NULL)
+       if (sias->signedObject == NULL)
                pr_crit("Certificate's signedObject was not recorded.");
 
        /* XXX the left one is no longer normalized */
-       if (strcmp(refs->signedObject, url) != 0) {
+       if (strcmp(sias->signedObject, url) != 0) {
                return pr_val_err("Certificate's signedObject ('%s') does not match the URI of its own signed object (%s).",
-                   refs->signedObject, url);
+                   sias->signedObject, url);
        }
 
        return 0;
 }
 
-/**
- * Ensures the @refs URIs match the parent Manifest's URIs. Assumes @refs came
- * from a (non-TA) CA certificate.
- *
- * @refs: References you want validated.
- * @pp: Repository Publication Point, as described by the parent Manifest.
- */
-int
-refs_validate_ca(struct certificate_refs *refs, struct rpp const *pp)
-{
-       int error;
-
-       error = validate_cdp(refs, pp);
-       if (error)
-               return error;
-
-       if (refs->signedObject != NULL)
-               pr_crit("CA summary has a signedObject ('%s').",
-                   refs->signedObject);
-
-       return 0;
-}
-
 /**
  * Ensures the @refs URIs match the Manifest URIs. Assumes @refs came from an
  * EE certificate.
  *
  * @refs: References you want validated.
- * @pp: Repository Publication Point, as described by the Manifest.
  * @url: URL of the signed object that contains the EE certificate.
  */
 int
-refs_validate_ee(struct certificate_refs *refs, struct rpp const *pp,
-    char const *url)
+refs_validate_ee(struct sia_uris *sias, char const *crl_url, char const *url)
 {
        int error;
 
-       error = validate_cdp(refs, pp);
+       error = validate_cdp(sias, crl_url);
        if (error)
                return error;
 
-       return validate_signedObject(refs, url);
+       return validate_signedObject(sias, url);
 }
index 841ba94b2e2c96065bd35a0564647a0a70ab9e88..2df0890ba00748c3a0259c1f087ab07f7b95a383 100644 (file)
@@ -1,45 +1,11 @@
 #ifndef SRC_CERTIFICATE_REFS_H_
 #define SRC_CERTIFICATE_REFS_H_
 
-#include "rpp.h"
+/* XXX delete this */
 
-/**
- * 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;
-};
+#include "cache.h"
 
-void refs_init(struct certificate_refs *);
-void refs_cleanup(struct certificate_refs *);
-int refs_validate_ca(struct certificate_refs *, struct rpp const *);
-int refs_validate_ee(struct certificate_refs *, struct rpp const *,
-    char const *);
+int validate_cdp(struct sia_uris *, char const *);
+int refs_validate_ee(struct sia_uris *, char const *, char const *);
 
 #endif /* SRC_CERTIFICATE_REFS_H_ */
index f986673e23432c57e9d679bbc2c02fe4db30759d..6ef81098af0b10bff3fb94744d262e9bfdd2e3eb 100644 (file)
@@ -321,7 +321,7 @@ end:        free(path);
  * If parent's parent is now empty, delete parent's parent.
  * And so on.
  *
- * FIXME this should be done by the cache cleaner instead.
+ * XXX this should be done by the cache cleaner instead.
  */
 int
 delete_dir_recursive_bottom_up(char const *path)
index 9b167215ba26a4844d05ea7fa8228a8fe83fb24e..6b3113be48d2fe19a6d7392de1e3b57cfbab0b57 100644 (file)
@@ -997,24 +997,27 @@ int
 handle_aki(void *ext, void *arg)
 {
        AUTHORITY_KEYID *aki = ext;
-       X509 *parent;
+//     X509 *parent;
 
        if (aki->keyid == NULL) {
-               return pr_val_err("%s extension lacks a keyIdentifier.",
+               return pr_val_err("The %s lacks a keyIdentifier.",
                    ext_aki()->name);
        }
        if (aki->issuer != NULL) {
-               return pr_val_err("%s extension contains an authorityCertIssuer.",
+               return pr_val_err("The %s contains an authorityCertIssuer.",
                    ext_aki()->name);
        }
        if (aki->serial != NULL) {
-               return pr_val_err("%s extension contains an authorityCertSerialNumber.",
+               return pr_val_err("The %s contains an authorityCertSerialNumber.",
                    ext_aki()->name);
        }
 
+       /* XXX
        parent = x509stack_peek(validation_certstack(state_retrieve()));
        if (parent == NULL)
                return pr_val_err("Certificate has no parent.");
 
        return validate_public_key_hash(parent, aki->keyid, "AKI");
+       */
+       return 0;
 }
index 2641fcc388bdfc94631a58c180158e718eb9917b..b9a35b2c870bd00b9021f01942da1848d1b44c9c 100644 (file)
@@ -45,12 +45,6 @@ static struct incidence incidences[__INID_MAX] = {
                "The current time is after the nextUpdate field at the manifest",
                INAC_ERROR,
        },
-       {
-               INID_CRL_STALE,
-               "incid-crl-stale",
-               "The current time is after the nextUpdate field at the CRL",
-               INAC_ERROR,
-       },
 };
 
 static int
index 93e97998b8b7821ba40b3107af225c796befbb1c..f0170aea9374338365d6446aa4d337b229e09b2a 100644 (file)
@@ -13,7 +13,7 @@ enum incidence_id {
        INID_MFT_FILE_NOT_FOUND, // XXX deprecate and no-op
        INID_MFT_FILE_HASH_NOT_MATCH, // XXX deprecate and no-op
        INID_MFT_STALE,
-       INID_CRL_STALE,
+       // XXX Document elimination of INID_CRL_STALE
 
        __INID_MAX,
 };
index 3968af308850f0a0566dc812c6ac231752ef2811..e4bf59238b7f0a1ae4089534b031deafcc9fadfd 100644 (file)
 #include "libcrypto_util.h"
 #include "log.h"
 #include "nid.h"
+#include "object/ghostbusters.h"
 #include "object/manifest.h"
+#include "object/roa.h"
 #include "thread_var.h"
+#include "types/name.h"
 #include "types/path.h"
 #include "types/str.h"
 #include "types/url.h"
@@ -34,6 +37,9 @@
  */
 typedef AUTHORITY_INFO_ACCESS SIGNATURE_INFO_ACCESS;
 
+/* Certificates that need to be postponed during a validation cycle. */
+SLIST_HEAD(cert_stack, rpki_certificate);
+
 struct ski_arguments {
        X509 *cert;
        OCTET_STRING_t *sid;
@@ -89,39 +95,6 @@ static const struct ad_metadata RPKI_MANIFEST = {
        .required = true,
 };
 
-static void
-debug_serial_number(BIGNUM *number)
-{
-       char *number_str;
-
-       number_str = BN_bn2dec(number);
-       if (number_str == NULL) {
-               val_crypto_err("Could not convert BN to string");
-               return;
-       }
-
-       pr_val_debug("serial Number: %s", number_str);
-       free(number_str);
-}
-
-static int
-validate_serial_number(X509 *cert)
-{
-       struct validation *state;
-       BIGNUM *number;
-
-       number = ASN1_INTEGER_to_BN(X509_get0_serialNumber(cert), NULL);
-       if (number == NULL)
-               return val_crypto_err("Could not parse certificate serial number");
-
-       if (log_val_enabled(LOG_DEBUG))
-               debug_serial_number(number);
-
-       state = state_retrieve();
-       x509stack_store_serial(validation_certstack(state), number);
-       return 0;
-}
-
 static int
 validate_signature_algorithm(X509 *cert)
 {
@@ -133,25 +106,23 @@ validate_signature_algorithm(X509 *cert)
 }
 
 static int
-validate_issuer(X509 *cert, bool is_ta)
+validate_issuer(struct rpki_certificate *cert)
 {
        X509_NAME *issuer;
        struct rfc5280_name *name;
        int error;
 
-       issuer = X509_get_issuer_name(cert);
-
-       if (!is_ta)
-               return validate_issuer_name("Certificate", issuer);
+       issuer = X509_get_issuer_name(cert->x509);
 
-       /* TODO wait. Shouldn't we check subject == issuer? */
+       if (cert->type != CERTYPE_TA)
+               return validate_issuer_name(issuer, cert->parent->x509);
 
        error = x509_name_decode(issuer, "issuer", &name);
        if (error)
                return error;
        pr_val_debug("Issuer: %s", x509_name_commonName(name));
-
        x509_name_put(name);
+
        return 0;
 }
 
@@ -160,8 +131,7 @@ validate_issuer(X509 *cert, bool is_ta)
  * @diff_pk_cb when the public key is different; return 0 if both are equal.
  */
 static int
-spki_cmp(X509_PUBKEY *tal_spki, X509_PUBKEY *cert_spki,
-    int (*diff_alg_cb)(void), int (*diff_pk_cb)(void))
+spki_cmp(X509_PUBKEY *tal_spki, X509_PUBKEY *cert_spki)
 {
        ASN1_OBJECT *tal_alg;
        ASN1_OBJECT *cert_alg;
@@ -181,13 +151,18 @@ spki_cmp(X509_PUBKEY *tal_spki, X509_PUBKEY *cert_spki,
                return val_crypto_err("X509_PUBKEY_get0_param() 2 returned %d", ok);
 
        if (OBJ_cmp(tal_alg, cert_alg) != 0)
-               return diff_alg_cb();
+               goto root_different_alg_err;
        if (tal_spk_len != cert_spk_len)
-               return diff_pk_cb();
+               goto root_different_pk_err;
        if (memcmp(tal_spk, cert_spk, cert_spk_len) != 0)
-               return diff_pk_cb();
+               goto root_different_pk_err;
 
        return 0;
+
+root_different_alg_err:
+       return pr_val_err("TAL's public key algorithm is different than the root certificate's public key algorithm.");
+root_different_pk_err:
+       return pr_val_err("TAL's public key is different than the root certificate's public key.");
 }
 
 /*
@@ -239,28 +214,14 @@ fail:     fnstack_pop();
        return NULL;
 }
 
-static int
-root_different_alg_err(void)
-{
-       return pr_val_err("TAL's public key algorithm is different than the root certificate's public key algorithm.");
-}
-
-static int
-root_different_pk_err(void)
-{
-       return pr_val_err("TAL's public key is different than the root certificate's public key.");
-}
-
 static int
 validate_spki(X509_PUBKEY *cert_spki)
 {
-       struct validation *state;
        struct tal *tal;
        X509_PUBKEY *tal_spki;
+       int error;
 
-       state = state_retrieve();
-
-       tal = validation_tal(state);
+       tal = validation_tal(state_retrieve());
        if (tal == NULL)
                pr_crit("Validation state has no TAL.");
 
@@ -286,16 +247,10 @@ validate_spki(X509_PUBKEY *cert_spki)
        if (tal_spki == NULL)
                return -EINVAL;
 
-       if (spki_cmp(tal_spki, cert_spki, root_different_alg_err,
-           root_different_pk_err) != 0) {
-               X509_PUBKEY_free(tal_spki);
-               validation_pubkey_invalid(state);
-               return -EINVAL;
-       }
+       error = spki_cmp(tal_spki, cert_spki);
 
        X509_PUBKEY_free(tal_spki);
-       validation_pubkey_valid(state);
-       return 0;
+       return error;
 }
 
 /*
@@ -491,7 +446,7 @@ validate_public_key(X509 *cert, enum cert_type type)
 }
 
 int
-certificate_validate_rfc6487(X509 *cert, enum cert_type type)
+certificate_validate_rfc6487(struct rpki_certificate *cert)
 {
        int error;
 
@@ -504,21 +459,19 @@ certificate_validate_rfc6487(X509 *cert, enum cert_type type)
         */
 
        /* rfc6487#section-4.1 */
-       if (X509_get_version(cert) != 2)
+       if (X509_get_version(cert->x509) != 2)
                return pr_val_err("Certificate version is not v3.");
 
        /* rfc6487#section-4.2 */
-       error = validate_serial_number(cert);
-       if (error)
-               return error;
+       /* <Redacted> */
 
        /* rfc6487#section-4.3 */
-       error = validate_signature_algorithm(cert);
+       error = validate_signature_algorithm(cert->x509);
        if (error)
                return error;
 
        /* rfc6487#section-4.4 */
-       error = validate_issuer(cert, type == CERTYPE_TA);
+       error = validate_issuer(cert);
        if (error)
                return error;
 
@@ -528,7 +481,7 @@ certificate_validate_rfc6487(X509 *cert, enum cert_type type)
         * "An issuer SHOULD use a different subject name if the subject's
         * key pair has changed" (it's a SHOULD, so [for now] avoid validation)
         */
-       error = validate_subject(cert);
+       error = validate_subject(cert->x509);
        if (error)
                return error;
 
@@ -537,7 +490,7 @@ certificate_validate_rfc6487(X509 *cert, enum cert_type type)
 
        /* rfc6487#section-4.7 */
        /* Fragment of rfc8630#section-2.3 */
-       error = validate_public_key(certtype);
+       error = validate_public_key(cert->x509, cert->type);
        if (error)
                return error;
 
@@ -794,75 +747,93 @@ end:
        return error;
 }
 
-static int
-certificate_load(struct cache_mapping const *map, X509 **result)
+static X509 *
+certificate_load(char const *path)
 {
        X509 *cert = NULL;
        BIO *bio;
-       int error;
-
-       *result = NULL;
 
        bio = BIO_new(BIO_s_file());
-       if (bio == NULL)
-               return val_crypto_err("BIO_new(BIO_s_file()) returned NULL");
-       if (BIO_read_filename(bio, map->path) <= 0) {
-               error = val_crypto_err("Error reading certificate");
+       if (bio == NULL) {
+               val_crypto_err("BIO_new(BIO_s_file()) returned NULL");
+               return NULL;
+       }
+       if (BIO_read_filename(bio, path) <= 0) {
+               val_crypto_err("Error reading certificate");
                goto end;
        }
 
        cert = d2i_X509_bio(bio, NULL);
        if (cert == NULL) {
-               error = val_crypto_err("Error parsing certificate");
+               val_crypto_err("Error parsing certificate");
                goto end;
        }
 
-       *result = cert;
-       error = 0;
-end:
-       BIO_free(bio);
-       return error;
+end:   BIO_free(bio);
+       return cert;
 }
 
-/*
- * Allocates a clone of @original_crl and pushes it to @crls.
- *
- * Don't forget to pop from @crls and release the popped CRL.
- */
-static int
-update_crl_time(STACK_OF(X509_CRL) *crls, X509_CRL *original_crl)
+static void
+certificate_stack_push(struct cert_stack *stack, struct cache_mapping *map,
+    struct rpki_certificate *parent)
 {
-       ASN1_TIME *tm;
-       X509_CRL *clone;
+       struct rpki_certificate *cert;
 
-       /*
-        * Yes, this is an awful hack. The other options were:
-        * - Use X509_V_FLAG_NO_CHECK_TIME parameter, but this avoids also the
-        *   time check for the certificate.
-        * - Avoid whole CRL check, but since we don't implement the
-        *   certificate chain validation, we can't assure that the CRL has
-        *   only the nextUpdate field wrong (maybe there are other invalid
-        *   things).
-        */
-       tm = ASN1_TIME_adj(NULL, time_fatal(), 0, 60);
-       if (tm == NULL)
-               return val_crypto_err("ASN1_TIME_adj() returned NULL.");
-
-       clone = X509_CRL_dup(original_crl);
-       if (clone == NULL) {
-               ASN1_STRING_free(tm);
-               return val_crypto_err("X509_CRL_dup() returned NULL.");
-       }
+       cert = pzalloc(sizeof(*cert));
+       cert->refcount++;
 
-       X509_CRL_set1_nextUpdate(clone, tm);
-       ASN1_STRING_free(tm);
+       map_copy(&cert->map, map);
 
-       if (sk_X509_CRL_push(crls, clone) <= 0) {
-               X509_CRL_free(clone);
-               return val_crypto_err("Error calling sk_X509_CRL_push()");
-       }
+       cert->parent = parent;
+       parent->refcount++;
 
-       return 0;
+       cert->rpp.ancestors = X509_chain_up_ref(parent->rpp.ancestors);
+       if (!cert->rpp.ancestors)
+               goto fail;
+       if (sk_X509_push(cert->rpp.ancestors, parent->x509) <= 0)
+               goto fail;
+       if (!X509_up_ref(parent->x509))
+               goto fail;
+
+       SLIST_INSERT_HEAD(stack, cert, lh);
+       return;
+
+fail:  rpki_certificate_free(cert);
+}
+
+void
+rpki_certificate_init_ee(struct rpki_certificate *ee,
+    struct rpki_certificate *parent, bool force_inherit)
+{
+       memset(ee, 0, sizeof(*ee));
+       ee->type = CERTYPE_EE;
+       ee->policy = RPKI_POLICY_RFC6484;
+       ee->resources = resources_create(RPKI_POLICY_RFC6484, force_inherit);
+       ee->parent = parent;
+       ee->refcount = 1;
+}
+
+void
+rpki_certificate_cleanup(struct rpki_certificate *cert)
+{
+       map_cleanup(&cert->map);
+       if (cert->x509 != NULL)
+               X509_free(cert->x509);
+       resources_destroy(cert->resources);
+       sias_cleanup(&cert->sias);
+       // XXX Recursive. Try refcounting the resources.
+       rpki_certificate_free(cert->parent);
+       rpp_cleanup(&cert->rpp);
+}
+
+void
+rpki_certificate_free(struct rpki_certificate *cert)
+{
+       cert->refcount--;
+       if (cert->refcount == 0) {
+               rpki_certificate_cleanup(cert);
+               free(cert);
+       }
 }
 
 static void
@@ -879,112 +850,34 @@ pr_debug_x509_dates(X509 *x509)
        free(na);
 }
 
-/*
- * Retry certificate validation without CRL time validation.
- */
-static int
-verify_cert_crl_stale(struct validation *state, X509 *cert,
-    STACK_OF(X509_CRL) *crls)
-{
-       X509_STORE_CTX *ctx;
-       X509_CRL *original_crl, *clone;
-       int error;
-       int ok;
-
-       ctx = X509_STORE_CTX_new();
-       if (ctx == NULL) {
-               val_crypto_err("X509_STORE_CTX_new() returned NULL");
-               return -EINVAL;
-       }
-
-       /* Returns 0 or 1 , all callers test ! only. */
-       ok = X509_STORE_CTX_init(ctx, validation_store(state), cert, NULL);
-       if (!ok) {
-               error = val_crypto_err("X509_STORE_CTX_init() returned %d", ok);
-               goto release_ctx;
-       }
-
-       original_crl = sk_X509_CRL_pop(crls);
-       error = update_crl_time(crls, original_crl);
-       if (error)
-               goto push_original;
-
-       X509_STORE_CTX_trusted_stack(ctx,
-           certstack_get_x509s(validation_certstack(state)));
-       X509_STORE_CTX_set0_crls(ctx, crls);
-
-       ok = X509_verify_cert(ctx);
-       if (ok > 0) {
-               error = 0; /* Happy path */
-               goto pop_clone;
-       }
-
-       error = X509_STORE_CTX_get_error(ctx);
-       if (error)
-               error = pr_val_err("Certificate validation failed: %s",
-                   X509_verify_cert_error_string(error));
-       else
-               error = val_crypto_err("Certificate validation failed: %d", ok);
-
-       if (error && log_val_enabled(LOG_DEBUG))
-               pr_debug_x509_dates(cert);
-
-pop_clone:
-       clone = sk_X509_CRL_pop(crls);
-       if (clone == NULL)
-               error = pr_val_err("Error calling sk_X509_CRL_pop()");
-       else
-               X509_CRL_free(clone);
-push_original:
-       /* Try to return to the "regular" CRL chain */
-       ok = sk_X509_CRL_push(crls, original_crl);
-       if (ok <= 0)
-               error = val_crypto_err("Could not return CRL to a CRL stack");
-release_ctx:
-       X509_STORE_CTX_free(ctx);
-       return error;
-
-}
-
-static int
-complain_crl_stale(STACK_OF(X509_CRL) *crls)
+static void
+complain_crl_stale(X509_CRL *crl)
 {
-       X509_CRL *crl;
        char *lu;
        char *nu;
-       int ret;
-
-       if (sk_X509_CRL_num(crls) < 1)
-               pr_crit("Empty CRL stack despite validations.");
-       crl = sk_X509_CRL_value(crls, 0);
-       if (crl == NULL)
-               pr_crit("Unable to pop CRL from nonempty stack.");
 
        lu = asn1time2str(X509_CRL_get0_lastUpdate(crl));
        nu = asn1time2str(X509_CRL_get0_nextUpdate(crl));
 
-       ret = incidence(INID_CRL_STALE,
-           "CRL is stale/expired. (lastUpdate:%s, nextUpdate:%s)", lu, nu);
+       pr_val_err("CRL is stale/expired. (lastUpdate:%s, nextUpdate:%s)",
+           lu, nu);
 
        free(lu);
        free(nu);
-       return ret;
 }
 
 int
-certificate_validate_chain(X509 *cert, STACK_OF(X509_CRL) *crls)
+certificate_validate_chain(struct rpki_certificate *cert)
 {
        /* Reference: openbsd/src/usr.bin/openssl/verify.c */
 
-       struct validation *state;
        X509_STORE_CTX *ctx;
+       STACK_OF(X509_CRL) *crls;
        int ok;
        int error;
 
-       if (crls == NULL)
-               return 0; /* Certificate is TA; no chain validation needed. */
-
-       state = state_retrieve();
+       if (cert->type == CERTYPE_TA)
+               return 0; /* No chain to validate. */
 
        ctx = X509_STORE_CTX_new();
        if (ctx == NULL) {
@@ -993,15 +886,28 @@ certificate_validate_chain(X509 *cert, STACK_OF(X509_CRL) *crls)
        }
 
        /* Returns 0 or 1 , all callers test ! only. */
-       ok = X509_STORE_CTX_init(ctx, validation_store(state), cert, NULL);
+       ok = X509_STORE_CTX_init(ctx, validation_store(state_retrieve()),
+           cert->x509, NULL);
        if (!ok) {
                val_crypto_err("X509_STORE_CTX_init() returned %d", ok);
                goto abort;
        }
 
-       X509_STORE_CTX_trusted_stack(ctx,
-           certstack_get_x509s(validation_certstack(state)));
-       X509_STORE_CTX_set0_crls(ctx, crls);
+       X509_STORE_CTX_trusted_stack(ctx, cert->rpp.ancestors);
+
+       crls = sk_X509_CRL_new_null();
+       if (!crls)
+               enomem_panic();
+       if (sk_X509_CRL_push(crls, cert->rpp.crl.obj) != 1) {
+               // XXX
+       }
+       // XXX These CRLs will only be used if CRL verification is enabled in
+       // the associated X509_VERIFY_PARAM structure.
+       X509_STORE_CTX_set0_crls(ctx, crls); // XXX needs free
+       // sk_X509_CRL_pop_free(cert->crl.stack, X509_CRL_free);
+
+       if (log_val_enabled(LOG_DEBUG))
+               pr_debug_x509_dates(cert->x509);
 
        /*
         * HERE'S THE MEAT OF LIBCRYPTO'S VALIDATION.
@@ -1019,28 +925,18 @@ certificate_validate_chain(X509 *cert, STACK_OF(X509_CRL) *crls)
                 * error code is stored in the context.
                 */
                error = X509_STORE_CTX_get_error(ctx);
-               if (error) {
-                       if (error != X509_V_ERR_CRL_HAS_EXPIRED) {
-                               pr_val_err("Certificate validation failed: %s",
-                                   X509_verify_cert_error_string(error));
-                               goto abort;
-                       }
-
-                       if (complain_crl_stale(crls))
-                               goto abort;
-                       X509_STORE_CTX_free(ctx);
-                       if (incidence_get_action(INID_CRL_STALE) == INAC_WARN)
-                               pr_val_info("Re-validating avoiding CRL time check");
-                       return verify_cert_crl_stale(state, cert, crls);
-               } else {
+               if (error == X509_V_ERR_CRL_HAS_EXPIRED)
+                       complain_crl_stale(cert->rpp.crl.obj);
+               else if (error)
+                       pr_val_err("Certificate validation failed: %s",
+                           X509_verify_cert_error_string(error));
+               else
                        /*
                         * ...But don't trust X509_STORE_CTX_get_error() either.
                         * That said, there's not much to do about !error,
                         * so hope for the best.
                         */
                        val_crypto_err("Certificate validation failed: %d", ok);
-               }
-
                goto abort;
        }
 
@@ -1053,7 +949,7 @@ abort:
 }
 
 static int
-handle_ip_extension(X509_EXTENSION *ext, struct resources *resources)
+handle_ip_extension(struct rpki_certificate *cert, X509_EXTENSION *ext)
 {
        ASN1_OCTET_STRING *string;
        struct IPAddrBlocks *blocks;
@@ -1094,7 +990,9 @@ handle_ip_extension(X509_EXTENSION *ext, struct resources *resources)
        }
 
        for (i = 0; i < blocks->list.count && !error; i++)
-               error = resources_add_ip(resources, blocks->list.array[i]);
+               error = resources_add_ip(cert->resources,
+                   cert->parent->resources,
+                   blocks->list.array[i]);
 
 end:
        ASN_STRUCT_FREE(asn_DEF_IPAddrBlocks, blocks);
@@ -1102,8 +1000,7 @@ end:
 }
 
 static int
-handle_asn_extension(X509_EXTENSION *ext, struct resources *resources,
-    bool allow_inherit)
+handle_asn_extension(struct rpki_certificate *cert, X509_EXTENSION *ext)
 {
        ASN1_OCTET_STRING *string;
        struct ASIdentifiers *ids;
@@ -1115,16 +1012,17 @@ handle_asn_extension(X509_EXTENSION *ext, struct resources *resources,
        if (error)
                return error;
 
-       error = resources_add_asn(resources, ids, allow_inherit);
+       error = resources_add_asn(cert->resources, cert->parent->resources,
+           ids, cert->type != CERTYPE_BGPSEC);
 
        ASN_STRUCT_FREE(asn_DEF_ASIdentifiers, ids);
        return error;
 }
 
 static int
-__certificate_get_resources(X509 *cert, struct resources *resources,
+__certificate_get_resources(struct rpki_certificate *cert,
     int addr_nid, int asn_nid, int bad_addr_nid, int bad_asn_nid,
-    char const *policy_rfc, char const *bad_ext_rfc, bool allow_asn_inherit)
+    char const *policy_rfc, char const *bad_ext_rfc)
 {
        X509_EXTENSION *ext;
        int nid;
@@ -1136,8 +1034,8 @@ __certificate_get_resources(X509 *cert, struct resources *resources,
        /* Reference: X509_get_ext_d2i */
        /* rfc6487#section-2 */
 
-       for (i = 0; i < X509_get_ext_count(cert); i++) {
-               ext = X509_get_ext(cert, i);
+       for (i = 0; i < X509_get_ext_count(cert->x509); i++) {
+               ext = X509_get_ext(cert->x509, i);
                nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
 
                if (nid == addr_nid) {
@@ -1148,7 +1046,7 @@ __certificate_get_resources(X509 *cert, struct resources *resources,
 
                        ip_ext_found = true;
 
-                       error = handle_ip_extension(ext, resources);
+                       error = handle_ip_extension(cert, ext);
                        if (error)
                                return error;
 
@@ -1160,8 +1058,7 @@ __certificate_get_resources(X509 *cert, struct resources *resources,
 
                        asn_ext_found = true;
 
-                       error = handle_asn_extension(ext, resources,
-                           allow_asn_inherit);
+                       error = handle_asn_extension(cert, ext);
                        if (error)
                                return error;
 
@@ -1182,26 +1079,22 @@ __certificate_get_resources(X509 *cert, struct resources *resources,
 
 /* Copies the resources from @cert to @resources. */
 int
-certificate_get_resources(X509 *cert, struct resources *resources,
-    enum cert_type type)
+certificate_get_resources(struct rpki_certificate *cert)
 {
-       enum rpki_policy policy;
-
-       policy = resources_get_policy(resources);
-       switch (policy) {
+       switch (cert->policy) {
        case RPKI_POLICY_RFC6484:
-               return __certificate_get_resources(cert, resources,
+               return __certificate_get_resources(cert,
                    NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
                    nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
-                   "6484", "8360", type != CERTYPE_BGPSEC);
+                   "6484", "8360");
        case RPKI_POLICY_RFC8360:
-               return __certificate_get_resources(cert, resources,
+               return __certificate_get_resources(cert,
                    nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
                    NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
-                   "8360", "6484", type != CERTYPE_BGPSEC);
+                   "8360", "6484");
        }
 
-       pr_crit("Unknown policy: %u", policy);
+       pr_crit("Unknown policy: %u", cert->policy);
 }
 
 static bool
@@ -1263,10 +1156,9 @@ handle_rpkiNotify(char *uri, void *arg)
 static void
 handle_signedObject(char *uri, void *arg)
 {
-       struct certificate_refs *refs = arg;
+       struct sia_uris *sias = arg;
        pr_val_debug("signedObject: %s", uri);
-       // XXX Maybe it's time to review this API.
-       refs->signedObject = uri;
+       sias->signedObject = uri;
 }
 
 static int
@@ -1390,7 +1282,7 @@ static int
 handle_cdp(void *ext, void *arg)
 {
        STACK_OF(DIST_POINT) *crldp = ext;
-       struct certificate_refs *refs = arg;
+       struct sia_uris *sias = arg;
        DIST_POINT *dp;
        GENERAL_NAMES *names;
        GENERAL_NAME *name;
@@ -1451,7 +1343,7 @@ handle_cdp(void *ext, void *arg)
                         * So we will store the URI in @refs, and validate it
                         * later.
                         */
-                       return ia5s2string(str, &refs->crldp);
+                       return ia5s2string(str, &sias->crldp);
                }
        }
 
@@ -1586,13 +1478,15 @@ handle_ad(int nid, struct ad_metadata const *meta, SIGNATURE_INFO_ACCESS *ia,
 static void
 handle_caIssuers(char *uri, void *arg)
 {
-       struct certificate_refs *refs = arg;
+       struct sia_uris *sias = arg;
        /*
         * Bringing the parent certificate's URI all the way
         * over here is too much trouble, so do the handle_cdp()
         * hack.
+        *
+        * XXX Uh... it's extremely easy now.
         */
-       refs->caIssuers = uri;
+       sias->caIssuers = uri;
 }
 
 static int
@@ -1683,26 +1577,25 @@ handle_cp(void *ext, void *arg)
 
 /* Validates the certificate extensions, Trust Anchor style. */
 static int
-certificate_validate_extensions_ta(X509 *cert, struct sia_uris *sia_uris,
-    enum rpki_policy *policy)
+validate_ta_extensions(struct rpki_certificate *cert)
 {
        struct extension_handler handlers[] = {
-          /* ext        reqd   handler        arg       */
-           { ext_bc(),  true,  handle_bc,               },
-           { ext_ski(), true,  handle_ski_ca, cert      },
-           { ext_aki(), false, handle_aki_ta, cert      },
-           { ext_ku(),  true,  handle_ku_ca,            },
-           { ext_sia(), true,  handle_sia_ca, sia_uris  },
-           { ext_cp(),  true,  handle_cp,     policy    },
+          /* ext        reqd   handler        arg           */
+           { ext_bc(),  true,  handle_bc,                    },
+           { ext_ski(), true,  handle_ski_ca, cert->x509     },
+           { ext_aki(), false, handle_aki_ta, cert->x509     },
+           { ext_ku(),  true,  handle_ku_ca,                 },
+           { ext_sia(), true,  handle_sia_ca, &cert->sias    },
+           { ext_cp(),  true,  handle_cp,     &cert->policy  },
            /* These are handled by certificate_get_resources(). */
-           { ext_ir(),  false,                          },
-           { ext_ar(),  false,                          },
-           { ext_ir2(), false,                          },
-           { ext_ar2(), false,                          },
+           { ext_ir(),  false,                               },
+           { ext_ar(),  false,                               },
+           { ext_ir2(), false,                               },
+           { ext_ar2(), false,                               },
            { NULL },
        };
 
-       return handle_extensions(handlers, X509_get0_extensions(cert));
+       return handle_extensions(handlers, X509_get0_extensions(cert->x509));
 }
 
 /*
@@ -1713,71 +1606,65 @@ certificate_validate_extensions_ta(X509 *cert, struct sia_uris *sia_uris,
  * extensions.
  */
 static int
-certificate_validate_extensions_ca(X509 *cert, struct sia_uris *sia_uris,
-    enum rpki_policy *policy, struct rpp *rpp_parent)
+validate_ca_extensions(struct rpki_certificate *cert)
 {
-       struct certificate_refs refs = { 0 };
        struct extension_handler handlers[] = {
-          /* ext        reqd   handler        arg       */
-           { ext_bc(),  true,  handle_bc,               },
-           { ext_ski(), true,  handle_ski_ca, cert      },
-           { ext_aki(), true,  handle_aki,              },
-           { ext_ku(),  true,  handle_ku_ca,            },
-           { ext_cdp(), true,  handle_cdp,    &refs     },
-           { ext_aia(), true,  handle_aia,    &refs     },
-           { ext_sia(), true,  handle_sia_ca, sia_uris  },
-           { ext_cp(),  true,  handle_cp,     policy    },
-           { ext_ir(),  false,                          },
-           { ext_ar(),  false,                          },
-           { ext_ir2(), false,                          },
-           { ext_ar2(), false,                          },
+          /* ext        reqd   handler        arg           */
+           { ext_bc(),  true,  handle_bc,                    },
+           { ext_ski(), true,  handle_ski_ca, cert->x509     },
+           { ext_aki(), true,  handle_aki,                   },
+           { ext_ku(),  true,  handle_ku_ca,                 },
+           { ext_cdp(), true,  handle_cdp,    &cert->sias    },
+           { ext_aia(), true,  handle_aia,    &cert->sias    },
+           { ext_sia(), true,  handle_sia_ca, &cert->sias    },
+           { ext_cp(),  true,  handle_cp,     &cert->policy  },
+           /* These are handled by certificate_get_resources(). */
+           { ext_ir(),  false,                               },
+           { ext_ar(),  false,                               },
+           { ext_ir2(), false,                               },
+           { ext_ar2(), false,                               },
            { NULL },
        };
        int error;
 
-       error = handle_extensions(handlers, X509_get0_extensions(cert));
+       error = handle_extensions(handlers, X509_get0_extensions(cert->x509));
        if (error)
-               goto end;
-       error = certificate_validate_aia(refs.caIssuers, cert);
+               return error;
+       error = certificate_validate_aia(cert);
        if (error)
-               goto end;
-       error = refs_validate_ca(&refs, rpp_parent);
-
-end:
-       refs_cleanup(&refs);
-       return error;
+               return error;
+       return validate_cdp(&cert->sias, cert->rpp.crl.map->url);
 }
 
 int
-certificate_validate_extensions_ee(X509 *cert, OCTET_STRING_t *sid,
-    struct certificate_refs *refs, enum rpki_policy *policy)
+certificate_validate_extensions_ee(struct rpki_certificate *cert,
+    OCTET_STRING_t *sid)
 {
        struct ski_arguments ski_args;
        struct extension_handler handlers[] = {
-          /* ext        reqd   handler        arg       */
-           { ext_ski(), true,  handle_ski_ee, &ski_args },
-           { ext_aki(), true,  handle_aki,              },
-           { ext_ku(),  true,  handle_ku_ee,            },
-           { ext_cdp(), true,  handle_cdp,    refs      },
-           { ext_aia(), true,  handle_aia,    refs      },
-           { ext_sia(), true,  handle_sia_ee, refs      },
-           { ext_cp(),  true,  handle_cp,     policy    },
-           { ext_ir(),  false,                          },
-           { ext_ar(),  false,                          },
-           { ext_ir2(), false,                          },
-           { ext_ar2(), false,                          },
+          /* ext        reqd   handler        arg           */
+           { ext_ski(), true,  handle_ski_ee, &ski_args      },
+           { ext_aki(), true,  handle_aki,                   },
+           { ext_ku(),  true,  handle_ku_ee,                 },
+           { ext_cdp(), true,  handle_cdp,    &cert->sias    },
+           { ext_aia(), true,  handle_aia,    &cert->sias    },
+           { ext_sia(), true,  handle_sia_ee, &cert->sias    },
+           { ext_cp(),  true,  handle_cp,     &cert->policy  },
+           { ext_ir(),  false,                               },
+           { ext_ar(),  false,                               },
+           { ext_ir2(), false,                               },
+           { ext_ar2(), false,                               },
            { NULL },
        };
 
-       ski_args.cert = cert;
+       ski_args.cert = cert->x509;
        ski_args.sid = sid;
 
-       return handle_extensions(handlers, X509_get0_extensions(cert));
+       return handle_extensions(handlers, X509_get0_extensions(cert->x509));
 }
 
 int
-certificate_validate_extensions_bgpsec(X509 *cert, unsigned char **ski,
-    enum rpki_policy *policy, struct rpp *pp)
+certificate_validate_extensions_bgpsec(void)
 {
        return 0; /* TODO (#58) */
 }
@@ -1810,34 +1697,26 @@ has_bgpsec_router_eku(X509 *cert)
  * Assumption: Meant to be used exclusively in the context of parsing a .cer
  * certificate.
  */
-static int
-get_certificate_type(X509 *cert, bool is_ta, enum cert_type *result)
+static enum cert_type
+get_certificate_type(struct rpki_certificate *cert)
 {
-       if (is_ta) {
-               *result = CERTYPE_TA;
-               return 0;
-       }
+       if (cert->rpp.ancestors == NULL)
+               return CERTYPE_TA;
 
-       if (X509_check_purpose(cert, -1, -1) <= 0)
-               goto err;
+       if (X509_check_purpose(cert->x509, -1, -1) <= 0)
+               return CERTYPE_UNKNOWN;
 
-       if (X509_check_ca(cert) == 1) {
-               *result = CERTYPE_CA;
-               return 0;
-       }
+       if (X509_check_ca(cert->x509) == 1)
+               return CERTYPE_CA;
 
-       if (has_bgpsec_router_eku(cert)) {
-               *result = CERTYPE_BGPSEC;
-               return 0;
-       }
+       if (has_bgpsec_router_eku(cert->x509))
+               return CERTYPE_BGPSEC;
 
-err:
-       *result = CERTYPE_EE; /* Shuts up nonsense gcc 8.3 warning */
-       return pr_val_err("Certificate is not TA, CA nor BGPsec. Ignoring...");
+       return CERTYPE_UNKNOWN;
 }
 
 int
-certificate_validate_aia(char const *caIssuers, X509 *cert)
+certificate_validate_aia(struct rpki_certificate *cert)
 {
        /*
         * FIXME Compare the AIA to the parent's URI.
@@ -1848,62 +1727,49 @@ certificate_validate_aia(char const *caIssuers, X509 *cert)
 }
 
 static int
-check_rpp(struct cache_mapping const *map_rpp, char *rpkiManifest)
+init_resources(struct rpki_certificate *cert)
 {
-       struct cache_mapping mft;
-       struct rpp *pp;
        int error;
 
-       mft.url = rpkiManifest;
-       mft.path = join_paths(map_rpp->path, mft.url + RPKI_SCHEMA_LEN);
+       cert->resources = resources_create(cert->policy, false);
 
-       error = handle_manifest(&mft, &pp);
+       error = certificate_get_resources(cert);
        if (error)
-               goto end;
+               return error;
 
-       rpp_traverse(pp);
-       rpp_refput(pp);
+       /*
+        * rfc8630#section-2.3
+        * "The INR extension(s) of this TA MUST contain a non-empty set of
+        * number resources."
+        * The "It MUST NOT use the "inherit" form of the INR extension(s)"
+        * part is already handled in certificate_get_resources().
+        */
+       if (cert->type == CERTYPE_TA && resources_empty(cert->resources))
+               return pr_val_err("Trust Anchor certificate does not define any number resources.");
 
-end:   free(mft.path);
-       return error;
+       return 0;
 }
 
-/* Boilerplate code for CA certificate validation and recursive traversal. */
-int
-certificate_traverse(struct rpp *rpp_parent,
-    struct cache_mapping const *cert_map)
+static int
+certificate_validate(struct rpki_certificate *cert)
 {
-       struct validation *state;
-       int total_parents;
-       X509 *x509;
-       struct sia_uris sias;
-       enum rpki_policy policy;
-       enum cert_type certype;
-       struct cache_mapping rpp;
        int error;
 
-       state = state_retrieve();
-
-       total_parents = certstack_get_x509_num(validation_certstack(state));
-       if (total_parents >= config_get_max_cert_depth())
+       if (sk_X509_num(cert->rpp.ancestors) >= config_get_max_cert_depth())
                return pr_val_err("Certificate chain maximum depth exceeded.");
 
-       fnstack_push_map(cert_map);
+       fnstack_push_map(&cert->map);
 
-       /* -- Validate the certificate (@cert) -- */
-       error = certificate_load(cert_map, &x509);
-       if (error)
-               goto revert_fnstack_and_debug;
-       error = certificate_validate_chain(x509, rpp_crl(rpp_parent));
-       if (error)
-               goto revert_cert;
+       cert->x509 = certificate_load(cert->map.path);
+       if (!cert->x509)
+               return -EINVAL;
+       cert->type = get_certificate_type(cert);
 
-       error = get_certificate_type(x509, rpp_parent == NULL, &certype);
+       error = certificate_validate_chain(cert);
        if (error)
-               goto revert_cert;
+               goto end;
 
-       /* Debug cert type */
-       switch (certype) {
+       switch (cert->type) {
        case CERTYPE_TA:
                break;
        case CERTYPE_CA:
@@ -1913,46 +1779,112 @@ certificate_traverse(struct rpp *rpp_parent,
                pr_val_debug("Type: BGPsec EE. Ignoring...");
 //             error = handle_bgpsec(cert, x509stack_peek_resources(
 //                 validation_certstack(state)), rpp_parent);
-               goto revert_cert;
+               goto end;
        default:
                pr_val_debug("Type: Unknown. Ignoring...");
-               goto revert_cert;
+               goto end;
        }
 
-       error = certificate_validate_rfc6487(x509, certype);
+       error = certificate_validate_rfc6487(cert);
        if (error)
-               goto revert_cert;
+               goto end;
 
-       sias_init(&sias);
-       error = (certype == CERTYPE_TA)
-           ? certificate_validate_extensions_ta(x509, &sias, &policy)
-           : certificate_validate_extensions_ca(x509, &sias, &policy,
-                                                rpp_parent);
+       error = (cert->type == CERTYPE_TA)
+           ? validate_ta_extensions(cert)
+           : validate_ca_extensions(cert);
        if (error)
-               goto revert_sias;
+               goto end;
 
-       error = x509stack_push(validation_certstack(state), cert_map, x509,
-           policy, certype);
+       error = init_resources(cert);
+
+end:   fnstack_pop();
+       return error;
+}
+
+static int
+certificate_traverse(struct rpki_certificate *ca, struct cert_stack *stack)
+{
+       struct cache_cage *cage;
+       char const *mft;
+       array_index i;
+       struct cache_mapping *map;
+       char const *ext;
+       int error;
+
+       error = certificate_validate(ca);
        if (error)
-               goto revert_sias;
-       x509 = NULL; /* Ownership stolen */
+               return error;
+
+       if (ca->type != CERTYPE_TA && ca->type != CERTYPE_CA)
+               return 0;
+
+       cage = cache_refresh_sias(&ca->sias);
+       if (!cage)
+               return pr_val_err("caRepository '%s' could not be refreshed, "
+                   "and there is no fallback in the cache. "
+                   "I'm going to have to skip it.", ca->sias.caRepository);
+
+retry: mft = cage_map_file(cage, ca->sias.rpkiManifest);
+       if (!mft) {
+               if (cage_disable_refresh(cage))
+                       goto retry;
+               error = pr_val_err("caRepository '%s' is missing a manifest.",
+                   ca->sias.caRepository);
+               goto end;
+       }
 
-       error = cache_refresh_sias(&sias, &rpp);
+       error = manifest_validate(ca->sias.rpkiManifest, mft, cage, ca);
        if (error) {
-               x509stack_cancel(validation_certstack(state));
-               goto revert_sias;
+               if (cage_disable_refresh(cage))
+                       goto retry;
+               goto end;
        }
 
-       error = check_rpp(&rpp, sias.rpkiManifest);
-       if (error)
-               x509stack_cancel(validation_certstack(state));
-
-revert_sias:
-       sias_cleanup(&sias);
-revert_cert:
-       if (x509 != NULL)
-               X509_free(x509);
-revert_fnstack_and_debug:
-       fnstack_pop();
+       for (i = 0; i < ca->rpp.nfiles; i++) {
+               map = ca->rpp.files + i;
+               ext = map->url + strlen(map->url) - 4;
+               if (strcmp(ext, ".cer") == 0)
+                       certificate_stack_push(stack, map, ca);
+               else if (strcmp(ext, ".roa") == 0)
+                       roa_traverse(map, ca);
+               else if (strcmp(ext, ".gbr") == 0)
+                       ghostbusters_traverse(map, ca);
+       }
+
+end:   free(cage);
        return error;
 }
+
+int
+traverse_tree(struct cache_mapping const *ta_map, struct validation *state)
+{
+       struct cert_stack stack;
+       struct rpki_certificate ta = { .map = *ta_map };
+       struct rpki_certificate *ca;
+       int error;
+
+       SLIST_INIT(&stack);
+
+       /* == Root certificate == */
+       error = certificate_traverse(&ta, &stack); // XXX clean up TA
+       if (error)
+               return error;
+
+       /*
+        * From now on, the tree should be considered valid, even if subsequent
+        * certificates fail.
+        * (the root validated successfully; subtrees are isolated problems.)
+        */
+
+       /* == Every other certificate == */
+       while (!SLIST_EMPTY(&stack)) {
+               ca = SLIST_FIRST(&stack);
+               SLIST_REMOVE_HEAD(&stack, lh);
+
+               certificate_traverse(ca, &stack);
+
+               rpki_certificate_free(ca);
+       }
+
+       return 0;
+}
index 5e9aa6f6cd2457c91de202fceb0850bf00deb125..18c0ab083d5d91c79a426de1c7a4b79476278348 100644 (file)
@@ -1,10 +1,16 @@
 #ifndef SRC_OBJECT_CERTIFICATE_H_
 #define SRC_OBJECT_CERTIFICATE_H_
 
+#include <openssl/x509.h>
+#include <sys/queue.h>
+
 #include "asn1/asn1c/ANY.h"
 #include "asn1/asn1c/SignatureValue.h"
+#include "cache.h"
 #include "certificate_refs.h"
 #include "resource.h"
+#include "rpp.h"
+#include "state.h"
 
 /* Certificate types in the RPKI */
 enum cert_type {
@@ -12,23 +18,45 @@ enum cert_type {
        CERTYPE_CA,             /* Certificate Authority */
        CERTYPE_BGPSEC,         /* BGPsec certificates */
        CERTYPE_EE,             /* End Entity certificates */
+       CERTYPE_UNKNOWN,
 };
 
+struct rpki_certificate {
+       struct cache_mapping map;               /* Nonexistent on EEs */
+       X509 *x509;                             /* Initializes after dequeue */
+
+       enum cert_type type;
+       enum rpki_policy policy;                /* XXX seems redundant */
+       struct resources *resources;
+       struct sia_uris sias;
+
+       struct rpki_certificate *parent;
+       struct rpp rpp;                         /* Nonexistent on EEs */
+
+       SLIST_ENTRY(rpki_certificate) lh;       /* List Hook */
+       unsigned int refcount;
+};
+
+void rpki_certificate_init_ee(struct rpki_certificate *,
+    struct rpki_certificate *, bool);
+void rpki_certificate_cleanup(struct rpki_certificate *);
+void rpki_certificate_free(struct rpki_certificate *);
+
 /**
  * Performs the basic (RFC 5280, presumably) chain validation.
  * (Ignores the IP and AS extensions.)
  */
-int certificate_validate_chain(X509 *, STACK_OF(X509_CRL) *);
+int certificate_validate_chain(struct rpki_certificate *);
 /**
  * Validates RFC 6487 compliance.
  * (Except extensions.)
  */
-int certificate_validate_rfc6487(X509 *, enum cert_type);
+int certificate_validate_rfc6487(struct rpki_certificate *);
 
 int certificate_validate_signature(X509 *, ANY_t *coded, SignatureValue_t *);
 
 /**
- * Returns the IP and AS resources declared in the respective extensions.
+ * Extracts the resources from cert->x509 into cert->resources.
  *
  * Note: One reason why this is separate from the validate_extensions functions
  * is because it needs to be handled after the policy has been extracted from
@@ -36,7 +64,7 @@ int certificate_validate_signature(X509 *, ANY_t *coded, SignatureValue_t *);
  * not care about order. I don't know if you'll find other reasons if you choose
  * to migrate it.
  */
-int certificate_get_resources(X509 *, struct resources *, enum cert_type);
+int certificate_get_resources(struct rpki_certificate *cert);
 
 /**
  * Validates the certificate extensions, End-Entity style.
@@ -44,17 +72,16 @@ int certificate_get_resources(X509 *, struct resources *, enum cert_type);
  * Also initializes the second argument with the references found in the
  * extensions.
  */
-int certificate_validate_extensions_ee(X509 *, OCTET_STRING_t *,
-    struct certificate_refs *, enum rpki_policy *);
-int certificate_validate_extensions_bgpsec(X509 *, unsigned char **,
-    enum rpki_policy *, struct rpp *);
+int certificate_validate_extensions_ee(struct rpki_certificate *,
+    OCTET_STRING_t *);
+int certificate_validate_extensions_bgpsec(void);
 
 /*
  * Specific validation of AIA (rfc6487#section-4.8.7) extension, public so that
  * CAs and EEs can access it.
  */
-int certificate_validate_aia(char const *, X509 *);
+int certificate_validate_aia(struct rpki_certificate *);
 
-int certificate_traverse(struct rpp *, struct cache_mapping const *);
+int traverse_tree(struct cache_mapping const *, struct validation *);
 
 #endif /* SRC_OBJECT_CERTIFICATE_H_ */
index 3339aecfd1bac40941b8a099f81821e94d84370e..36fd4cd52933d56d0946afbd4691866ced51f5c8 100644 (file)
@@ -139,7 +139,7 @@ validate_extensions(X509_CRL *crl)
 }
 
 static int
-crl_validate(X509_CRL *crl)
+crl_validate(X509_CRL *crl, X509 *parent)
 {
        long version;
        int error;
@@ -153,7 +153,7 @@ crl_validate(X509_CRL *crl)
        if (error)
                return error;
 
-       error = validate_issuer_name("CRL", X509_CRL_get_issuer(crl));
+       error = validate_issuer_name(X509_CRL_get_issuer(crl), parent);
        if (error)
                return error;
 
@@ -165,7 +165,7 @@ crl_validate(X509_CRL *crl)
 }
 
 int
-crl_load(struct cache_mapping *map, X509_CRL **result)
+crl_load(struct cache_mapping *map, X509 *parent, X509_CRL **result)
 {
        int error;
 
@@ -175,7 +175,7 @@ crl_load(struct cache_mapping *map, X509_CRL **result)
        if (error)
                goto end;
 
-       error = crl_validate(*result);
+       error = crl_validate(*result, parent);
        if (error)
                X509_CRL_free(*result);
 
index 59006ba04a525fb48f7c3b22b89b2cd195824ac5..04240ff3d01d83f5dbe648b94454d214d6031e45 100644 (file)
@@ -4,6 +4,6 @@
 #include <openssl/x509.h>
 #include "types/map.h"
 
-int crl_load(struct cache_mapping *, X509_CRL **);
+int crl_load(struct cache_mapping *, X509 *, X509_CRL **);
 
 #endif /* SRC_OBJECT_CRL_H_ */
index 7f5bf217ca02fe3e453498489d54cbb727efd3e8..d9d979d2fc633d52cb3f6c6dd740f9691c2c8f63 100644 (file)
@@ -16,13 +16,13 @@ handle_vcard(struct signed_object *sobj)
 }
 
 int
-ghostbusters_traverse(struct cache_mapping *map, struct rpp *pp)
+ghostbusters_traverse(struct cache_mapping *map,
+    struct rpki_certificate *parent)
 {
        static OID oid = OID_GHOSTBUSTERS;
        struct oid_arcs arcs = OID2ARCS("ghostbusters", oid);
        struct signed_object sobj;
-       struct ee_cert ee;
-       STACK_OF(X509_CRL) *crl;
+       struct rpki_certificate ee;
        int error;
 
        /* Prepare */
@@ -31,30 +31,22 @@ ghostbusters_traverse(struct cache_mapping *map, struct rpp *pp)
        /* Decode */
        error = signed_object_decode(&sobj, map->path);
        if (error)
-               goto revert_log;
+               goto end1;
 
        /* Prepare validation arguments */
-       crl = rpp_crl(pp);
-       if (crl == NULL) {
-               error = -EINVAL;
-               goto revert_sobj;
-       }
-       eecert_init(&ee, crl, true);
+       rpki_certificate_init_ee(&ee, parent, true);
 
        /* Validate everything */
        error = signed_object_validate(&sobj, &arcs, &ee);
        if (error)
-               goto revert_args;
+               goto end2;
        error = handle_vcard(&sobj);
        if (error)
-               goto revert_args;
-       error = refs_validate_ee(&ee.refs, pp, map->url);
+               goto end2;
+       error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, map->url);
 
-revert_args:
-       eecert_cleanup(&ee);
-revert_sobj:
+end2:  rpki_certificate_cleanup(&ee);
        signed_object_cleanup(&sobj);
-revert_log:
-       fnstack_pop();
+end1:  fnstack_pop();
        return error;
 }
index 5e71f65885b7b607dc6791ed20870911b17441c1..39350737e479881a5615a4a63a77882faadb024b 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef SRC_OBJECT_GHOSTBUSTERS_H_
 #define SRC_OBJECT_GHOSTBUSTERS_H_
 
-#include "rpp.h"
+#include "object/certificate.h"
 
-int ghostbusters_traverse(struct cache_mapping *, struct rpp *);
+int ghostbusters_traverse(struct cache_mapping *, struct rpki_certificate *);
 
 #endif /* SRC_OBJECT_GHOSTBUSTERS_H_ */
index 644ec256bf2b8a7a84a12c7ff52c34460ea10793..9b3edf2eac043062feeb77dbd3e7ab03e0266931 100644 (file)
@@ -1,11 +1,13 @@
 #include "object/manifest.h"
 
 #include "algorithm.h"
+#include "alloc.h"
 #include "asn1/asn1c/Manifest.h"
 #include "asn1/decode.h"
 #include "common.h"
 #include "hash.h"
 #include "log.h"
+#include "object/crl.h"
 #include "object/signed_object.h"
 #include "thread_var.h"
 #include "types/path.h"
@@ -166,6 +168,25 @@ validate_manifest(struct Manifest *manifest)
        return 0;
 }
 
+static void
+shuffle_mft_files(struct Manifest *mft)
+{
+       int i, j;
+       unsigned int seed, rnd;
+       struct FileAndHash *tmpfah;
+
+       seed = time(NULL) ^ getpid();
+
+       /* Fisher-Yates shuffle with modulo bias */
+       for (i = 0; i < mft->fileList.list.count - 1; i++) {
+               rnd = rand_r(&seed);
+               j = i + rnd % (mft->fileList.list.count - i);
+               tmpfah = mft->fileList.list.array[j];
+               mft->fileList.list.array[j] = mft->fileList.list.array[i];
+               mft->fileList.list.array[i] = tmpfah;
+       }
+}
+
 static bool
 is_valid_mft_file_chara(uint8_t chara)
 {
@@ -178,7 +199,7 @@ is_valid_mft_file_chara(uint8_t chara)
 
 /* RFC 9286, section 4.2.2 */
 static int
-validate_mft_file(IA5String_t *ia5)
+validate_mft_filename(IA5String_t *ia5)
 {
        size_t dot;
        size_t i;
@@ -214,9 +235,6 @@ check_file_and_hash(struct FileAndHash *fah, char const *path)
            fah->hash.buf, fah->hash.size);
 }
 
-#define INFER_CHILD(parent, fah) \
-       path_childn(parent, (char const *)fah->file.buf, fah->file.size)
-
 /*
  * XXX
  *
@@ -234,131 +252,124 @@ check_file_and_hash(struct FileAndHash *fah, char const *path)
  */
 
 static int
-build_rpp(struct cache_mapping *mft_map, struct Manifest *mft,
-    struct rpp **result)
+build_rpp(char const *mft_url, struct Manifest *mft, struct cache_cage *cage,
+    struct rpki_certificate *parent)
 {
-       struct cache_mapping pp_map;
-       struct rpp *pp;
-       unsigned int i, j;
-       struct FileAndHash *fah, *tmpfah;
-       struct cache_mapping map;
+       struct rpp *rpp;
+       char *rpp_url;
+       unsigned int i;
+       struct FileAndHash *src;
+       struct cache_mapping *dst;
+       char const *path;
        int error;
-       unsigned int seed, rnd;
 
-       seed = time(NULL) ^ getpid();
+       shuffle_mft_files(mft);
 
-       map_parent(mft_map, &pp_map);
-       pp = rpp_create();
-
-       /* Fisher-Yates shuffle with modulo bias */
-       for (i = 0; i < mft->fileList.list.count - 1; i++) {
-               rnd = rand_r(&seed);
-               j = i + rnd % (mft->fileList.list.count - i);
-               tmpfah = mft->fileList.list.array[j];
-               mft->fileList.list.array[j] = mft->fileList.list.array[i];
-               mft->fileList.list.array[i] = tmpfah;
-       }
+       rpp = &parent->rpp;
+       rpp_url = path_parent(mft_url);
+       rpp->nfiles = mft->fileList.list.count;
+       rpp->files = pzalloc(rpp->nfiles * sizeof(*rpp->files));
 
        for (i = 0; i < mft->fileList.list.count; i++) {
-               fah = mft->fileList.list.array[i];
+               src = mft->fileList.list.array[i];
+               dst = &rpp->files[i];
 
                /*
                 * IA5String is a subset of ASCII. However, IA5String_t doesn't
                 * seem to be guaranteed to be NULL-terminated.
                 */
 
-               error = validate_mft_file(&fah->file);
+               error = validate_mft_filename(&src->file);
                if (error)
-                       goto fail;
-
-               map.url = INFER_CHILD(pp_map.url, fah);
-               map.path = INFER_CHILD(pp_map.path, fah);
+                       goto revert;
+
+               dst->url = path_childn(rpp_url,
+                   (char const *)src->file.buf,
+                   src->file.size);
+
+               path = cage_map_file(cage, dst->url);
+               if (!path) {
+                       error = pr_val_err(
+                           "Manifest file '%s' is absent from the cache.",
+                           dst->url);
+                       goto revert;
+               }
+               dst->path = pstrdup(path);
 
-               error = check_file_and_hash(fah, map.path);
+               error = check_file_and_hash(src, dst->path);
                if (error)
-                       goto fail2;
+                       goto revert;
 
-               error = rpp_add_file(pp, &map);
-               if (error)
-                       goto fail2;
+               if (strcmp(((char const *)src->file.buf) + src->file.size - 4, ".crl") == 0) {
+                       if (rpp->crl.map != NULL) {
+                               error = pr_val_err(
+                                   "Manifest has more than one CRL.");
+                               goto revert;
+                       }
+                       rpp->crl.map = dst;
+               }
        }
 
        /* rfc6486#section-7 */
-       if (rpp_crl(pp) == NULL) {
+       if (rpp->crl.map == NULL) {
                error = pr_val_err("Manifest lacks a CRL.");
-               goto fail;
+               goto revert;
        }
 
-       map_cleanup(&pp_map);
-       *result = pp;
+       error = crl_load(rpp->crl.map, parent->x509, &rpp->crl.obj);
+       if (error)
+               goto revert;
+
+       free(rpp_url);
        return 0;
 
-fail2: map_cleanup(&map);
-fail:  map_cleanup(&pp_map);
-       rpp_refput(pp);
+revert:        rpp_cleanup(rpp);
+       free(rpp_url);
        return error;
 }
 
-/* Validates the manifest @map, returns the RPP described by it in @pp. */
 int
-handle_manifest(struct cache_mapping *map, struct rpp **pp)
+manifest_validate(char const *url, char const *path, struct cache_cage *cage,
+    struct rpki_certificate *parent)
 {
        static OID oid = OID_MANIFEST;
        struct oid_arcs arcs = OID2ARCS("manifest", oid);
        struct signed_object sobj;
-       struct ee_cert ee;
+       struct rpki_certificate ee;
        struct Manifest *mft;
-       STACK_OF(X509_CRL) *crl;
        int error;
 
        /* Prepare */
-       fnstack_push_map(map);
+       fnstack_push(url); // XXX
 
        /* Decode */
-       error = signed_object_decode(&sobj, map->path);
+       error = signed_object_decode(&sobj, path);
        if (error)
-               goto revert_log;
+               goto end1;
        error = decode_manifest(&sobj, &mft);
        if (error)
-               goto revert_sobj;
+               goto end2;
 
-       /* Initialize @pp */
-       error = build_rpp(map, mft, pp);
+       /* Initialize @summary */
+       error = build_rpp(url, mft, cage, parent);
        if (error)
-               goto revert_manifest;
+               goto end3;
 
        /* Prepare validation arguments */
-       crl = rpp_crl(*pp);
-       if (crl == NULL) {
-               error = -EINVAL;
-               goto revert_rpp;
-       }
-       eecert_init(&ee, crl, false);
+       rpki_certificate_init_ee(&ee, parent, false);
 
        /* Validate everything */
        error = signed_object_validate(&sobj, &arcs, &ee);
        if (error)
-               goto revert_args;
+               goto end4;
        error = validate_manifest(mft);
        if (error)
-               goto revert_args;
-       error = refs_validate_ee(&ee.refs, *pp, map->url);
-       if (error)
-               goto revert_args;
-
-       /* Success */
-       eecert_cleanup(&ee);
-       goto revert_manifest;
-
-revert_args:
-       eecert_cleanup(&ee);
-revert_rpp:
-       rpp_refput(*pp);
-revert_manifest:
-       ASN_STRUCT_FREE(asn_DEF_Manifest, mft);
-revert_sobj:
-       signed_object_cleanup(&sobj);
-revert_log:
-       fnstack_pop();
+               goto end4;
+       error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, url);
+
+end4:  rpki_certificate_cleanup(&ee);
+end3:  ASN_STRUCT_FREE(asn_DEF_Manifest, mft);
+end2:  signed_object_cleanup(&sobj);
+end1:  fnstack_pop();
        return error;
 }
index 3deb6ca3aaf5850fea96e2c6cf4e032071da8bf4..12cb16485b9ea320ec7a2b3339c61c18604536a6 100644 (file)
@@ -1,8 +1,13 @@
 #ifndef SRC_OBJECT_MANIFEST_H_
 #define SRC_OBJECT_MANIFEST_H_
 
-#include "rpp.h"
+#include <openssl/sha.h>
+#include <openssl/x509.h>
 
-int handle_manifest(struct cache_mapping *map, struct rpp **);
+#include "cache.h"
+#include "object/certificate.h"
+
+int manifest_validate(char const *url, char const *path,
+    struct cache_cage *cage, struct rpki_certificate *parent);
 
 #endif /* SRC_OBJECT_MANIFEST_H_ */
index c45f614e9926a89281d81623c89741478154edaf..cb70349f8593086cf165a5627be50730e779e3d0 100644 (file)
@@ -200,14 +200,13 @@ family_error:
 }
 
 int
-roa_traverse(struct cache_mapping *map, struct rpp *pp)
+roa_traverse(struct cache_mapping *map, struct rpki_certificate *parent)
 {
        static OID oid = OID_ROA;
        struct oid_arcs arcs = OID2ARCS("roa", oid);
        struct signed_object sobj;
-       struct ee_cert ee;
+       struct rpki_certificate ee;
        struct RouteOriginAttestation *roa;
-       STACK_OF(X509_CRL) *crl;
        int error;
 
        /* Prepare */
@@ -216,35 +215,26 @@ roa_traverse(struct cache_mapping *map, struct rpp *pp)
        /* Decode */
        error = signed_object_decode(&sobj, map->path);
        if (error)
-               goto revert_log;
+               goto end1;
        error = decode_roa(&sobj, &roa);
        if (error)
-               goto revert_sobj;
+               goto end2;
 
        /* Prepare validation arguments */
-       crl = rpp_crl(pp);
-       if (crl == NULL) {
-               error = -EINVAL;
-               goto revert_roa;
-       }
-       eecert_init(&ee, crl, false);
+       rpki_certificate_init_ee(&ee, parent, false);
 
        /* Validate and handle everything */
        error = signed_object_validate(&sobj, &arcs, &ee);
        if (error)
-               goto revert_args;
-       error = __handle_roa(roa, ee.res);
+               goto end3;
+       error = __handle_roa(roa, ee.resources);
        if (error)
-               goto revert_args;
-       error = refs_validate_ee(&ee.refs, pp, map->url);
+               goto end3;
+       error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, map->url);
 
-revert_args:
-       eecert_cleanup(&ee);
-revert_roa:
+end3:  rpki_certificate_cleanup(&ee);
        ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
-revert_sobj:
-       signed_object_cleanup(&sobj);
-revert_log:
-       fnstack_pop();
+end2:  signed_object_cleanup(&sobj);
+end1:  fnstack_pop();
        return error;
 }
index 2ae9a227d409fd2968becfc3785076492f9bdaaa..9642f3cc935b8bfd518c2b7ae41078c6129129e3 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef SRC_OBJECT_ROA_H_
 #define SRC_OBJECT_ROA_H_
 
-#include "rpp.h"
+#include "object/certificate.h"
 
-int roa_traverse(struct cache_mapping *, struct rpp *);
+int roa_traverse(struct cache_mapping *, struct rpki_certificate *);
 
 #endif /* SRC_OBJECT_ROA_H_ */
index f6c11fef51ca6392dc8c3f72762feef70a436cd8..8947a4e166f7455af0e650e63e6e3a07679e65b5 100644 (file)
@@ -68,7 +68,7 @@ validate_content_type(struct SignedData *sdata, struct oid_arcs const *oid)
 
 int
 signed_object_validate(struct signed_object *sobj, struct oid_arcs const *oid,
-    struct ee_cert *ee)
+    struct rpki_certificate *ee)
 {
        int error;
 
index cced66e69837db61ddbc1895df1c759b6b25a299..35670ab0b6605e6a624f7c6d95e7c6bcc116b916 100644 (file)
@@ -12,7 +12,7 @@ struct signed_object {
 
 int signed_object_decode(struct signed_object *, char const *);
 int signed_object_validate(struct signed_object *, struct oid_arcs const *,
-    struct ee_cert *);
+    struct rpki_certificate *);
 void signed_object_cleanup(struct signed_object *);
 
 #endif /* SRC_OBJECT_SIGNED_OBJECT_H_ */
index 0802e28a6ff566568f8ca03e827642e226412de9..2aac5dad6a735f422c45acc510bf1062c6d2aa6a 100644 (file)
@@ -10,6 +10,7 @@
 #include "config.h"
 #include "file.h"
 #include "log.h"
+#include "object/certificate.h"
 #include "thread_var.h"
 #include "types/path.h"
 #include "types/str.h"
@@ -34,14 +35,6 @@ struct validation_thread {
 /* List of threads, one per TAL file */
 SLIST_HEAD(threads_list, validation_thread);
 
-#define TS_SUCCESS     0       /* TA looks sane. */
-#define TS_NEXT                1       /* TA seems compromised; try some other URL. */
-#define TS_FALLBACK    2       /* TA is broken; fall back to old cache. */
-typedef struct { int v; } ta_status;
-static ta_status ts_success    = { .v = TS_SUCCESS };
-static ta_status ts_next       = { .v = TS_NEXT };
-static ta_status ts_fallback   = { .v = TS_FALLBACK };
-
 static char *
 find_newline(char *str)
 {
@@ -153,62 +146,6 @@ tal_get_spki(struct tal *tal, unsigned char const **buffer, size_t *len)
        *len = tal->spki_len;
 }
 
-static ta_status
-handle_ta(struct cache_mapping const *ta, struct validation *state)
-{
-       struct cert_stack *certstack;
-       struct deferred_cert deferred;
-       int error;
-
-       /* == Root certificate == */
-       if (certificate_traverse(NULL, ta) != 0) {
-               switch (validation_pubkey_state(state)) {
-               case PKS_INVALID:
-                       /* Signature invalid; probably an impersonator. */
-                       return ts_next;
-               case PKS_VALID:
-                       /* No impersonator but still error: Broken tree. */
-                       /*
-                        * XXX Change to ts_next. This is the TA;
-                        * we can't really afford to panic-fallback.
-                        */
-                       return ts_fallback;
-               case PKS_UNTESTED:
-                       /* We don't know; try some other URL. */
-                       return ts_next;
-               }
-
-               pr_crit("Unknown public key state: %u",
-                   validation_pubkey_state(state));
-       }
-
-       /*
-        * From now on, the tree should be considered valid, even if subsequent
-        * certificates fail.
-        * (the root validated successfully; subtrees are isolated problems.)
-        */
-
-       /* == Every other certificate == */
-       certstack = validation_certstack(state);
-
-       do {
-               error = deferstack_pop(certstack, &deferred);
-               if (error == -ENOENT)
-                       return ts_success; /* No more certificates left */
-               else if (error) /* All other errors are critical, currently */
-                       pr_crit("deferstack_pop() returned illegal %d.", error);
-
-               /*
-                * Ignore result code; remaining certificates are unrelated,
-                * so they should not be affected.
-                */
-               certificate_traverse(deferred.pp, &deferred.map);
-
-               map_cleanup(&deferred.map);
-               rpp_refput(deferred.pp);
-       } while (true);
-}
-
 static void
 __do_file_validation(struct validation_thread *thread)
 {
@@ -218,7 +155,6 @@ __do_file_validation(struct validation_thread *thread)
        struct validation *state;
        char **url;
        struct cache_mapping map;
-       ta_status status;
 
        thread->error = tal_init(&tal, thread->tal_file);
        if (thread->error)
@@ -236,28 +172,23 @@ __do_file_validation(struct validation_thread *thread)
        }
 
        ARRAYLIST_FOREACH(&tal.urls, url) {
-               if (cache_refresh_url(*url, &map) != 0)
+               map.url = *url;
+               map.path = cache_refresh_url(*url);
+               if (!map.path)
                        continue;
-
-               status = handle_ta(&map, state);
-               switch (status.v) {
-               case TS_SUCCESS:        goto end1;
-               case TS_FALLBACK:       goto fallback;
-               case TS_NEXT:           ; /* Fall through */
-               }
+               if (traverse_tree(&map, state) != 0)
+                       continue;
+               goto end1; /* Happy path */
        }
 
-fallback:
        ARRAYLIST_FOREACH(&tal.urls, url) {
-               if (cache_fallback_url(*url, &map) != 0)
+               map.url = *url;
+               map.path = cache_fallback_url(*url);
+               if (!map.path)
                        continue;
-
-               status = handle_ta(&map, state);
-               switch (status.v) {
-               case TS_SUCCESS:        goto end1;
-               case TS_FALLBACK:       /* Already fallbacking */
-               case TS_NEXT:           ; /* Fall through */
-               }
+               if (traverse_tree(&map, state) != 0)
+                       continue;
+               goto end1; /* Happy path */
        }
 
        pr_op_err("None of the TAL URIs yielded a successful traversal.");
index 27476c9394263ffe352168749f886e846bd3d7b5..7d91ee10dfa345db6696b0ef385f764776dffbdd 100644 (file)
 static BIO *
 __rsync2bio(char const *src, char const *dst)
 {
+       struct cache_mapping map;
        int error;
 
        // XXX use the cache
-       error = rsync_download(src, dst, NULL);
+
+       map.url = (char *)src;
+       map.path = (char *)dst;
+
+       error = rsync_download(&map);
        if (error) {
                pr_op_err("rysnc download failed: %s", strerror(abs(error)));
                return NULL;
index 7ab0394eb9ff55b8efcb79d29d28765212a08673..069565eed1a1aa530082a040bef7f7749bc3356e 100644 (file)
@@ -78,18 +78,10 @@ unknown:
        return -1;
 }
 
-static struct resources *
-get_parent_resources(void)
-{
-       return x509stack_peek_resources(validation_certstack(state_retrieve()));
-}
-
 static int
-inherit_aors(struct resources *resources, int family)
+inherit_aors(struct resources *resources, struct resources *parent, int family)
 {
-       struct resources *parent;
-
-       parent = get_parent_resources();
+       // XXX is this really crit worthy?
        if (parent == NULL)
                pr_crit("Parent has no resources.");
 
@@ -118,15 +110,13 @@ inherit_aors(struct resources *resources, int family)
 }
 
 static int
-add_prefix4(struct resources *resources, IPAddress_t *addr)
+add_prefix4(struct resources *resources, struct resources *parent,
+    IPAddress_t *addr)
 {
-       struct resources *parent;
        struct ipv4_prefix prefix;
        int error;
 
-       parent = get_parent_resources();
-
-       if ((parent != NULL) && (resources->ip4s == parent->ip4s))
+       if (parent && (resources->ip4s == parent->ip4s))
                return pr_val_err("Certificate defines IPv4 prefixes while also inheriting his parent's.");
 
        error = prefix4_decode(addr, &prefix);
@@ -160,15 +150,13 @@ add_prefix4(struct resources *resources, IPAddress_t *addr)
 }
 
 static int
-add_prefix6(struct resources *resources, IPAddress_t *addr)
+add_prefix6(struct resources *resources, struct resources *parent,
+    IPAddress_t *addr)
 {
-       struct resources *parent;
        struct ipv6_prefix prefix;
        int error;
 
-       parent = get_parent_resources();
-
-       if ((parent != NULL) && (resources->ip6s == parent->ip6s))
+       if (parent && (resources->ip6s == parent->ip6s))
                return pr_val_err("Certificate defines IPv6 prefixes while also inheriting his parent's.");
 
        error = prefix6_decode(addr, &prefix);
@@ -202,13 +190,14 @@ add_prefix6(struct resources *resources, IPAddress_t *addr)
 }
 
 static int
-add_prefix(struct resources *resources, int family, IPAddress_t *addr)
+add_prefix(struct resources *resources, struct resources *parent,
+    int family, IPAddress_t *addr)
 {
        switch (family) {
        case AF_INET:
-               return add_prefix4(resources, addr);
+               return add_prefix4(resources, parent, addr);
        case AF_INET6:
-               return add_prefix6(resources, addr);
+               return add_prefix6(resources, parent, addr);
        }
 
        pr_crit("Unknown address family '%d'", family);
@@ -216,14 +205,12 @@ add_prefix(struct resources *resources, int family, IPAddress_t *addr)
 }
 
 static int
-add_range4(struct resources *resources, IPAddressRange_t *input)
+add_range4(struct resources *resources, struct resources *parent,
+    IPAddressRange_t *input)
 {
-       struct resources *parent;
        struct ipv4_range range;
        int error;
 
-       parent = get_parent_resources();
-
        if (parent && (resources->ip4s == parent->ip4s))
                return pr_val_err("Certificate defines IPv4 ranges while also inheriting his parent's.");
 
@@ -259,15 +246,13 @@ add_range4(struct resources *resources, IPAddressRange_t *input)
 }
 
 static int
-add_range6(struct resources *resources, IPAddressRange_t *input)
+add_range6(struct resources *resources, struct resources *parent,
+    IPAddressRange_t *input)
 {
-       struct resources *parent;
        struct ipv6_range range;
        int error;
 
-       parent = get_parent_resources();
-
-       if ((parent != NULL) && (resources->ip6s == parent->ip6s))
+       if (parent && (resources->ip6s == parent->ip6s))
                return pr_val_err("Certificate defines IPv6 ranges while also inheriting his parent's.");
 
        error = range6_decode(input, &range);
@@ -302,13 +287,14 @@ add_range6(struct resources *resources, IPAddressRange_t *input)
 }
 
 static int
-add_range(struct resources *resources, int family, IPAddressRange_t *range)
+add_range(struct resources *resources, struct resources *parent,
+    int family, IPAddressRange_t *range)
 {
        switch (family) {
        case AF_INET:
-               return add_range4(resources, range);
+               return add_range4(resources, parent, range);
        case AF_INET6:
-               return add_range6(resources, range);
+               return add_range6(resources, parent, range);
        }
 
        pr_crit("Unknown address family '%d'", family);
@@ -316,7 +302,7 @@ add_range(struct resources *resources, int family, IPAddressRange_t *range)
 }
 
 static int
-add_aors(struct resources *resources, int family,
+add_aors(struct resources *resources, struct resources *parent, int family,
     struct IPAddressChoice__addressesOrRanges *aors)
 {
        struct IPAddressOrRange *aor;
@@ -332,13 +318,13 @@ add_aors(struct resources *resources, int family,
                aor = aors->list.array[i];
                switch (aor->present) {
                case IPAddressOrRange_PR_addressPrefix:
-                       error = add_prefix(resources, family,
+                       error = add_prefix(resources, parent, family,
                            &aor->choice.addressPrefix);
                        if (error)
                                return error;
                        break;
                case IPAddressOrRange_PR_addressRange:
-                       error = add_range(resources, family,
+                       error = add_range(resources, parent, family,
                            &aor->choice.addressRange);
                        if (error)
                                return error;
@@ -354,7 +340,8 @@ add_aors(struct resources *resources, int family,
 }
 
 int
-resources_add_ip(struct resources *resources, struct IPAddressFamily *obj)
+resources_add_ip(struct resources *resources, struct resources *parent,
+    struct IPAddressFamily *obj)
 {
        int family;
 
@@ -366,9 +353,9 @@ resources_add_ip(struct resources *resources, struct IPAddressFamily *obj)
        case IPAddressChoice_PR_NOTHING:
                break;
        case IPAddressChoice_PR_inherit:
-               return inherit_aors(resources, family);
+               return inherit_aors(resources, parent, family);
        case IPAddressChoice_PR_addressesOrRanges:
-               return add_aors(resources, family,
+               return add_aors(resources, parent, family,
                    &obj->ipAddressChoice.choice.addressesOrRanges);
        }
 
@@ -378,11 +365,8 @@ resources_add_ip(struct resources *resources, struct IPAddressFamily *obj)
 }
 
 static int
-inherit_asiors(struct resources *resources)
+inherit_asiors(struct resources *resources, struct resources *parent)
 {
-       struct resources *parent;
-
-       parent = get_parent_resources();
        if (parent == NULL)
                pr_crit("Parent has no resources.");
 
@@ -461,15 +445,13 @@ add_asn(struct resources *resources, struct asn_range const *asns,
 }
 
 static int
-add_asior(struct resources *resources, struct ASIdOrRange *obj)
+add_asior(struct resources *resources, struct resources *parent,
+    struct ASIdOrRange *obj)
 {
-       struct resources *parent;
        struct asn_range asns;
        int error;
 
-       parent = get_parent_resources();
-
-       if ((parent != NULL) && (resources->asns == parent->asns))
+       if (parent && (resources->asns == parent->asns))
                return pr_val_err("Certificate defines ASN resources while also inheriting his parent's.");
 
        switch (obj->present) {
@@ -497,7 +479,8 @@ add_asior(struct resources *resources, struct ASIdOrRange *obj)
 }
 
 static int
-add_asiors(struct resources *resources, struct ASIdentifiers *ids)
+add_asiors(struct resources *resources, struct resources *parent,
+    struct ASIdentifiers *ids)
 {
        struct ASIdentifierChoice__asIdsOrRanges *iors;
        int i;
@@ -511,7 +494,7 @@ add_asiors(struct resources *resources, struct ASIdentifiers *ids)
                return pr_val_err("AS extension's set of AS number records is empty.");
 
        for (i = 0; i < iors->list.count; i++) {
-               error = add_asior(resources, iors->list.array[i]);
+               error = add_asior(resources, parent, iors->list.array[i]);
                if (error)
                        return error;
        }
@@ -520,8 +503,8 @@ add_asiors(struct resources *resources, struct ASIdentifiers *ids)
 }
 
 int
-resources_add_asn(struct resources *resources, struct ASIdentifiers *ids,
-    bool allow_inherit)
+resources_add_asn(struct resources *resources, struct resources *parent,
+    struct ASIdentifiers *ids, bool allow_inherit)
 {
        if (ids->asnum == NULL)
                return pr_val_err("ASN extension lacks 'asnum' element.");
@@ -533,9 +516,9 @@ resources_add_asn(struct resources *resources, struct ASIdentifiers *ids,
                if (!allow_inherit)
                        return pr_val_err("ASIdentifierChoice %u isn't allowed",
                            ids->asnum->present);
-               return inherit_asiors(resources);
+               return inherit_asiors(resources, parent);
        case ASIdentifierChoice_PR_asIdsOrRanges:
-               return add_asiors(resources, ids);
+               return add_asiors(resources, parent, ids);
        case ASIdentifierChoice_PR_NOTHING:
                break;
        }
@@ -569,12 +552,6 @@ resources_contains_ipv6(struct resources *res, struct ipv6_prefix const *prefix)
        return res6_contains_prefix(res->ip6s, prefix);
 }
 
-enum rpki_policy
-resources_get_policy(struct resources *res)
-{
-       return res->policy;
-}
-
 void
 resources_set_policy(struct resources *res, enum rpki_policy policy)
 {
index 661e3b7bae0280e1704f79dc803ef496ac557085..5d811c23057de7f4694a088eb0bd2339f6789ba9 100644 (file)
@@ -26,15 +26,16 @@ struct resources;
 struct resources *resources_create(enum rpki_policy, bool);
 void resources_destroy(struct resources *);
 
-int resources_add_ip(struct resources *, struct IPAddressFamily *);
-int resources_add_asn(struct resources *, struct ASIdentifiers *, bool);
+int resources_add_ip(struct resources *, struct resources *,
+    struct IPAddressFamily *);
+int resources_add_asn(struct resources *, struct resources *,
+    struct ASIdentifiers *, bool);
 
 bool resources_empty(struct resources *);
 bool resources_contains_asns(struct resources *, struct asn_range const *);
 bool resources_contains_ipv4(struct resources *, struct ipv4_prefix const *);
 bool resources_contains_ipv6(struct resources *, struct ipv6_prefix const *);
 
-enum rpki_policy resources_get_policy(struct resources *);
 void resources_set_policy(struct resources *, enum rpki_policy);
 
 int resources_foreach_asn(struct resources *, foreach_asn_cb, void *);
index c3e75f945ad2476998357c785718b0b6d44233a3..160db8bff8bab828249a4431fd2a95fb620b0d0b 100644 (file)
--- a/src/rpp.c
+++ b/src/rpp.c
 #include "rpp.h"
 
-#include "common.h"
-#include "log.h"
-#include "object/crl.h"
-#include "object/ghostbusters.h"
-#include "object/roa.h"
-#include "thread_var.h"
-#include "types/arraylist.h"
-
-STATIC_ARRAY_LIST(filelist, struct cache_mapping)
-
-/* A Repository Publication Point (RFC 6481), as described by some manifest. */
-struct rpp {
-       struct filelist files;
-
-       struct {
-               struct cache_mapping map;
-               STACK_OF(X509_CRL) *stack;
-       } crl;
-
-       /*
-        * Note that the reference counting functions are not prepared for
-        * multithreading, because this is not atomic.
-        */
-       unsigned int references;
-};
-
-struct rpp *
-rpp_create(void)
-{
-       struct rpp *result = pmalloc(sizeof(struct rpp));
-       filelist_init(&result->files);
-       memset(&result->crl, 0, sizeof(result->crl));
-       result->references = 1;
-       return result;
-}
+#include "types/array.h"
 
 void
-rpp_refget(struct rpp *pp)
+rpp_cleanup(struct rpp *rpp)
 {
-       pp->references++;
-}
-
-void
-rpp_refput(struct rpp *pp)
-{
-       pp->references--;
-       if (pp->references == 0) {
-               filelist_cleanup(&pp->files, map_cleanup);
-               free(pp->crl.map.url);
-               free(pp->crl.map.path);
-               sk_X509_CRL_pop_free(pp->crl.stack, X509_CRL_free);
-               free(pp);
-       }
-}
-
-static int
-set_crl(struct rpp *pp, struct cache_mapping *map)
-{
-       X509_CRL *crl;
-       int error;
-
-       /* rfc6481#section-2.2 */
-       if (pp->crl.stack != NULL)
-               return pr_val_err("Repository Publication Point has more than one CRL.");
-
-       error = crl_load(map, &crl);
-       if (error)
-               return error;
-
-       pp->crl.stack = sk_X509_CRL_new_null();
-       if (pp->crl.stack == NULL)
-               enomem_panic();
-       if (sk_X509_CRL_push(pp->crl.stack, crl) <= 0) {
-               X509_CRL_free(crl);
-               sk_X509_CRL_pop_free(pp->crl.stack, X509_CRL_free);
-               pp->crl.stack = NULL;
-               return val_crypto_err("Could not add CRL to a CRL stack");
-       }
-
-       pp->crl.map = *map;
-       return 0;
-}
-
-/* Steals ownership of @map->* */
-int
-rpp_add_file(struct rpp *pp, struct cache_mapping *map)
-{
-       if (str_ends_with(map->url, ".crl"))
-               return set_crl(pp, map);
-
-       filelist_add(&pp->files, map);
-       return 0;
-}
-
-char const *
-rpp_get_crl_url(struct rpp const *pp)
-{
-       return pp->crl.map.url;
-}
-
-/*
- * The stack belongs to @pp and should not be released. Can be NULL, in which
- * case you're currently validating the TA (since it lacks governing CRL).
- */
-STACK_OF(X509_CRL) *
-rpp_crl(struct rpp *pp)
-{
-       return (pp != NULL) ? pp->crl.stack : NULL;
-}
-
-/* Traverses through all of @pp's known files, validating them. */
-void
-rpp_traverse(struct rpp *pp)
-{
-       struct cert_stack *certstack;
-       struct cache_mapping *map;
-
-       /*
-        * A subtree should not invalidate the rest of the tree, so error codes
-        * are ignored.
-        * (Errors log messages anyway.)
-        */
+       array_index i;
 
-       /*
-        * Certificates cannot be validated now, because then
-        * the algorithm would be recursive.
-        * Store them in the defer stack (see cert_stack.h),
-        * will get back to them later.
-        */
+       sk_X509_pop_free(rpp->ancestors, X509_free);
 
-       certstack = validation_certstack(state_retrieve());
+       for (i = 0; i < rpp->nfiles; i++)
+               map_cleanup(&rpp->files[i]);
+       free(rpp->files);
 
-       ARRAYLIST_FOREACH(&pp->files, map) {
-               char const *ext = map->url + strlen(map->url) - 4;
-               if (strcmp(ext, ".cer") == 0)
-                       deferstack_push(certstack, map, pp);
-               else if (strcmp(ext, ".roa") == 0)
-                       roa_traverse(map, pp);
-               else if (strcmp(ext, ".gbr") == 0)
-                       ghostbusters_traverse(map, pp);
-       }
+       if (rpp->crl.obj != NULL)
+               X509_CRL_free(rpp->crl.obj);
 }
index 15a15e3a8cc2ef7dd2fa778cea3c179cdab7b959..f63f2246a0e36e87abfb486d1d5cbfbaf18eac83 100644 (file)
--- a/src/rpp.h
+++ b/src/rpp.h
@@ -1,22 +1,25 @@
 #ifndef SRC_RPP_H_
 #define SRC_RPP_H_
 
-#include <openssl/safestack.h>
+// XXX move to types?
+
 #include <openssl/x509.h>
 
 #include "types/map.h"
 
-struct rpp;
-
-struct rpp *rpp_create(void);
-void rpp_refget(struct rpp *);
-void rpp_refput(struct rpp *);
+/* Repository Publication Point */
+struct rpp {
+       STACK_OF(X509) *ancestors;              /* 1st = root, last = parent */
 
-int rpp_add_file(struct rpp *, struct cache_mapping *);
+       struct cache_mapping *files;
+       size_t nfiles;                          /* Number of maps in @files */
 
-char const *rpp_get_crl_url(struct rpp const *);
-STACK_OF(X509_CRL) *rpp_crl(struct rpp *);
+       struct {
+               struct cache_mapping *map;      /* Points to @files entry */
+               X509_CRL *obj;
+       } crl;
+};
 
-void rpp_traverse(struct rpp *);
+void rpp_cleanup(struct rpp *);
 
 #endif /* SRC_RPP_H_ */
index ab87db9f6c49851a8feab9ec01f5c3e85bcb4f73..437cf7064ecd76685a824921fadabb1f47174d40 100644 (file)
@@ -1,7 +1,10 @@
 #include "rrdp.h"
 
+#include <openssl/bn.h>
+#include <openssl/sha.h>
+#include <sys/queue.h>
+
 #include "base64.h"
-#include "cachent.h"
 #include "cachetmp.h"
 #include "common.h"
 #include "config.h"
@@ -15,6 +18,7 @@
 #include "types/arraylist.h"
 #include "types/path.h"
 #include "types/url.h"
+#include "types/uthash.h"
 
 /* RRDP's XML namespace */
 #define RRDP_NAMESPACE         "http://www.ripe.net/rpki/rrdp"
 #define RRDP_ATTR_URI          "uri"
 #define RRDP_ATTR_HASH         "hash"
 
+struct rrdp_serial {
+       BIGNUM *num;
+       char *str;                      /* String version of @num. */
+};
+
+struct rrdp_session {
+       char *session_id;
+       struct rrdp_serial serial;
+};
+
+#define RRDP_HASH_LEN SHA256_DIGEST_LENGTH
+
+struct rrdp_hash {
+       unsigned char bytes[RRDP_HASH_LEN];
+       STAILQ_ENTRY(rrdp_hash) hook;
+};
+
+struct cache_file {
+       struct cache_mapping map;
+       UT_hash_handle hh;              /* Hash table hook */
+};
+
+/* Subset of the notification that is relevant to the TAL's cachefile */
+struct rrdp_state {
+       char const *repo;               /* Points to cache_node's map.path */
+
+       struct rrdp_session session;
+
+       struct cache_file *files;       /* Hash table */
+       unsigned int next_id;
+       size_t pathlen;
+
+       /*
+        * The 1st one contains the hash of the session.serial delta.
+        * The 2nd one contains the hash of the session.serial - 1 delta.
+        * The 3rd one contains the hash of the session.serial - 2 delta.
+        * And so on.
+        */
+       STAILQ_HEAD(, rrdp_hash) delta_hashes;
+};
+
 struct file_metadata {
        char *uri;
        unsigned char *hash; /* Array. Sometimes omitted. */
@@ -70,7 +115,7 @@ struct withdraw {
 
 struct parser_args {
        struct rrdp_session *session;
-       struct cache_node *notif;
+       struct rrdp_state *state;
 };
 
 static BIGNUM *
@@ -99,6 +144,27 @@ session_cleanup(struct rrdp_session *meta)
        free(meta->serial.str);
 }
 
+static struct cache_file *
+state_find_file(struct rrdp_state *state, char const *url, size_t len)
+{
+       struct cache_file *file;
+       HASH_FIND(hh, state->files, url, len, file);
+       return file;
+}
+
+static void
+state_flush_files(struct rrdp_state *state)
+{
+       struct cache_file *file, *tmp;
+
+       HASH_ITER(hh, state->files, file, tmp) {
+               HASH_DEL(state->files, file);
+               free(file->map.url);
+               free(file->map.path);
+               free(file);
+       }
+}
+
 static void
 metadata_cleanup(struct file_metadata *meta)
 {
@@ -371,7 +437,7 @@ parse_session(xmlTextReaderPtr reader, struct rrdp_session *meta)
 }
 
 static int
-validate_session(xmlTextReaderPtr reader, struct rrdp_session *expected)
+validate_session(xmlTextReaderPtr reader, struct parser_args *args)
 {
        struct rrdp_session actual = { 0 };
        int error;
@@ -380,15 +446,15 @@ validate_session(xmlTextReaderPtr reader, struct rrdp_session *expected)
        if (error)
                return error;
 
-       if (strcmp(expected->session_id, actual.session_id) != 0) {
+       if (strcmp(args->session->session_id, actual.session_id) != 0) {
                error = pr_val_err("File session id [%s] doesn't match notification's session id [%s]",
-                   expected->session_id, actual.session_id);
+                   args->session->session_id, actual.session_id);
                goto end;
        }
 
-       if (BN_cmp(actual.serial.num, expected->serial.num) != 0) {
+       if (BN_cmp(actual.serial.num, args->session->serial.num) != 0) {
                error = pr_val_err("File serial [%s] doesn't match notification's serial [%s]",
-                   actual.serial.str, expected->serial.str);
+                   actual.serial.str, args->session->serial.str);
                goto end;
        }
 
@@ -469,64 +535,100 @@ parse_withdraw(xmlTextReaderPtr reader, struct withdraw *tag)
        return 0;
 }
 
-/* Remove a local file and its directory tree (if empty) */
-static int
-delete_file(char const *path)
+static char *
+create_path(struct rrdp_state *state)
 {
-       /* Delete parent dirs only if empty. */
-       return delete_dir_recursive_bottom_up(path);
+       char *path;
+       int len;
+
+       do {
+               path = pmalloc(state->pathlen);
+
+               len = snprintf(path, state->pathlen, "%s/%X",
+                   state->repo, state->next_id);
+               if (len < 0) {
+                       pr_val_err("Cannot compute new cache path: Unknown cause.");
+                       return NULL;
+               }
+               if (len < state->pathlen) {
+                       state->next_id++;
+                       return path; /* Happy path */
+               }
+
+               state->pathlen++;
+               free(path);
+       } while (true);
 }
 
 static int
-handle_publish(xmlTextReaderPtr reader, struct cache_node *notif)
+handle_publish(xmlTextReaderPtr reader, struct parser_args *args)
 {
        struct publish tag = { 0 };
-       struct cache_node *subtree, *node;
+       struct cache_file *file;
+       size_t len;
        int error;
 
        error = parse_publish(reader, &tag);
        if (error)
                goto end;
 
-       if (!notif->rrdp.subtree) {
-               subtree = pzalloc(sizeof(struct cache_node));
-               subtree->url = "rsync://";
-               subtree->path = notif->path;
-               subtree->name = path_filename(subtree->path);
-               subtree->tmppath = notif->tmppath;
-               notif->rrdp.subtree = subtree;
-       }
+       pr_val_debug("Publish %s", logv_filename(tag.meta.uri));
 
-       node = cachent_provide(notif->rrdp.subtree, tag.meta.uri);
-       if (!node) {
-               // XXX outdated msg
-               error = pr_val_err("Broken RRDP: <publish> is attempting to create file '%s' outside of its publication point '%s'.",
-                   tag.meta.uri, notif->url);
-               goto end;
-       }
+       len = strlen(tag.meta.uri);
+       file = state_find_file(args->state, tag.meta.uri, len);
 
        /* rfc8181#section-2.2 */
-       if (node->flags & CNF_CACHED) {
+       if (file) {
                if (tag.meta.hash == NULL) {
                        // XXX watch out for this in the log before release
-                       error = pr_val_err("RRDP desync: <publish> is attempting to create '%s', but the file is already cached.",
+                       error = pr_val_err("RRDP desync: "
+                           "<publish> is attempting to create '%s', "
+                           "but the file is already cached.",
                            tag.meta.uri);
                        goto end;
                }
 
-               error = validate_hash(&tag.meta, node->path);
+               error = validate_hash(&tag.meta, file->map.path);
                if (error)
                        goto end;
 
-       } else if (tag.meta.hash != NULL) {
-               // XXX watch out for this in the log before release
-               error = pr_val_err("RRDP desync: <publish> is attempting to overwrite '%s', but the file is absent in the cache.",
-                   tag.meta.uri);
-               goto end;
+               /*
+                * Reminder: This is needed because the file might be
+                * hard-linked. Our repo file write should not propagate
+                * to the fallback.
+                */
+               if (remove(file->map.path) < 0) {
+                       error = errno;
+                       pr_val_err("Cannot delete %s: %s",
+                           file->map.path, strerror(error));
+                       if (error != ENOENT)
+                               goto end;
+               }
+
+       } else {
+               if (tag.meta.hash != NULL) {
+                       // XXX watch out for this in the log before release
+                       error = pr_val_err("RRDP desync: "
+                           "<publish> is attempting to overwrite '%s', "
+                           "but the file is absent in the cache.",
+                           tag.meta.uri);
+                       goto end;
+               }
+
+               file = pzalloc(sizeof(struct cache_file));
+               file->map.url = pstrdup(tag.meta.uri);
+               file->map.path = create_path(args->state);
+               if (!file->map.path) {
+                       free(file->map.url);
+                       free(file);
+                       error = -EINVAL;
+                       goto end;
+               }
+
+               HASH_ADD_KEYPTR(hh, args->state->files, file->map.url, len, file);
        }
 
-       pr_val_debug("Publish %s", logv_filename(node->tmppath));
-       error = file_write_full(node->tmppath, tag.content, tag.content_len);
+       error = file_write_full(file->map.path, tag.content, tag.content_len);
 
 end:   metadata_cleanup(&tag.meta);
        free(tag.content);
@@ -534,41 +636,43 @@ end:      metadata_cleanup(&tag.meta);
 }
 
 static int
-handle_withdraw(xmlTextReaderPtr reader, struct cache_node *notif)
+handle_withdraw(xmlTextReaderPtr reader, struct parser_args *args)
 {
        struct withdraw tag = { 0 };
-       struct cache_node *node;
+       struct cache_file *file;
+       size_t len;
        int error;
 
        error = parse_withdraw(reader, &tag);
        if (error)
                goto end;
 
-       node = cachent_provide(notif->rrdp.subtree, tag.meta.uri);
-       if (!node) {
-               // XXX outdated msg
-               error = pr_val_err("Broken RRDP: <withdraw> is attempting to delete file '%s' outside of its publication point '%s'.",
-                   tag.meta.uri, notif->url);
-               goto end;
-       }
+       pr_val_debug("Withdraw %s", logv_filename(tag.meta.uri));
 
-       /*
-        * XXX CNF_CACHED's comment suggests I should check parents,
-        * but this is not rsync.
-        */
-       if (!(node->flags & CNF_CACHED)) {
-               /* XXX May want to query the actualy filesystem, to be sure */
-               error = pr_val_err("RRDP desync: <withdraw> is attempting to delete file '%s', but it doesn't appear to exist.",
+       len = strlen(tag.meta.uri);
+       file = state_find_file(args->state, tag.meta.uri, len);
+
+       if (!file) {
+               error = pr_val_err("Broken RRDP: "
+                   "<withdraw> is attempting to delete unknown file '%s'.",
                    tag.meta.uri);
                goto end;
        }
 
-       error = validate_hash(&tag.meta, node->path);
+       error = validate_hash(&tag.meta, file->map.path);
        if (error)
                goto end;
 
-       node->flags |= CNF_WITHDRAWN;
-       pr_val_debug("Withdraw %s", logv_filename(tag.meta.uri));
+       if (remove(file->map.path) < 0) {
+               pr_val_warn("Cannot delete %s: %s", file->map.path,
+                   strerror(errno));
+               /* It's fine; keep going. */
+       }
+
+       HASH_DEL(args->state->files, file);
+       free(file->map.url);
+       free(file->map.path);
+       free(file);
 
 end:   metadata_cleanup(&tag.meta);
        return error;
@@ -765,7 +869,6 @@ parse_notification(char const *url, char const *path,
 static int
 xml_read_snapshot(xmlTextReaderPtr reader, void *arg)
 {
-       struct parser_args *args = arg;
        xmlReaderTypes type;
        xmlChar const *name;
        int error;
@@ -775,9 +878,9 @@ xml_read_snapshot(xmlTextReaderPtr reader, void *arg)
        switch (type) {
        case XML_READER_TYPE_ELEMENT:
                if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH))
-                       error = handle_publish(reader, args->notif);
+                       error = handle_publish(reader, arg);
                else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_SNAPSHOT))
-                       error = validate_session(reader, args->session);
+                       error = validate_session(reader, arg);
                else
                        return pr_val_err("Unexpected '%s' element", name);
                if (error)
@@ -792,14 +895,14 @@ xml_read_snapshot(xmlTextReaderPtr reader, void *arg)
 
 static int
 parse_snapshot(struct rrdp_session *session, char const *path,
-    struct cache_node *notif)
+    struct rrdp_state *state)
 {
-       struct parser_args args = { .session = session, .notif = notif };
+       struct parser_args args = { .session = session, .state = state };
        return relax_ng_parse(path, xml_read_snapshot, &args);
 }
 
 static int
-validate_session_desync(struct cachefile_notification *old_notif,
+validate_session_desync(struct rrdp_state *old_notif,
     struct update_notification *new_notif)
 {
        struct rrdp_hash *old_delta;
@@ -851,7 +954,7 @@ dl_tmp(char const *url, char **path)
 }
 
 static int
-handle_snapshot(struct update_notification *new, struct cache_node *notif)
+handle_snapshot(struct update_notification *new, struct rrdp_state *state)
 {
        char *tmppath;
        int error;
@@ -865,7 +968,7 @@ handle_snapshot(struct update_notification *new, struct cache_node *notif)
        error = validate_hash(&new->snapshot, tmppath);
        if (error)
                goto end2;
-       error = parse_snapshot(&new->session, tmppath, notif);
+       error = parse_snapshot(&new->session, tmppath, state);
 //     delete_file(tmppath); XXX
 
 end2:  free(tmppath);
@@ -876,7 +979,6 @@ end1:       fnstack_pop();
 static int
 xml_read_delta(xmlTextReaderPtr reader, void *arg)
 {
-       struct parser_args *args = arg;
        xmlReaderTypes type;
        xmlChar const *name;
        int error;
@@ -886,11 +988,11 @@ xml_read_delta(xmlTextReaderPtr reader, void *arg)
        switch (type) {
        case XML_READER_TYPE_ELEMENT:
                if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH))
-                       error = handle_publish(reader, args->notif);
+                       error = handle_publish(reader, arg);
                else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_WITHDRAW))
-                       error = handle_withdraw(reader, args->notif);
+                       error = handle_withdraw(reader, arg);
                else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_DELTA))
-                       error = validate_session(reader, args->session);
+                       error = validate_session(reader, arg);
                else
                        return pr_val_err("Unexpected '%s' element", name);
                if (error)
@@ -905,7 +1007,7 @@ xml_read_delta(xmlTextReaderPtr reader, void *arg)
 
 static int
 parse_delta(struct update_notification *notif, struct notification_delta *delta,
-    char const *path, struct cache_node *notif_node)
+    char const *path, struct rrdp_state *state)
 {
        struct parser_args args;
        struct rrdp_session session;
@@ -918,14 +1020,14 @@ parse_delta(struct update_notification *notif, struct notification_delta *delta,
        session.session_id = notif->session.session_id;
        session.serial = delta->serial;
        args.session = &session;
-       args.notif = notif_node;
+       args.state = state;
 
        return relax_ng_parse(path, xml_read_delta, &args);
 }
 
 static int
 handle_delta(struct update_notification *notif,
-    struct notification_delta *delta, struct cache_node *notif_node)
+    struct notification_delta *delta, struct rrdp_state *state)
 {
        char *tmppath;
        int error;
@@ -936,7 +1038,7 @@ handle_delta(struct update_notification *notif,
        error = dl_tmp(delta->meta.uri, &tmppath);
        if (error)
                goto end;
-       error = parse_delta(notif, delta, tmppath, notif_node);
+       error = parse_delta(notif, delta, tmppath, state);
 //     delete_file(tmppath); XXX
 
        free(tmppath);
@@ -945,7 +1047,7 @@ end:       fnstack_pop();
 }
 
 static int
-handle_deltas(struct update_notification *notif, struct cache_node *notif_node)
+handle_deltas(struct update_notification *notif, struct rrdp_state *state)
 {
        struct rrdp_serial *old;
        struct rrdp_serial *new;
@@ -959,7 +1061,7 @@ handle_deltas(struct update_notification *notif, struct cache_node *notif_node)
                return -ENOENT;
        }
 
-       old = &notif_node->rrdp.session.serial;
+       old = &state->session.serial;
        new = &notif->session.serial;
 
        pr_val_debug("Handling RRDP delta serials %s-%s.", old->str, new->str);
@@ -982,7 +1084,7 @@ handle_deltas(struct update_notification *notif, struct cache_node *notif_node)
                    old->str, new->str);
 
        for (d = notif->deltas.len - diff; d < notif->deltas.len; d++) {
-               error = handle_delta(notif, &notif->deltas.array[d], notif_node);
+               error = handle_delta(notif, &notif->deltas.array[d], state);
                if (error)
                        return error;
        }
@@ -995,7 +1097,7 @@ handle_deltas(struct update_notification *notif, struct cache_node *notif_node)
  * Consumes @new.
  */
 static void
-init_notif(struct cachefile_notification *old, struct update_notification *new)
+init_notif(struct rrdp_state *old, struct update_notification *new)
 {
        size_t dn;
        size_t i;
@@ -1018,14 +1120,14 @@ init_notif(struct cachefile_notification *old, struct update_notification *new)
 }
 
 static void
-drop_notif(struct cachefile_notification *notif)
+drop_notif(struct rrdp_state *state)
 {
        struct rrdp_hash *hash;
 
-       session_cleanup(&notif->session);
-       while (!STAILQ_EMPTY(&notif->delta_hashes)) {
-               hash = STAILQ_FIRST(&notif->delta_hashes);
-               STAILQ_REMOVE_HEAD(&notif->delta_hashes, hook);
+       session_cleanup(&state->session);
+       while (!STAILQ_EMPTY(&state->delta_hashes)) {
+               hash = STAILQ_FIRST(&state->delta_hashes);
+               STAILQ_REMOVE_HEAD(&state->delta_hashes, hook);
                free(hash);
        }
 }
@@ -1035,7 +1137,7 @@ drop_notif(struct cachefile_notification *notif)
  * Consumes @new on success.
  */
 static int
-update_notif(struct cachefile_notification *old, struct update_notification *new)
+update_notif(struct rrdp_state *old, struct update_notification *new)
 {
        BIGNUM *diff_bn;
        BN_ULONG diff; /* difference between the old and new serials */
@@ -1083,100 +1185,102 @@ update_notif(struct cachefile_notification *old, struct update_notification *new
        return 0;
 }
 
-static bool
-dl_notif(struct cache_node *notif, struct update_notification *new)
+static int
+dl_notif(struct cache_mapping *map,  time_t mtim, bool *changed,
+    struct update_notification *new)
 {
        char *tmppath;
-       time_t mtim;
-       bool changed;
-
-       notif->dlerr = cache_tmpfile(&tmppath);
-       if (notif->dlerr)
-               return false;
+       int error;
 
-       mtim = time_nonfatal();
-       changed = false;
-       notif->dlerr = http_download(notif->url, tmppath, notif->mtim, &changed);
-       notif->flags |= CNF_FRESH;
+       error = cache_tmpfile(&tmppath);
+       if (error)
+               return error;
 
-       if (notif->dlerr)
+       *changed = false;
+       error = http_download(map->url, tmppath, mtim, changed);
+       if (error)
                goto end;
-       if (!changed) {
+       if (!(*changed)) {
                pr_val_debug("The Notification has not changed.");
                goto end;
        }
 
-       notif->mtim = mtim; /* XXX should happen much later */
-       notif->dlerr = parse_notification(notif->url, tmppath, new);
-       if (notif->dlerr)
+       error = parse_notification(map->url, tmppath, new);
+       if (error)
                goto end;
 
        if (remove(tmppath) < 0) {
-               /*
-                * Note, this could be ignored if we weren't planning on reusing
-                * the path. This is going to stop being an issue once streaming
-                * is implemented.
-                */
-               notif->dlerr = errno;
-               pr_val_err("Can't remove notification's temporal file: %s",
-                  strerror(notif->dlerr));
+               pr_val_warn("Can't remove notification's temporal file: %s",
+                  strerror(errno));
                update_notification_cleanup(new);
-               goto end;
+               /* Nonfatal; fall through */
        }
 
-       notif->flags |= CNF_FREE_TMPPATH;
-       notif->tmppath = tmppath;
-       return true;
-
 end:   free(tmppath);
-       return false;
+       return error;
 }
 
 /*
- * Downloads the Update Notification @notif, and updates the cache accordingly.
+ * Downloads the Update Notification @notif->url, and updates the cache
+ * accordingly.
  *
  * "Updates the cache accordingly" means it downloads the missing deltas or
- * snapshot, and explodes them into @notif's tmp directory.
+ * snapshot, and explodes them into @notif->path.
  */
 int
-rrdp_update(struct cache_node *notif)
+rrdp_update(struct cache_mapping *notif, time_t mtim, bool *changed,
+    struct rrdp_state **state)
 {
-       struct cachefile_notification *old;
+       struct rrdp_state *old;
        struct update_notification new;
        int serial_cmp;
+       int error;
 
        fnstack_push(notif->url);
        pr_val_debug("Processing notification.");
 
-       if (!dl_notif(notif, &new))
-               goto end; /* Unchanged or error */
+       error = dl_notif(notif, mtim, changed, &new);
+       if (error)
+               goto end;
+       if (!(*changed))
+               goto end;
 
        pr_val_debug("New session/serial: %s/%s", new.session.session_id,
            new.session.serial.str);
 
-       if (!(notif->flags & CNF_NOTIFICATION)) {
+       if ((*state) == NULL) {
                pr_val_debug("This is a new Notification.");
-               notif->dlerr = handle_snapshot(&new, notif);
-               if (notif->dlerr)
+
+               old = pzalloc(sizeof(struct rrdp_state));
+               old->repo = notif->path;
+               /* session postponed! */
+               old->pathlen = strlen(old->repo) + 5;
+               STAILQ_INIT(&old->delta_hashes);
+
+               error = handle_snapshot(&new, old);
+               if (error) {
+                       state_flush_files(old);
+                       free(old);
                        goto clean_notif;
+               }
 
-               notif->flags |= CNF_NOTIFICATION;
-               init_notif(&notif->rrdp, &new);
+               init_notif(old, &new);
+               *state = old;
                goto end;
        }
 
-       old = &notif->rrdp;
+       old = *state;
        serial_cmp = BN_cmp(old->session.serial.num, new.session.serial.num);
        if (serial_cmp < 0) {
                pr_val_debug("The Notification's serial changed.");
-               notif->dlerr = validate_session_desync(old, &new);
-               if (notif->dlerr)
+               error = validate_session_desync(old, &new);
+               if (error)
                        goto snapshot_fallback;
-               notif->dlerr = handle_deltas(&new, notif);
-               if (notif->dlerr)
+               error = handle_deltas(&new, old);
+               if (error)
                        goto snapshot_fallback;
-               notif->dlerr = update_notif(old, &new);
-               if (!notif->dlerr)
+               error = update_notif(old, &new);
+               if (!error)
                        goto end;
                /*
                 * The files are exploded and usable, but @cached is not
@@ -1199,8 +1303,8 @@ rrdp_update(struct cache_node *notif)
 
 snapshot_fallback:
        pr_val_debug("Falling back to snapshot.");
-       notif->dlerr = handle_snapshot(&new, notif);
-       if (notif->dlerr)
+       error = handle_snapshot(&new, old);
+       if (error)
                goto clean_notif;
 
 reset_notif:
@@ -1212,7 +1316,15 @@ clean_notif:
        update_notification_cleanup(&new);
 
 end:   fnstack_pop();
-       return notif->dlerr;
+       return error;
+}
+
+char const *
+rrdp_file(struct rrdp_state *state, char const *url)
+{
+       struct cache_file *file;
+       file = state_find_file(state, url, strlen(url));
+       return file ? file->map.path : NULL;
 }
 
 #define TAGNAME_SESSION "session_id"
@@ -1228,7 +1340,7 @@ hash_b2c(unsigned char bin)
 }
 
 json_t *
-rrdp_notif2json(struct cachefile_notification *notif)
+rrdp_state2json(struct rrdp_state *state)
 {
        json_t *json;
        json_t *deltas;
@@ -1236,19 +1348,19 @@ rrdp_notif2json(struct cachefile_notification *notif)
        struct rrdp_hash *hash;
        size_t i;
 
-       if (notif == NULL)
+       if (state == NULL)
                return NULL;
 
        json = json_object();
        if (json == NULL)
                enomem_panic();
 
-       if (json_add_str(json, TAGNAME_SESSION, notif->session.session_id))
+       if (json_add_str(json, TAGNAME_SESSION, state->session.session_id))
                goto fail;
-       if (json_add_str(json, TAGNAME_SERIAL, notif->session.serial.str))
+       if (json_add_str(json, TAGNAME_SERIAL, state->session.serial.str))
                goto fail;
 
-       if (STAILQ_EMPTY(&notif->delta_hashes))
+       if (STAILQ_EMPTY(&state->delta_hashes))
                return json; /* Happy path, but unlikely. */
 
        deltas = json_array();
@@ -1258,7 +1370,7 @@ rrdp_notif2json(struct cachefile_notification *notif)
                goto fail;
 
        hash_str[2 * RRDP_HASH_LEN] = '\0';
-       STAILQ_FOREACH(hash, &notif->delta_hashes, hook) {
+       STAILQ_FOREACH(hash, &state->delta_hashes, hook) {
                for (i = 0; i < RRDP_HASH_LEN; i++) {
                        hash_str[2 * i    ] = hash_b2c(hash->bytes[i] >> 4);
                        hash_str[2 * i + 1] = hash_b2c(hash->bytes[i]     );
@@ -1324,29 +1436,29 @@ bad_char:
 }
 
 static void
-clear_delta_hashes(struct cachefile_notification *notif)
+clear_delta_hashes(struct rrdp_state *state)
 {
        struct rrdp_hash *hash;
 
-       while (!STAILQ_EMPTY(&notif->delta_hashes)) {
-               hash = STAILQ_FIRST(&notif->delta_hashes);
-               STAILQ_REMOVE_HEAD(&notif->delta_hashes, hook);
+       while (!STAILQ_EMPTY(&state->delta_hashes)) {
+               hash = STAILQ_FIRST(&state->delta_hashes);
+               STAILQ_REMOVE_HEAD(&state->delta_hashes, hook);
                free(hash);
        }
 }
 
 int
-rrdp_json2notif(json_t *json, struct cachefile_notification **result)
+rrdp_json2state(json_t *json, struct rrdp_state **result)
 {
-       struct cachefile_notification *notif;
+       struct rrdp_state *state;
        char const *str;
        json_t *jdeltas;
        size_t d, dn;
        struct rrdp_hash *hash;
        int error;
 
-       notif = pzalloc(sizeof(struct cachefile_notification));
-       STAILQ_INIT(&notif->delta_hashes);
+       state = pzalloc(sizeof(struct rrdp_state));
+       STAILQ_INIT(&state->delta_hashes);
 
        error = json_get_str(json, TAGNAME_SESSION, &str);
        if (error) {
@@ -1354,7 +1466,7 @@ rrdp_json2notif(json_t *json, struct cachefile_notification **result)
                        pr_op_err("Node is missing the '" TAGNAME_SESSION "' tag.");
                goto revert_notif;
        }
-       notif->session.session_id = pstrdup(str);
+       state->session.session_id = pstrdup(str);
 
        error = json_get_str(json, TAGNAME_SERIAL, &str);
        if (error) {
@@ -1362,11 +1474,11 @@ rrdp_json2notif(json_t *json, struct cachefile_notification **result)
                        pr_op_err("Node is missing the '" TAGNAME_SERIAL "' tag.");
                goto revert_session;
        }
-       notif->session.serial.str = pstrdup(str);
+       state->session.serial.str = pstrdup(str);
 
-       notif->session.serial.num = BN_create();
-       if (!BN_dec2bn(&notif->session.serial.num, notif->session.serial.str)) {
-               error = pr_op_err("Not a serial number: %s", notif->session.serial.str);
+       state->session.serial.num = BN_create();
+       if (!BN_dec2bn(&state->session.serial.num, state->session.serial.str)) {
+               error = pr_op_err("Not a serial number: %s", state->session.serial.str);
                goto revert_serial;
        }
 
@@ -1387,38 +1499,38 @@ rrdp_json2notif(json_t *json, struct cachefile_notification **result)
                error = json2dh(json_array_get(jdeltas, d), &hash);
                if (error)
                        goto revert_deltas;
-               STAILQ_INSERT_TAIL(&notif->delta_hashes, hash, hook);
+               STAILQ_INSERT_TAIL(&state->delta_hashes, hash, hook);
        }
 
 success:
-       *result = notif;
+       *result = state;
        return 0;
 
 revert_deltas:
-       clear_delta_hashes(notif);
+       clear_delta_hashes(state);
 revert_serial:
-       BN_free(notif->session.serial.num);
-       free(notif->session.serial.str);
+       BN_free(state->session.serial.num);
+       free(state->session.serial.str);
 revert_session:
-       free(notif->session.session_id);
+       free(state->session.session_id);
 revert_notif:
-       free(notif);
+       free(state);
        return error;
 }
 
 void
-rrdp_notif_cleanup(struct cachefile_notification *notif)
+rrdp_state_cleanup(struct rrdp_state *state)
 {
-       session_cleanup(&notif->session);
-       cachent_delete(notif->subtree);
-       clear_delta_hashes(notif);
+       session_cleanup(&state->session);
+       state_flush_files(state);
+       clear_delta_hashes(state);
 }
 
 void
-rrdp_notif_free(struct cachefile_notification *notif)
+rrdp_state_free(struct rrdp_state *state)
 {
-       if (notif != NULL) {
-               rrdp_notif_cleanup(notif);
-               free(notif);
+       if (state != NULL) {
+               rrdp_state_cleanup(state);
+               free(state);
        }
 }
index 984811a2118e4f7e25f7b5c82d623f737b80b754..6c4663bdcc1441425989311f68773bddb1dd9e88 100644 (file)
@@ -2,51 +2,20 @@
 #define SRC_RRDP_H_
 
 #include <jansson.h>
-#include <openssl/bn.h>
-#include <openssl/sha.h>
-#include <sys/queue.h>
+#include <stdbool.h>
+#include <time.h>
 
-struct cache_node;
+#include "types/map.h"
 
-/* These are supposed to be unbounded */
-struct rrdp_serial {
-       BIGNUM *num;
-       char *str; /* String version of @num. */
-};
+struct rrdp_state;
 
-struct rrdp_session {
-       char *session_id;
-       struct rrdp_serial serial;
-};
+int rrdp_update(struct cache_mapping *, time_t, bool *, struct rrdp_state **);
+char const *rrdp_file(struct rrdp_state *, char const *);
 
-#define RRDP_HASH_LEN SHA256_DIGEST_LENGTH
+json_t *rrdp_state2json(struct rrdp_state *);
+int rrdp_json2state(json_t *, struct rrdp_state **);
 
-struct rrdp_hash {
-       unsigned char bytes[RRDP_HASH_LEN];
-       STAILQ_ENTRY(rrdp_hash) hook;
-};
-
-/*
- * Subset of the notification that is relevant to the TAL's cachefile.
- */
-struct cachefile_notification {
-       struct rrdp_session session;
-       struct cache_node *subtree;
-       /*
-        * The 1st one contains the hash of the session.serial delta.
-        * The 2nd one contains the hash of the session.serial - 1 delta.
-        * The 3rd one contains the hash of the session.serial - 2 delta.
-        * And so on.
-        */
-       STAILQ_HEAD(, rrdp_hash) delta_hashes;
-};
-
-int rrdp_update(struct cache_node *);
-
-json_t *rrdp_notif2json(struct cachefile_notification *);
-int rrdp_json2notif(json_t *, struct cachefile_notification **);
-
-void rrdp_notif_cleanup(struct cachefile_notification *);
-void rrdp_notif_free(struct cachefile_notification *);
+void rrdp_state_cleanup(struct rrdp_state *);
+void rrdp_state_free(struct rrdp_state *);
 
 #endif /* SRC_RRDP_H_ */
index 36aa596b86140cda88f12587d9a337d771fc2747..ec59418120dd9739092e01a8f708996353fbecd4 100644 (file)
@@ -38,13 +38,13 @@ duplicate_fds(int fds[2][2])
 }
 
 static void
-prepare_rsync(char **args, char const *src, char const *dst, char const *cmpdst)
+prepare_rsync(char **args, struct cache_mapping *map)
 {
        size_t i = 0;
 
        /*
-        * execvp() is not going to tweak those strings;
-        * stop angsting over those casts.
+        * execvp() is not going to tweak these strings;
+        * stop angsting over the const-to-raw conversion.
         */
 
        /* XXX review */
@@ -69,13 +69,9 @@ prepare_rsync(char **args, char const *src, char const *dst, char const *cmpdst)
        args[i++] = "--include=*.mft";
        args[i++] = "--include=*.roa";
        args[i++] = "--exclude=*";
-       if (cmpdst) {
-               args[i++] = "--compare-dest";
-               args[i++] = (char *)cmpdst;
-       }
 #endif
-       args[i++] = (char *)src;
-       args[i++] = (char *)dst;
+       args[i++] = map->url;
+       args[i++] = map->path;
        args[i++] = NULL;
 }
 
@@ -276,9 +272,9 @@ exhaust_pipes(int fds[2][2])
        return exhaust_read_fds(STDERR_READ(fds), STDOUT_READ(fds));
 }
 
-/* rsync [--compare-dest @cmpdst] @src @dst */
+/* rsync @src @dst */
 int
-rsync_download(char const *src, char const *dst, char const *cmpdst)
+rsync_download(struct cache_mapping *map)
 {
        char *args[32];
        /* Descriptors to pipe stderr (first element) and stdout (second) */
@@ -290,16 +286,16 @@ rsync_download(char const *src, char const *dst, char const *cmpdst)
        int error;
 
        /* Prepare everything for the child exec */
-       prepare_rsync(args, src, dst, cmpdst);
+       prepare_rsync(args, map);
 
-       pr_val_info("rsync: %s", src);
+       pr_val_info("rsync: %s -> %s", map->url, map->path);
        if (log_val_enabled(LOG_DEBUG)) {
                pr_val_debug("Executing rsync:");
                for (i = 0; args[i] != NULL; i++)
                        pr_val_debug("    %s", args[i]);
        }
 
-       error = mkdir_p(dst, true);
+       error = mkdir_p(map->path, true);
        if (error)
                return error;
 
@@ -369,11 +365,11 @@ rsync_download(char const *src, char const *dst, char const *cmpdst)
                        if (retries == config_get_rsync_retry_count()) {
                                if (retries > 0)
                                        pr_val_warn("Max RSYNC retries (%u) reached on '%s', won't retry again.",
-                                           retries, src);
+                                           retries, map->url);
                                return EIO;
                        }
                        pr_val_warn("Retrying RSYNC '%s' in %u seconds, %u attempts remaining.",
-                           src,
+                           map->url,
                            config_get_rsync_retry_interval(),
                            config_get_rsync_retry_count() - retries);
                        retries++;
index 52781eed35e3a6ac00a31affa9dbdeb8672d6a51..beb96bedf928c8d6432b51ee813a6266a9293e31 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef SRC_RSYNC_RSYNC_H_
 #define SRC_RSYNC_RSYNC_H_
 
-int rsync_download(char const *, char const *, char const *);
+#include "types/map.h"
+
+int rsync_download(struct cache_mapping *);
 
 #endif /* SRC_RSYNC_RSYNC_H_ */
index 62099e65db893463a0028c00c1dbd0e3af43678a..ed4d998f1213329d5c72f374823e5035f98f0245 100644 (file)
@@ -5,11 +5,10 @@
 #include "thread_var.h"
 
 /**
- * The current state of the validation cycle.
+ * Just a bunch of thread-specific variables that are too much of a pain
+ * to keep passing around.
  *
- * It is one of the core objects in this project. Every time a trust anchor
- * triggers a validation cycle, the validator creates one of these objects and
- * uses it to traverse the tree and keep track of validated data.
+ * Should be refactored away, honestly.
  */
 struct validation {
        struct tal *tal;
@@ -20,11 +19,6 @@ struct validation {
                X509_VERIFY_PARAM *params;
        } x509_data;
 
-       struct cert_stack *certstack;
-
-       /* Did the TAL's public key match the root certificate's public key? */
-       enum pubkey_state pubkey_state;
-
        /**
         * Two buffers calling code will store stringified IP addresses in,
         * to prevent proliferation of similar buffers on the stack.
@@ -107,20 +101,12 @@ validation_prepare(struct validation **out, struct tal *tal,
        X509_STORE_set1_param(result->x509_data.store, params);
        X509_STORE_set_verify_cb(result->x509_data.store, cb);
 
-       error = certstack_create(&result->certstack);
-       if (error)
-               goto undo_crypto;
-
-       result->pubkey_state = PKS_UNTESTED;
        result->validation_handler = *validation_handler;
        result->x509_data.params = params; /* Ownership transfered */
 
        *out = result;
        return 0;
 
-undo_crypto:
-       X509_VERIFY_PARAM_free(params);
-       X509_STORE_free(result->x509_data.store);
 undo_result:
        free(result);
        return error;
@@ -131,7 +117,6 @@ validation_destroy(struct validation *state)
 {
        X509_VERIFY_PARAM_free(state->x509_data.params);
        X509_STORE_free(state->x509_data.store);
-       certstack_destroy(state->certstack);
        free(state);
 }
 
@@ -147,30 +132,6 @@ validation_store(struct validation *state)
        return state->x509_data.store;
 }
 
-struct cert_stack *
-validation_certstack(struct validation *state)
-{
-       return state->certstack;
-}
-
-void
-validation_pubkey_valid(struct validation *state)
-{
-       state->pubkey_state = PKS_VALID;
-}
-
-void
-validation_pubkey_invalid(struct validation *state)
-{
-       state->pubkey_state = PKS_INVALID;
-}
-
-enum pubkey_state
-validation_pubkey_state(struct validation *state)
-{
-       return state->pubkey_state;
-}
-
 char *
 validation_get_ip_buffer1(struct validation *state)
 {
index e00952397c4d8705b97efcd07f0c1f3404654344..d168a71535551349bbc37bde6d83a44a3d7ed0ed 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef SRC_STATE_H_
 #define SRC_STATE_H_
 
-#include "cert_stack.h"
+#include <openssl/x509.h>
+
 #include "object/tal.h"
 #include "validation_handler.h"
 
@@ -13,17 +14,9 @@ void validation_destroy(struct validation *);
 
 struct tal *validation_tal(struct validation *);
 X509_STORE *validation_store(struct validation *);
-struct cert_stack *validation_certstack(struct validation *);
-
-enum pubkey_state {
-       PKS_VALID,
-       PKS_INVALID,
-       PKS_UNTESTED,
-};
 
 void validation_pubkey_valid(struct validation *);
 void validation_pubkey_invalid(struct validation *);
-enum pubkey_state validation_pubkey_state(struct validation *);
 
 char *validation_get_ip_buffer1(struct validation *);
 char *validation_get_ip_buffer2(struct validation *);
index d2b0c72a695c25d25ba669191cbd8ca013b3922d..23bca5ae6cede447c98c229877bc53bfd901dbf1 100644 (file)
@@ -2,6 +2,7 @@
 #define SRC_THREAD_VAR_H_
 
 #include "state.h"
+#include "types/map.h"
 
 int thvar_init(void); /* This function does not need cleanup. */
 
index 7377f402d5681d18aeba3a57f6c01d2a86f5b242..4eddaa56ff0d52d0125ae8c9cd8e52340c94d986 100644 (file)
@@ -33,25 +33,6 @@ map_op_get_printable(struct cache_mapping const *map)
        return map_get_printable(map, config_get_op_log_file_format());
 }
 
-void
-map_parent(struct cache_mapping const *child, struct cache_mapping *parent)
-{
-       parent->url = path_parent(child->url);
-       parent->path = path_parent(child->path);
-}
-
-struct cache_mapping *
-map_child(struct cache_mapping const *parent, char const *name)
-{
-       struct cache_mapping *child;
-
-       child = pmalloc(sizeof(struct cache_mapping));
-       child->url = join_paths(parent->url, name);
-       child->path = join_paths(parent->path, name);
-
-       return child;
-}
-
 void
 map_copy(struct cache_mapping *dst, struct cache_mapping const *src)
 {
index 3ecc56fa6434ca3c24d2263b77594dc9e8f9eeeb..c7d9a4e61f96ac6b84c8712f0e2fc307b5bef880 100644 (file)
@@ -12,9 +12,6 @@ struct cache_mapping {
 char const *map_val_get_printable(struct cache_mapping const *);
 char const *map_op_get_printable(struct cache_mapping const *);
 
-void map_parent(struct cache_mapping const *, struct cache_mapping *);
-struct cache_mapping *map_child(struct cache_mapping const *, char const *);
-
 void map_copy(struct cache_mapping *, struct cache_mapping const *);
 void map_cleanup(struct cache_mapping *);
 
index 0a128f7bcca3e9f784ce3dbd3244d7f65c489b95..556b553bcb5b7c5ad6f6c3874789f807a682c37b 100644 (file)
@@ -140,10 +140,8 @@ x509_name_equals(struct rfc5280_name *a, struct rfc5280_name *b)
 }
 
 int
-validate_issuer_name(char const *container, X509_NAME *issuer)
+validate_issuer_name(X509_NAME *issuer, X509 *parent)
 {
-       struct validation *state;
-       X509 *parent;
        struct rfc5280_name *parent_subject;
        struct rfc5280_name *child_issuer;
        int error;
@@ -155,13 +153,6 @@ validate_issuer_name(char const *container, X509_NAME *issuer)
         * But let's check it anyway.
         */
 
-       state = state_retrieve();
-       parent = x509stack_peek(validation_certstack(state));
-       if (parent == NULL) {
-               return pr_val_err("%s appears to have no parent certificate.",
-                   container);
-       }
-
        error = x509_name_decode(X509_get_subject_name(parent), "subject",
            &parent_subject);
        if (error)
@@ -178,8 +169,7 @@ validate_issuer_name(char const *container, X509_NAME *issuer)
                parent_serial = x509_name_serialNumber(parent_subject);
                child_serial = x509_name_serialNumber(child_issuer);
 
-               error = pr_val_err("%s's issuer name ('%s%s%s') does not equal issuer certificate's name ('%s%s%s').",
-                   container,
+               error = pr_val_err("Issuer name ('%s%s%s') does not equal issuer certificate's name ('%s%s%s').",
                    x509_name_commonName(child_issuer),
                    (child_serial != NULL) ? "/" : "",
                    (child_serial != NULL) ? child_serial : "",
index 3c38b2345556c67b743ef449d2625c6c7e636a82..ca2d84d0d3cad0d1d1b5c170c96997412d9e8cfc 100644 (file)
@@ -20,7 +20,7 @@ bool x509_name_equals(struct rfc5280_name *, struct rfc5280_name *);
 
 
 /* X509_NAME utils */
-int validate_issuer_name(char const *, X509_NAME *);
+int validate_issuer_name(X509_NAME *, X509 *);
 
 void x509_name_pr_debug(char const *, X509_NAME *);
 
index 8bfb7a8466d3aa54bde91d566fedcc311a66d40c..d521d1342e1a6c6cb8ebf8ef208b5a66981fce80 100644 (file)
@@ -4,12 +4,6 @@
 #include <string.h>
 #include "types/uthash.h"
 
-static int
-cnf_clean(int flags)
-{
-       return flags & ~(CNF_FREE_URL | CNF_FREE_PATH | CNF_FREE_TMPPATH);
-}
-
 void
 ck_assert_cachent_eq(struct cache_node *expected, struct cache_node *actual)
 {
@@ -20,7 +14,7 @@ ck_assert_cachent_eq(struct cache_node *expected, struct cache_node *actual)
        ck_assert_str_eq(expected->url, actual->url);
        ck_assert_str_eq(expected->path, actual->path);
        ck_assert_str_eq(expected->name, actual->name);
-       ck_assert_int_eq(cnf_clean(expected->flags), cnf_clean(actual->flags));
+       ck_assert_int_eq(expected->flags, actual->flags);
        if (expected->tmppath)
                ck_assert_str_eq(expected->tmppath, actual->tmppath);
        else
index 3d37166037df2c3d8ab90bdbe4185829d07521b3..37ae43842cd1b1cdce1b3fe34908788793fc67fd 100644 (file)
@@ -10,7 +10,7 @@
 static char deleted[16][6];
 static unsigned int dn;
 
-MOCK_ABORT_VOID(rrdp_notif_cleanup, struct cachefile_notification *notif)
+MOCK_ABORT_VOID(rrdp_state_cleanup, struct cachefile_notification *notif)
 
 static void
 __delete_node_cb(struct cache_node const *node)
index a73b86f8b6aecc450c855a0f55eddd1f1e0e510b..4ee885685ceceba0a169fb5cd4ce34c5a9fdc44b 100644 (file)
@@ -10,7 +10,7 @@
 #include "types/path.c"
 #include "types/url.c"
 
-MOCK_ABORT_VOID(rrdp_notif_cleanup, struct cachefile_notification *notif)
+MOCK_ABORT_VOID(rrdp_state_cleanup, struct cachefile_notification *notif)
 MOCK_ABORT_INT(signed_object_decode, struct signed_object *sobj, char const *path)
 MOCK_ABORT_VOID(signed_object_cleanup, struct signed_object *sobj)
 MOCK_VOID(__delete_node_cb, struct cache_node const *node)
@@ -32,7 +32,7 @@ __test_validate(char const *src, size_t len)
        dst.buf = buffer;
        dst.size = len;
 
-       return validate_mft_file(&dst);
+       return validate_mft_filename(&dst);
 }
 
 #define test_validate(str) __test_validate(str, sizeof(str) - 1)
index bf11db66f3f0d92f2b5aaabd72f940d5d488f899..e41b04ed646a61e990d834c0eff456e2466175d9 100644 (file)
@@ -26,13 +26,10 @@ MOCK_ABORT_INT(handle_roa_v6, uint32_t as, struct ipv6_prefix const *prefix,
     uint8_t max_length, void *arg)
 MOCK_ABORT_INT(handle_router_key, unsigned char const *ski,
     struct asn_range const *asns, unsigned char const *spk, void *arg)
-MOCK_ABORT_VOID(rpp_refput, struct rpp *pp)
 MOCK(state_retrieve, struct validation *, NULL, void)
-MOCK_ABORT_PTR(validation_certstack, cert_stack, struct validation *state)
 MOCK_ABORT_VOID(validation_destroy, struct validation *state)
 MOCK_ABORT_INT(validation_prepare, struct validation **out, struct tal *tal,
     struct validation_handler *validation_handler)
-MOCK_ABORT_ENUM(validation_pubkey_state, pubkey_state, struct validation *state)
 MOCK(validation_tal, struct tal *, NULL, struct validation *state)
 
 /* Tests */
index 4041892ca1160354fd9d6c9dc0e2e185276e8600..a20fb913e8ec83608d2e891024e1ca3007660bd4 100644 (file)
@@ -410,7 +410,7 @@ validate_cachefile_notif(struct cachefile_notification *notif,
 
        ck_assert_ptr_eq(NULL, hash);
 
-       rrdp_notif_free(notif);
+       rrdp_state_free(notif);
 }
 
 START_TEST(test_update_notif)
@@ -632,10 +632,10 @@ START_TEST(test_2s_simple)
 
        notif = create_cachefile_notif("session", "1234", 0);
 
-       json = rrdp_notif2json(notif);
+       json = rrdp_state2json(notif);
        ck_assert_ptr_ne(NULL, json);
 
-       rrdp_notif_free(notif);
+       rrdp_state_free(notif);
        notif = NULL;
 
        ck_assert_int_eq(0, json_get_str(json, TAGNAME_SESSION, &str));
@@ -644,12 +644,12 @@ START_TEST(test_2s_simple)
        ck_assert_str_eq("1234", str);
        ck_assert_int_eq(ENOENT, json_get_array(json, TAGNAME_DELTAS, &jdeltas));
 
-       ck_assert_int_eq(0, rrdp_json2notif(json, &notif));
+       ck_assert_int_eq(0, rrdp_json2state(json, &notif));
        ck_rrdp_session("session", "1234", &notif->session);
        ck_assert_uint_eq(true, STAILQ_EMPTY(&notif->delta_hashes));
 
        json_decref(json);
-       rrdp_notif_free(notif);
+       rrdp_state_free(notif);
 }
 END_TEST
 
@@ -672,10 +672,10 @@ START_TEST(test_2s_more)
            "123456789012345678901234567890123456789012",
            0xAA, 0xBB, 0xCD, 0);
 
-       json = rrdp_notif2json(notif);
+       json = rrdp_state2json(notif);
        ck_assert_ptr_ne(NULL, json);
 
-       rrdp_notif_free(notif);
+       rrdp_state_free(notif);
        notif = NULL;
 
        ck_assert_int_eq(0, json_get_str(json, TAGNAME_SESSION, &str));
@@ -691,7 +691,7 @@ START_TEST(test_2s_more)
        ck_assert_str_eq("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
            json_string_value(json_array_get(jdeltas, 2)));
 
-       ck_assert_int_eq(0, rrdp_json2notif(json, &notif));
+       ck_assert_int_eq(0, rrdp_json2state(json, &notif));
        ck_rrdp_session("session", "123456789012345678901234567890123456789012", &notif->session);
        hash = STAILQ_FIRST(&notif->delta_hashes);
        ck_assert_ptr_ne(NULL, hash);
@@ -706,12 +706,12 @@ START_TEST(test_2s_more)
        ck_assert_ptr_eq(NULL, hash);
 
        json_decref(json);
-       rrdp_notif_free(notif);
+       rrdp_state_free(notif);
 }
 END_TEST
 
 void
-ck_json2notif(int expected, char const *json_str)
+ck_json2state(int expected, char const *json_str)
 {
        json_t *json;
        json_error_t error;
@@ -721,55 +721,55 @@ ck_json2notif(int expected, char const *json_str)
        ck_assert_ptr_ne(NULL, json);
 
        notif = NULL;
-       ck_assert_int_eq(expected, rrdp_json2notif(json, &notif));
+       ck_assert_int_eq(expected, rrdp_json2state(json, &notif));
 
        json_decref(json);
        if (notif == NULL)
-               rrdp_notif_free(notif);
+               rrdp_state_free(notif);
 }
 
 START_TEST(test_2s_errors)
 {
        struct cachefile_notification notif = { 0 };
 
-       ck_assert_ptr_eq(NULL, rrdp_notif2json(NULL));
-       ck_assert_ptr_eq(NULL, rrdp_notif2json(&notif));
+       ck_assert_ptr_eq(NULL, rrdp_state2json(NULL));
+       ck_assert_ptr_eq(NULL, rrdp_state2json(&notif));
        notif.session.session_id = "sid";
-       ck_assert_ptr_eq(NULL, rrdp_notif2json(&notif));
-
-       ck_json2notif(ENOENT, "{}");
-       ck_json2notif(0, "{ \"" TAGNAME_SESSION "\":\"sss\", \"" TAGNAME_SERIAL "\":\"123\" }");
-       ck_json2notif(-EINVAL, "{ \"" TAGNAME_SESSION "\":null, \"" TAGNAME_SERIAL "\":\"123\" }");
-       ck_json2notif(-EINVAL, "{ \"" TAGNAME_SESSION "\":\"sss\", \"" TAGNAME_SERIAL "\":null }");
-       ck_json2notif(-EINVAL, "{ \"" TAGNAME_SESSION "\":123, \"" TAGNAME_SERIAL "\":\"123\" }");
-       ck_json2notif(-EINVAL, "{ \"" TAGNAME_SESSION "\":\"sss\", \"" TAGNAME_SERIAL "\":123 }");
-       ck_json2notif(ENOENT, "{ \"" TAGNAME_SESSION "\":\"sss\" }");
-       ck_json2notif(ENOENT, "{ \"" TAGNAME_SERIAL "\":\"123\" }");
-       ck_json2notif(-EINVAL,
+       ck_assert_ptr_eq(NULL, rrdp_state2json(&notif));
+
+       ck_json2state(ENOENT, "{}");
+       ck_json2state(0, "{ \"" TAGNAME_SESSION "\":\"sss\", \"" TAGNAME_SERIAL "\":\"123\" }");
+       ck_json2state(-EINVAL, "{ \"" TAGNAME_SESSION "\":null, \"" TAGNAME_SERIAL "\":\"123\" }");
+       ck_json2state(-EINVAL, "{ \"" TAGNAME_SESSION "\":\"sss\", \"" TAGNAME_SERIAL "\":null }");
+       ck_json2state(-EINVAL, "{ \"" TAGNAME_SESSION "\":123, \"" TAGNAME_SERIAL "\":\"123\" }");
+       ck_json2state(-EINVAL, "{ \"" TAGNAME_SESSION "\":\"sss\", \"" TAGNAME_SERIAL "\":123 }");
+       ck_json2state(ENOENT, "{ \"" TAGNAME_SESSION "\":\"sss\" }");
+       ck_json2state(ENOENT, "{ \"" TAGNAME_SERIAL "\":\"123\" }");
+       ck_json2state(-EINVAL,
            "{ \"" TAGNAME_SESSION "\":\"sss\","
              "\"" TAGNAME_SERIAL "\":\"123\","
              "\"" TAGNAME_DELTAS "\":null }");
-       ck_json2notif(-EINVAL,
+       ck_json2state(-EINVAL,
            "{ \"" TAGNAME_SESSION "\":\"sss\","
              "\"" TAGNAME_SERIAL "\":\"123\","
              "\"" TAGNAME_DELTAS "\":\"123\" }");
-       ck_json2notif(-EINVAL,
+       ck_json2state(-EINVAL,
            "{ \"" TAGNAME_SESSION "\":\"sss\","
              "\"" TAGNAME_SERIAL "\":\"123\","
              "\"" TAGNAME_DELTAS "\":{} }");
-       ck_json2notif(0,
+       ck_json2state(0,
            "{ \"" TAGNAME_SESSION "\":\"sss\","
              "\"" TAGNAME_SERIAL "\":\"123\","
              "\"" TAGNAME_DELTAS "\":[] }");
-       ck_json2notif(-EINVAL,
+       ck_json2state(-EINVAL,
            "{ \"" TAGNAME_SESSION "\":\"sss\","
              "\"" TAGNAME_SERIAL "\":\"123\","
              "\"" TAGNAME_DELTAS "\":[ 1 ] }");
-       ck_json2notif(-EINVAL,
+       ck_json2state(-EINVAL,
            "{ \"" TAGNAME_SESSION "\":\"sss\","
              "\"" TAGNAME_SERIAL "\":\"123\","
              "\"" TAGNAME_DELTAS "\":[ \"111\" ] }");
-       ck_json2notif(0,
+       ck_json2state(0,
            "{ \"" TAGNAME_SESSION "\":\"sss\","
              "\"" TAGNAME_SERIAL "\":\"123\","
              "\"" TAGNAME_DELTAS "\":[ \"1111111111111111111111111111111111111111111111111111111111111111\" ] }");