Non-strict version.
Fixes new (still unnumbered) CVE.
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 */
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;
};
struct cache_node const *refresh;
struct cache_node const *fallback;
char const *rpkiNotify;
+ struct mft_meta *mft; /* Fallback */
};
struct cache_commit {
char *caRepository;
struct cache_mapping *files;
size_t nfiles;
+ struct mft_meta mft; /* RPPs commits only */
STAILQ_ENTRY(cache_commit) lh;
};
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;
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;
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.
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);
char const *dst;
array_index i;
+ fb->mft = commit->mft;
+
for (i = 0; i < commit->nfiles; i++) {
src = commit->files + i;
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 *);
+#define _DEFAULT_SOURCE 1 /* timegm() on Linux */
+#define _DARWIN_C_SOURCE 1 /* timegm() on MacOS */
+
#include "object/manifest.h"
#include "algorithm.h"
}
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) \
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
}
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;
*/
/* 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",
* "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;
* 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;
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);
#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_ */
#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;
struct cache_mapping *map; /* Points to @files entry */
X509_CRL *obj;
} crl;
+
+ struct mft_meta mft;
};
void rpp_cleanup(struct rpp *);