]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Always pick most recent known manifest
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Mon, 2 Dec 2024 21:11:45 +0000 (18:11 -0300)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Mon, 2 Dec 2024 21:11:45 +0000 (18:11 -0300)
Non-strict version.

Fixes new (still unnumbered) CVE.

src/cache.c
src/cache.h
src/object/manifest.c
src/object/manifest.h
src/types/rpp.h

index 2f4572e3cb24c08539995e5076eaf9b502c669e9..f3b9e451d67d12ff3b9162040b7eabbcff2bfaa6 100644 (file)
@@ -62,6 +62,7 @@ struct cache_node {
        time_t attempt_ts;      /* Refresh: Dl attempt. Fallback: Commit */
        time_t success_ts;      /* Refresh: Dl success. Fallback: Commit */
 
+       struct mft_meta mft;    /* RPP fallbacks only */
        struct rrdp_state *rrdp;
 
        UT_hash_handle hh;      /* Hash table hook */
@@ -80,7 +81,7 @@ struct cache_table {
        char *name;
        bool enabled;
        struct cache_sequence seq;
-       struct cache_node *nodes; /* Hash Table */
+       struct cache_node *nodes;       /* Hash Table */
        dl_cb download;
        pthread_mutex_t lock;
 };
@@ -108,6 +109,7 @@ struct cache_cage {
        struct cache_node const *refresh;
        struct cache_node const *fallback;
        char const *rpkiNotify;
+       struct mft_meta *mft;           /* Fallback */
 };
 
 struct cache_commit {
@@ -115,6 +117,7 @@ struct cache_commit {
        char *caRepository;
        struct cache_mapping *files;
        size_t nfiles;
+       struct mft_meta mft;            /* RPPs commits only */
        STAILQ_ENTRY(cache_commit) lh;
 };
 
@@ -392,6 +395,9 @@ json2node(json_t *json)
        error = json_get_ts(json, "success", &node->success_ts);
        if (error != 0 && error != ENOENT)
                goto fail;
+       error = json_get_ts(json, "mftUpdate", &node->mft.update);
+       if (error < 0)
+               goto fail;
        error = json_get_object(json, "rrdp", &rrdp);
        if (error < 0)
                goto fail;
@@ -531,6 +537,8 @@ node2json(struct cache_node *node)
                goto fail;
        if (node->success_ts && json_add_ts(json, "success", node->success_ts))
                goto fail;
+       if (node->mft.update && json_add_ts(json, "mftUpdate", node->mft.update))
+               goto fail;
        if (node->rrdp)
                if (json_object_add(json, "rrdp", rrdp_state2json(node->rrdp)))
                        goto fail;
@@ -965,6 +973,12 @@ cage_disable_refresh(struct cache_cage *cage)
        return true;
 }
 
+struct mft_meta const *
+cage_mft_fallback(struct cache_cage *cage)
+{
+       return cage->mft;
+}
+
 /*
  * Steals ownership of @rpp->files and @rpp->nfiles, but they're not going to be
  * modified nor deleted until the cache cleanup.
@@ -980,6 +994,7 @@ cache_commit_rpp(char const *rpkiNotify, char const *caRepository,
        commit->caRepository = pstrdup(caRepository);
        commit->files = rpp->files;
        commit->nfiles = rpp->nfiles;
+       commit->mft = rpp->mft;
 
        mutex_lock(&commits_lock);
        STAILQ_INSERT_TAIL(&commits, commit, lh);
@@ -1070,6 +1085,8 @@ commit_rpp(struct cache_commit *commit, struct cache_node *fb)
        char const *dst;
        array_index i;
 
+       fb->mft = commit->mft;
+
        for (i = 0; i < commit->nfiles; i++) {
                src = commit->files + i;
 
index 552b95b5b0cc68cf6c3d21eb4f6879bf968effe6..0be38fff7cfe3f1ebf6a06e6c29941ba0ae09035 100644 (file)
@@ -44,6 +44,7 @@ struct cache_cage;
 int cache_refresh_by_sias(struct sia_uris *, struct cache_cage **);
 char const *cage_map_file(struct cache_cage *, char const *);
 bool cage_disable_refresh(struct cache_cage *);
+struct mft_meta const *cage_mft_fallback(struct cache_cage *);
 void cache_commit_rpp(char const *, char const *, struct rpp *);
 void cache_commit_file(struct cache_mapping *);
 
index 6700c123d223f21bdc11874a8bc7b9b88177e3b6..361142e06bfbc2022c650156d74bcf71fed738c3 100644 (file)
@@ -1,3 +1,6 @@
+#define _DEFAULT_SOURCE  1     /* timegm() on Linux */
+#define _DARWIN_C_SOURCE 1     /* timegm() on MacOS */
+
 #include "object/manifest.h"
 
 #include "algorithm.h"
@@ -49,7 +52,8 @@ tm_cmp(struct tm *tm1, struct tm *tm2)
 }
 
 static int
-validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next)
+validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next,
+    struct mft_meta *meta)
 {
 #define TM_FMT "%02d/%02d/%02d %02d:%02d:%02d"
 #define TM_ARGS(tm)                                                    \
@@ -98,6 +102,13 @@ validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next)
                    TM_ARGS(nextUpdate));
        }
 
+       meta->update = timegm(&thisUpdate);
+       if (meta->update == (time_t)-1) {
+               error = errno;
+               return pr_val_err("Cannot convert '" TM_FMT "' to time_t: %s",
+                   TM_ARGS(thisUpdate), strerror(error));
+       }
+
        return 0;
 
 #undef TM_FMT
@@ -105,7 +116,23 @@ validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next)
 }
 
 static int
-validate_manifest(struct Manifest *manifest)
+check_more_recent(struct cache_cage *cage, struct mft_meta *current)
+{
+       struct mft_meta const *prev;
+
+       prev = cage_mft_fallback(cage);
+       if (!prev)
+               return 0;
+
+       if (prev->update && difftime(prev->update, current->update) > 0)
+               return pr_val_err("The fallback manifest is newer than the downloaded one.");
+
+       return 0;
+}
+
+static int
+validate_manifest(struct Manifest *mft, struct cache_cage *cage,
+    struct mft_meta *meta)
 {
        unsigned long version;
        int error;
@@ -130,8 +157,8 @@ validate_manifest(struct Manifest *manifest)
         */
 
        /* rfc6486#section-4.4.2 */
-       if (manifest->version != NULL) {
-               error = asn_INTEGER2ulong(manifest->version, &version);
+       if (mft->version != NULL) {
+               error = asn_INTEGER2ulong(mft->version, &version);
                if (error) {
                        if (errno) {
                                pr_val_err("Error casting manifest version: %s",
@@ -147,11 +174,15 @@ validate_manifest(struct Manifest *manifest)
         * "Manifest verifiers MUST be able to handle number values up to
         * 20 octets."
         */
-       if (manifest->manifestNumber.size > 20)
+       if (mft->manifestNumber.size > 20)
                return pr_val_err("Manifest number is larger than 20 octets");
 
        /* rfc6486#section-4.4.3 */
-       error = validate_dates(&manifest->thisUpdate, &manifest->nextUpdate);
+       error = validate_dates(&mft->thisUpdate, &mft->nextUpdate, meta);
+       if (error)
+               return error;
+
+       error = check_more_recent(cage, meta);
        if (error)
                return error;
 
@@ -163,7 +194,7 @@ validate_manifest(struct Manifest *manifest)
         * I'm going with the signed object hash function, since it appears to
         * be the closest match.
         */
-       error = validate_cms_hashing_algorithm_oid(&manifest->fileHashAlg,
+       error = validate_cms_hashing_algorithm_oid(&mft->fileHashAlg,
            "manifest file");
        if (error)
                return error;
@@ -367,7 +398,7 @@ manifest_traverse(char const *url, char const *path, struct cache_cage *cage,
        error = signed_object_validate(&sobj, &arcs, &ee);
        if (error)
                goto end5;
-       error = validate_manifest(mft);
+       error = validate_manifest(mft, cage, &parent->rpp.mft);
        if (error)
                goto end5;
        error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, url);
index e3b28b03460230dc87475c4575738182600fc332..ad09fac1099f3f8c0ba4a2f6e29bbb133b7598f6 100644 (file)
@@ -7,7 +7,7 @@
 #include "cache.h"
 #include "object/certificate.h"
 
-int manifest_traverse(char const *url, char const *path,
-    struct cache_cage *cage, struct rpki_certificate *parent);
+int manifest_traverse(char const *, char const *, struct cache_cage *,
+    struct rpki_certificate *);
 
 #endif /* SRC_OBJECT_MANIFEST_H_ */
index 8440700fd0538d64eccf2ff0d30ab0b9900f7329..97d324b4114cd7a3943b33d6302855ac8eb3023f 100644 (file)
@@ -2,9 +2,14 @@
 #define SRC_RPP_H_
 
 #include <openssl/x509.h>
+#include <time.h>
 
 #include "types/map.h"
 
+struct mft_meta {
+       time_t update;                          /* Manifest's thisUpdate */
+};
+
 /* Repository Publication Point */
 struct rpp {
        struct cache_mapping *files;
@@ -14,6 +19,8 @@ struct rpp {
                struct cache_mapping *map;      /* Points to @files entry */
                X509_CRL *obj;
        } crl;
+
+       struct mft_meta mft;
 };
 
 void rpp_cleanup(struct rpp *);