Testing. Fixes bugs and TODOs.
* to a tree leaf. Loops aren't possible.
*/
- pr_val_debug("EE Certificate (embedded) {");
-
/*
* "If the call is successful *in is incremented to the byte following
* the parsed data."
resources_set_policy(ee->res, policy);
error = certificate_get_resources(cert, ee->res, CERTYPE_EE);
- if (error)
- goto end2;
-end2:
- X509_free(cert);
-end1:
- pr_val_debug("}");
- return error;
+end2: X509_free(cert);
+end1: return error;
}
/* rfc6488#section-2.1.6.4.1 */
status = EVP_DecodeUpdate(ctx, result, &outl, (unsigned char *)in, in_len);
if (status == -1)
- return false;
+ goto cancel;
*out_len = outl;
status = EVP_DecodeFinal(ctx, result + outl, &outl);
if (status != 1)
- return false;
+ goto cancel;
+ EVP_ENCODE_CTX_free(ctx);
*out = result;
*out_len += outl;
return true;
+
+cancel: EVP_ENCODE_CTX_free(ctx);
+ return false;
}
/*
free(filename);
}
-static void
+static int
init_tmp_dir(void)
{
char *dirname;
dirname = get_cache_filename(CACHE_TMPDIR, true);
- error = mkdir(dirname, true);
- if (error != EEXIST)
- pr_crit("Cannot create %s: %s", dirname, strerror(error));
+ if (mkdir(dirname, 0777) < 0) {
+ error = errno;
+ if (error != EEXIST)
+ return pr_op_err("Cannot create '%s': %s",
+ dirname, strerror(error));
+ }
free(dirname);
+ return 0;
}
-void
+int
cache_setup(void)
{
init_cache_metafile();
init_tmp_dir();
init_cachedir_tag();
+ return 0;
}
void
return error;
}
- module->flags |= CNF_RSYNC | CNF_CACHED | CNF_FRESH;
+ module->flags |= CNF_RSYNC | CNF_CACHED | CNF_FRESH | CNF_FREE_TMPPATH;
module->mtim = time_nonfatal();
module->tmppath = tmppath;
return error;
}
- node->flags |= CNF_CACHED | CNF_FRESH;
+ node->flags |= CNF_CACHED | CNF_FRESH | CNF_FREE_TMPPATH;
if (changed)
node->mtim = mtim;
node->tmppath = tmppath;
return 0;
}
+static char *
+get_tmppath(struct cache_node *node)
+{
+ struct cache_node *ancestor;
+ struct path_builder pb;
+ size_t skiplen;
+
+ if (node->tmppath != NULL)
+ return node->tmppath;
+
+ ancestor = node;
+ do {
+ ancestor = ancestor->parent;
+ if (ancestor == NULL)
+ pr_crit("aaaaa"); // XXX This should never happen, but maybe don't crash anyway
+ } while (ancestor->tmppath == NULL);
+
+ skiplen = strlen(ancestor->path);
+ if (strncmp(ancestor->path, node->path, skiplen) != 0)
+ return NULL; // XXX
+
+ pb_init(&pb);
+ if (pb_append(&pb, ancestor->tmppath) != 0)
+ goto cancel;
+ if (pb_append(&pb, node->path + skiplen) != 0)
+ goto cancel;
+
+ node->flags |= CNF_FREE_TMPPATH;
+ node->tmppath = pb.string;
+ return pb.string;
+
+cancel: pb_cleanup(&pb);
+ return NULL;
+}
+
/* @uri is either a caRepository or a rpkiNotify */
static int
try_uri(char const *uri, struct cache_node *root,
}
map.url = rpp->url;
- map.path = (download != NULL) ? rpp->tmppath : rpp->path;
+ map.path = (download != NULL) ? get_tmppath(rpp) : rpp->path;
error = validate(&map, arg);
if (error) {
pr_val_debug("RPP validation failed.");
return try_uris(uris, cache.rsync, "rsync://", NULL, cb, arg);
}
-/**
+/*
* XXX outdated comment
*
* Assumes the URIs represent different ways to access the same content.
node->tmppath = NULL;
return true;
-branch: node->flags = 0;
+branch: /* Clean up state flags */
+ node->flags &= ~(CNF_CACHED | CNF_FRESH | CNF_TOUCHED | CNF_VALID);
if (node->tmppath) {
free(node->tmppath);
node->tmppath = NULL;
static int
rmf(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
- if (remove(fpath))
+ if (remove(fpath) < 0)
pr_op_warn("Can't remove %s: %s", fpath, strerror(errno));
else
pr_op_debug("Removed %s.", fpath);
if (pm)
cachent_delete(pm);
unknown:
- if (remove(path))
+ if (remove(path) < 0)
PR_DEBUG_MSG("remove(): %s", strerror(errno)); // XXX
return 0;
}
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;
}
#include "types/map.h"
#include "types/str.h"
-void cache_setup(void); /* Init this module */
+int cache_setup(void); /* Init this module */
void cache_teardown(void); /* Destroy this module */
void cache_prepare(void); /* Prepare cache for new validation cycle */
-void cache_commit(void); /* Finish successful validation cycle */
-/* XXX Huh. Looks like this could use a cache_rollback() */
+void cache_commit(void); /* Finish validation cycle */
struct sia_uris {
char *caRepository; /* RPP cage */
return child;
}
+// XXX path_childn() dup
static char *
inherit_path(char const *parent, char const *name, size_t nlen)
{
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;
*/
#define RSYNC_INHERIT (CNF_RSYNC | CNF_FRESH)
-// XXX rename to cache_entity or cachent
struct cache_node {
char *url; /* rsync://a.b.c/d/e (normalized) */
char *path; /* path/to/cache/rsync/a.b.c/d/e */
struct defer_node {
enum defer_node_type type;
- /**
- * This field is only relevant if @type == PCT_CERT.
+ /*
+ * 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. */
+ /* Used by certstack. Points to the next stacked certificate. */
SLIST_ENTRY(defer_node) next;
};
STATIC_ARRAY_LIST(serial_numbers, struct serial_number)
-/**
- * Cached certificate data.
- */
+/* Cached certificate data */
struct metadata_node {
struct cache_mapping map;
struct resources *resources;
*/
struct serial_numbers serials;
- /** Used by certstack. Points to the next stacked certificate. */
+ /* Used by certstack. Points to the next stacked certificate. */
SLIST_ENTRY(metadata_node) next;
};
-SLIST_HEAD(metadata_stack, metadata_node);
-
-/**
- * This is the foundation through which we pull off our iterative traversal,
- * as opposed to a stack-threatening recursive one.
- *
- * It is a bunch of data that replaces the one that would normally be allocated
- * in the function stack.
- */
+/* Certificates that need to be remembered during a validation cycle. */
struct cert_stack {
- /**
- * Defer stack. Certificates we haven't iterated through yet.
- *
- * Every time a certificate validates successfully, its children are
- * stored here so they can be traversed later.
+ /*
+ * Defer stack; certificates whose validation has been postponed.
+ * (Postponing certificates avoids us recursion and stack overflow.)
*/
struct defer_stack defers;
- /**
- * x509 stack. Parents of the certificate we're currently iterating
- * through.
+ /*
+ * X509 stack. Ancestor certificates of the current certificate.
* Formatted for immediate libcrypto consumption.
*/
STACK_OF(X509) *x509s;
- /**
- * Stacked additional data to each @x509 certificate.
- *
- * (These two stacks should always have the same size. The reason why I
- * don't combine them is because libcrypto's validation function needs
- * the X509 stack, and I'm not creating it over and over again.)
+ /*
+ * Metadata for each X509. Stuff that doesn't fit in libcrypto's struct.
*
- * (This is a SLIST and not a STACK_OF because the OpenSSL stack
- * implementation is different than the LibreSSL one, and the latter is
- * seemingly not intended to be used outside of its library.)
+ * (This is a SLIST and not a STACK_OF because the LibreSSL STACK_OF
+ * is seemingly private.)
*/
- struct metadata_stack metas;
+ SLIST_HEAD(, metadata_node) metas;
};
int
}
static void
-defer_destroy(struct defer_node *defer)
+defer_pop(struct cert_stack *stack)
{
- switch (defer->type) {
- case DNT_SEPARATOR:
- break;
- case DNT_CERT:
- free(defer->deferred.map.url);
- free(defer->deferred.map.path);
+ 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);
- break;
}
-
free(defer);
}
}
static void
-meta_destroy(struct metadata_node *meta)
+meta_pop(struct cert_stack *stack)
{
- free(meta->map.url);
- free(meta->map.path);
+ 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)
{
- unsigned int stack_size;
- struct metadata_node *meta;
- struct defer_node *post;
-
- stack_size = 0;
- while (!SLIST_EMPTY(&stack->defers)) {
- post = SLIST_FIRST(&stack->defers);
- SLIST_REMOVE_HEAD(&stack->defers, next);
- defer_destroy(post);
- stack_size++;
- }
- pr_val_debug("Deleted %u deferred certificates.", stack_size);
+ int n;
+
+ for (n = 0; !SLIST_EMPTY(&stack->defers); n++)
+ defer_pop(stack);
+ pr_val_debug("Deleted %d deferred certificates.", n);
- pr_val_debug("Deleting %d stacked x509s.", sk_X509_num(stack->x509s));
+ n = sk_X509_num(stack->x509s);
sk_X509_pop_free(stack->x509s, X509_free);
+ pr_val_debug("Deleted %d stacked x509s.", n);
- stack_size = 0;
- while (!SLIST_EMPTY(&stack->metas)) {
- meta = SLIST_FIRST(&stack->metas);
- SLIST_REMOVE_HEAD(&stack->metas, next);
- meta_destroy(meta);
- stack_size++;
- }
- pr_val_debug("Deleted %u metadatas.", stack_size);
+ for (n = 0; !SLIST_EMPTY(&stack->metas); n++)
+ meta_pop(stack);
+ pr_val_debug("Deleted %u metadatas.", n);
free(stack);
}
node = pmalloc(sizeof(struct defer_node));
node->type = DNT_CERT;
- node->deferred.map = *map; // XXX
+ map_copy(&node->deferred.map, map);
node->deferred.pp = pp;
rpp_refget(pp);
SLIST_INSERT_HEAD(&stack->defers, node, next);
x509stack_pop(struct cert_stack *stack)
{
X509 *cert;
- struct metadata_node *meta;
cert = sk_X509_pop(stack->x509s);
if (cert == NULL)
pr_crit("Attempted to pop empty X509 stack");
X509_free(cert);
- meta = SLIST_FIRST(&stack->metas);
- if (meta == NULL)
- pr_crit("Attempted to pop empty metadata stack");
- SLIST_REMOVE_HEAD(&stack->metas, next);
- meta_destroy(meta);
+ meta_pop(stack);
}
-/**
- * Contract: Returns either 0 or -ENOENT. No other outcomes.
- */
+/* Contract: Returns either 0 or -ENOENT. No other outcomes. */
int
deferstack_pop(struct cert_stack *stack, struct deferred_cert *result)
{
if (node->type == DNT_SEPARATOR) {
x509stack_pop(stack);
-
- SLIST_REMOVE_HEAD(&stack->defers, next);
- defer_destroy(node);
+ defer_pop(stack);
goto again;
}
*result = node->deferred;
-// uri_refget(node->deferred.uri); // XXX
- rpp_refget(node->deferred.pp);
SLIST_REMOVE_HEAD(&stack->defers, next);
- defer_destroy(node);
+ free(node);
return 0;
}
-bool
-deferstack_is_empty(struct cert_stack *stack)
-{
- return SLIST_EMPTY(&stack->defers);
-}
-
static int
init_resources(X509 *x509, enum rpki_policy policy, enum cert_type type,
struct resources **_result)
return result;
}
-/** Steals ownership of @x509 on success. */
+/* Steals ownership of @x509 on success. */
int
x509stack_push(struct cert_stack *stack, struct cache_mapping *map, X509 *x509,
enum rpki_policy policy, enum cert_type type)
meta = pmalloc(sizeof(struct metadata_node));
- meta->map = *map; // XXX
+ map_copy(&meta->map, map);
serial_numbers_init(&meta->serials);
error = init_resources(x509, policy, type, &meta->resources);
return error;
}
-/**
+/*
* This one is intended to revert a recent x509 push.
* Reverts that particular push.
*
void
x509stack_cancel(struct cert_stack *stack)
{
- struct defer_node *defer_separator;
-
x509stack_pop(stack);
-
- defer_separator = SLIST_FIRST(&stack->defers);
- if (defer_separator == NULL)
- pr_crit("Attempted to pop empty defer stack");
- SLIST_REMOVE_HEAD(&stack->defers, next);
- defer_destroy(defer_separator);
+ defer_pop(stack);
}
X509 *
return sk_X509_value(stack->x509s, sk_X509_num(stack->x509s) - 1);
}
-/** Does not grab reference. */
-struct cache_mapping *
-x509stack_peek_map(struct cert_stack *stack)
-{
- struct metadata_node *meta = SLIST_FIRST(&stack->metas);
- return (meta != NULL) ? &meta->map : NULL;
-}
-
struct resources *
x509stack_peek_resources(struct cert_stack *stack)
{
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.
#include "object/certificate.h"
#include "types/name.h"
-/*
- * One certificate stack is allocated per validation cycle, and it is used
- * through its entirety to hold the certificates relevant to the ongoing
- * validation.
- *
- * Keep in mind: This module deals with two different (but correlated) stack
- * data structures, and they both store "certificates" (albeit in different
- * representations):
- *
- * - Defer stack: This one stores certificates whose validation has been
- * postponed during the validation cycle. (They were found in some manifest
- * list, and haven't been opened yet.)
- * It prevents us from having to validate the RPKI tree in a recursive manner,
- * which would be prone to stack overflow.
- * - x509 stack: It is a chain of certificates, ready to be validated by
- * libcrypto.
- * For any given certificate being validated, this stack stores all of its
- * parents.
- */
-
struct cert_stack;
struct deferred_cert {
void deferstack_push(struct cert_stack *, struct cache_mapping *, struct rpp *);
int deferstack_pop(struct cert_stack *, struct deferred_cert *cert);
-bool deferstack_is_empty(struct cert_stack *);
int x509stack_push(struct cert_stack *, struct cache_mapping *, X509 *,
enum rpki_policy, enum cert_type);
void x509stack_cancel(struct cert_stack *);
X509 *x509stack_peek(struct cert_stack *);
-struct cache_mapping *x509stack_peek_map(struct cert_stack *);
struct resources *x509stack_peek_resources(struct cert_stack *);
void x509stack_store_serial(struct cert_stack *, BIGNUM *);
-typedef int (*subject_pk_check_cb)(bool *, char const *, void *);
-int x509stack_store_subject(struct cert_stack *, struct rfc5280_name *,
- subject_pk_check_cb, void *);
STACK_OF(X509) *certstack_get_x509s(struct cert_stack *);
int certstack_get_x509_num(struct cert_stack *);
* path actually refers to a file.
* So it looks like this stat() is unavoidable.
*/
- if (stat_dir(path) == ENOTDIR && remove(path))
+ if (stat_dir(path) == ENOTDIR && remove(path) < 0)
return errno;
- if (mkdir(path, mode)) {
+ if (mkdir(path, mode) < 0) {
error = errno;
return (error == EEXIST) ? 0 : error;
}
}
if (result == ENOTDIR)
- pr_op_err_st("stack tracing...");
+ pr_op_err_st("stack tracing for '%s'...", path);
for (i = 1; path[i] != '\0'; i++) {
if (path[i] == '/') {
size_t config_len;
int error;
- errno = 0;
- if (remove(path) != 0) {
+ if (remove(path) < 0) {
error = errno;
pr_val_err("Couldn't delete '%s': %s", path, strerror(error));
return error;
{
int error;
- errno = 0;
- if (remove(path) != 0) {
+ if (remove(path) < 0) {
error = errno;
if (error != ENOENT)
return error;
rm(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
pr_op_debug("Deleting %s.", fpath);
- errno = 0;
- return (remove(fpath) != 0) ? errno : 0;
+ return (remove(fpath) < 0) ? errno : 0;
}
/* Same as `system("rm -rf <path>")`, but more portable and maaaaybe faster. */
#include <errno.h>
+#include "cache.h"
#include "config.h"
#include "extension.h"
#include "hash.h"
return error;
}
-/**
+/*
* Shells don't like it when we return values other than 0-255.
* In fact, bash also has its own meanings for 126-255.
* (See man 1 bash > EXIT STATUS)
error = vrps_init();
if (error)
goto revert_relax_ng;
+ error = cache_setup();
+ if (error)
+ goto revert_vrps;
/* Meat */
/* End */
+ cache_teardown();
+revert_vrps:
vrps_destroy();
revert_relax_ng:
relax_ng_cleanup();
static X509_PUBKEY *
decode_spki(struct tal *tal)
{
- X509_PUBKEY *spki = NULL;
+ X509_PUBKEY *spki;
unsigned char const *origin, *cursor;
size_t len;
size_t remaining;
};
-/**
- * Skip the "T" part of a TLV.
- */
+/* Skip the "T" part of a TLV. */
static int
skip_t(ANY_t *content, struct progress *p, unsigned int tag)
{
return 0;
}
-/**
- * Skip the "TL" part of a TLV.
- */
+/* Skip the "TL" part of a TLV. */
static int
skip_tl(ANY_t *content, struct progress *p, unsigned int tag)
{
return 0;
}
-/**
- * A structure that points to the LV part of a signedAttrs TLV.
- */
+/* A structure that points to the LV part of a signedAttrs TLV. */
struct encoded_signedAttrs {
const uint8_t *buffer;
ber_tlv_len_t size;
if (!X509_EXTENSION_get_critical(ext))
return pr_val_err("The IP extension is not marked as critical.");
- pr_val_debug("IP {");
- error = handle_ip_extension(ext, resources);
- pr_val_debug("}");
ip_ext_found = true;
+ error = handle_ip_extension(ext, resources);
if (error)
return error;
if (!X509_EXTENSION_get_critical(ext))
return pr_val_err("The AS extension is not marked as critical.");
- pr_val_debug("ASN {");
- error = handle_asn_extension(ext, resources,
- allow_asn_inherit);
- pr_val_debug("}");
asn_ext_found = true;
+ error = handle_asn_extension(ext, resources,
+ allow_asn_inherit);
if (error)
return error;
return 0;
}
-/**
- * Copies the resources from @cert to @resources.
- */
+/* Copies the resources from @cert to @resources. */
int
certificate_get_resources(X509 *cert, struct resources *resources,
enum cert_type type)
return 0;
}
-/**
+/*
* The RFC does not explain AD validation very well. This is personal
* interpretation, influenced by Tim Bruijnzeels's response
* (https://mailarchive.ietf.org/arch/msg/sidr/4ycmff9jEU4VU9gGK5RyhZ7JYsQ)
return 0;
}
-/**
- * Validates the certificate extensions, Trust Anchor style.
- */
+/* Validates the certificate extensions, Trust Anchor style. */
static int
certificate_validate_extensions_ta(X509 *cert, struct sia_uris *sia_uris,
enum rpki_policy *policy)
return handle_extensions(handlers, X509_get0_extensions(cert));
}
-/**
+/*
* Validates the certificate extensions, (intermediate) Certificate Authority
* style.
*
return error;
}
-/** Boilerplate code for CA certificate validation and recursive traversal. */
+/* Boilerplate code for CA certificate validation and recursive traversal. */
int
certificate_traverse(struct rpp *rpp_parent, struct cache_mapping *cert_map)
{
struct validation *state;
int total_parents;
- STACK_OF(X509_CRL) *rpp_parent_crl;
X509 *x509;
struct sia_uris sia_uris;
enum rpki_policy policy;
if (total_parents >= config_get_max_cert_depth())
return pr_val_err("Certificate chain maximum depth exceeded.");
- /* Debug cert type */
- if (rpp_parent == NULL)
- pr_val_debug("TA Certificate '%s' {",
- map_val_get_printable(cert_map));
- else
- pr_val_debug("Certificate '%s' {",
- map_val_get_printable(cert_map));
fnstack_push_map(cert_map);
- rpp_parent_crl = rpp_crl(rpp_parent);
- if (rpp_parent_crl == NULL) {
- error = -EINVAL;
- goto revert_fnstack_and_debug;
- }
-
/* -- Validate the certificate (@cert) -- */
error = certificate_load(cert_map, &x509);
if (error)
goto revert_fnstack_and_debug;
- error = certificate_validate_chain(x509, rpp_parent_crl);
+ error = certificate_validate_chain(x509, rpp_crl(rpp_parent));
if (error)
goto revert_cert;
X509_free(x509);
revert_fnstack_and_debug:
fnstack_pop();
- pr_val_debug("}");
return error;
}
#include "algorithm.h"
#include "extension.h"
#include "log.h"
+#include "thread_var.h"
#include "types/name.h"
static int
if (bio == NULL)
return val_crypto_err("BIO_new(BIO_s_file()) returned NULL");
if (BIO_read_filename(bio, path) <= 0) {
- error = val_crypto_err("Error reading CRL '%s'", path);
+ error = val_crypto_err("Error reading CRL");
goto end;
}
crl = d2i_X509_CRL_bio(bio, NULL);
if (crl == NULL) {
- error = val_crypto_err("Error parsing CRL '%s'", path);
+ error = val_crypto_err("Error parsing CRL");
goto end;
}
return validate_extensions(crl);
}
-/* XXX I suspect this should receive the map */
int
-crl_load(char const *path, X509_CRL **result)
+crl_load(struct cache_mapping *map, X509_CRL **result)
{
int error;
- pr_val_debug("CRL '%s' {", path);
+ fnstack_push_map(map);
- error = __crl_load(path, result);
+ error = __crl_load(map->path, result);
if (error)
goto end;
if (error)
X509_CRL_free(*result);
-end:
- pr_val_debug("}");
+end: fnstack_pop();
return error;
}
#define SRC_OBJECT_CRL_H_
#include <openssl/x509.h>
+#include "types/map.h"
-int crl_load(char const *, X509_CRL **);
+int crl_load(struct cache_mapping *, X509_CRL **);
#endif /* SRC_OBJECT_CRL_H_ */
int error;
/* Prepare */
- pr_val_debug("Ghostbusters '%s' {", map_val_get_printable(map));
fnstack_push_map(map);
/* Decode */
revert_sobj:
signed_object_cleanup(&sobj);
revert_log:
- pr_val_debug("}");
fnstack_pop();
return error;
}
error = check_file_and_hash(fah, map.path);
if (error)
- goto fail;
+ goto fail2;
error = rpp_add_file(pp, &map);
if (error)
- goto fail;
+ goto fail2;
}
/* rfc6486#section-7 */
*result = pp;
return 0;
+fail2: map_cleanup(&map);
fail: map_cleanup(&pp_map);
rpp_refput(pp);
return error;
int error;
/* Prepare */
- pr_val_debug("Manifest '%s' {", map_val_get_printable(map));
fnstack_push_map(map);
/* Decode */
revert_sobj:
signed_object_cleanup(&sobj);
revert_log:
- pr_val_debug("}");
fnstack_pop();
return error;
}
if (error)
return error;
- pr_val_debug("ROAIPAddress {");
pr_val_debug("address: %s/%u", v4addr2str(&prefix.addr), prefix.len);
if (roa_addr->maxLength != NULL) {
pr_val_err("Error casting ROA's IPv4 maxLength: %s",
strerror(errno));
}
- error = pr_val_err("The ROA's IPv4 maxLength isn't a valid unsigned long");
- goto end_error;
+ return pr_val_err("The ROA's IPv4 maxLength isn't a valid unsigned long");
}
pr_val_debug("maxLength: %lu", max_length);
if (max_length > 32) {
- error = pr_val_err("maxLength (%lu) is out of bounds (0-32).",
+ return pr_val_err("maxLength (%lu) is out of bounds (0-32).",
max_length);
- goto end_error;
}
if (prefix.len > max_length) {
- error = pr_val_err("Prefix length (%u) > maxLength (%lu)",
+ return pr_val_err("Prefix length (%u) > maxLength (%lu)",
prefix.len, max_length);
- goto end_error;
}
} else {
}
if (!resources_contains_ipv4(parent, &prefix)) {
- error = pr_val_err("ROA is not allowed to advertise %s/%u.",
+ return pr_val_err("ROA is not allowed to advertise %s/%u.",
v4addr2str(&prefix.addr), prefix.len);
- goto end_error;
}
- pr_val_debug("}");
return vhandler_handle_roa_v4(asn, &prefix, max_length);
-end_error:
- pr_val_debug("}");
- return error;
}
static int
if (error)
return error;
- pr_val_debug("ROAIPAddress {");
pr_val_debug("address: %s/%u", v6addr2str(&prefix.addr), prefix.len);
if (roa_addr->maxLength != NULL) {
pr_val_err("Error casting ROA's IPv6 maxLength: %s",
strerror(errno));
}
- error = pr_val_err("The ROA's IPv6 maxLength isn't a valid unsigned long");
- goto end_error;
+ return pr_val_err("The ROA's IPv6 maxLength isn't a valid unsigned long");
}
pr_val_debug("maxLength: %lu", max_length);
if (max_length > 128) {
- error = pr_val_err("maxLength (%lu) is out of bounds (0-128).",
+ return pr_val_err("maxLength (%lu) is out of bounds (0-128).",
max_length);
- goto end_error;
}
if (prefix.len > max_length) {
- error = pr_val_err("Prefix length (%u) > maxLength (%lu)",
+ return pr_val_err("Prefix length (%u) > maxLength (%lu)",
prefix.len, max_length);
- goto end_error;
}
} else {
}
if (!resources_contains_ipv6(parent, &prefix)) {
- error = pr_val_err("ROA is not allowed to advertise %s/%u.",
+ return pr_val_err("ROA is not allowed to advertise %s/%u.",
v6addr2str(&prefix.addr), prefix.len);
- goto end_error;
}
- pr_val_debug("}");
return vhandler_handle_roa_v6(asn, &prefix, max_length);
-end_error:
- pr_val_debug("}");
- return error;
}
static int
int a;
int error;
- pr_val_debug("eContent {");
if (roa->version != NULL) {
error = asn_INTEGER2ulong(roa->version, &version);
if (error) {
pr_val_err("Error casting ROA's version: %s",
strerror(errno));
}
- error = pr_val_err("The ROA's version isn't a valid long");
- goto end_error;
+ return pr_val_err("The ROA's version isn't a valid long");
}
/* rfc6482#section-3.1 */
if (version != 0) {
- error = pr_val_err("ROA's version (%lu) is nonzero.",
+ return pr_val_err("ROA's version (%lu) is nonzero.",
version);
- goto end_error;
}
}
pr_val_err("Error casting ROA's AS ID value: %s",
strerror(errno));
}
- error = pr_val_err("ROA's AS ID couldn't be parsed as unsigned long");
- goto end_error;
+ return pr_val_err("ROA's AS ID couldn't be parsed as unsigned long");
}
- if (asn > UINT32_MAX) {
- error = pr_val_err("AS value (%lu) is out of range.", asn);
- goto end_error;
- }
- pr_val_debug("asId: %lu", asn);
+ if (asn > UINT32_MAX)
+ return pr_val_err("AS value (%lu) is out of range.", asn);
/* rfc6482#section-3.3 */
- if (roa->ipAddrBlocks.list.array == NULL) {
- error = pr_val_err("ipAddrBlocks array is NULL.");
- goto end_error;
- }
+ if (roa->ipAddrBlocks.list.array == NULL)
+ return pr_val_err("ipAddrBlocks array is NULL.");
- pr_val_debug("ipAddrBlocks {");
for (b = 0; b < roa->ipAddrBlocks.list.count; b++) {
block = roa->ipAddrBlocks.list.array[b];
- if (block == NULL) {
- error = pr_val_err("Address block array element is NULL.");
- goto ip_error;
- }
+ if (block == NULL)
+ return pr_val_err("Address block array element is NULL.");
if (block->addressFamily.size != 2)
goto family_error;
if (block->addressFamily.buf[0] != 0)
goto family_error;
- if (block->addressFamily.buf[1] != 1
- && block->addressFamily.buf[1] != 2)
+ if (block->addressFamily.buf[1] != 1 &&
+ block->addressFamily.buf[1] != 2)
goto family_error;
- pr_val_debug("%s {",
- block->addressFamily.buf[1] == 1 ? "v4" : "v6");
- if (block->addresses.list.array == NULL) {
- error = pr_val_err("ROA's address list array is NULL.");
- pr_val_debug("}");
- goto ip_error;
- }
+ if (block->addresses.list.array == NULL)
+ return pr_val_err("ROA's address list array is NULL.");
for (a = 0; a < block->addresses.list.count; a++) {
error = ____handle_roa(parent, asn,
block->addressFamily.buf[1],
block->addresses.list.array[a]);
- if (error) {
- pr_val_debug("}");
- goto ip_error;
- }
+ if (error)
+ return error;
}
- pr_val_debug("}");
}
- /* Error 0 it's ok */
- error = 0;
- goto ip_error;
+ return 0;
family_error:
- error = pr_val_err("ROA's IP family is not v4 or v6.");
-ip_error:
- pr_val_debug("}");
-end_error:
- pr_val_debug("}");
- return error;
+ return pr_val_err("ROA's IP family is not v4 or v6.");
}
int
int error;
/* Prepare */
- pr_val_debug("ROA '%s' {", map_val_get_printable(map));
fnstack_push_map(map);
/* Decode */
signed_object_cleanup(&sobj);
revert_log:
fnstack_pop();
- pr_val_debug("}");
return error;
}
if (is_blank(fc))
break;
- // XXX no longer validating schema
- strlist_add(&tal->urls, pstrdup(fc));
+ if (str_starts_with(fc, "https://") ||
+ str_starts_with(fc, "rsync://"))
+ strlist_add(&tal->urls, pstrdup(fc));
fc = nl + cr + 1;
if (*fc == '\0')
return pr_op_err("The TAL seems to end prematurely at line '%s'.", fc);
}
-/**
- * @file_name is expected to outlive the result.
- */
+/* @file_path is expected to outlive @tal. */
static int
tal_init(struct tal *tal, char const *file_path)
{
*len = tal->spki_len;
}
-/**
+/*
* Performs the whole validation walkthrough that starts with Trust Anchor @ta,
* which is assumed to have been extracted from TAL @arg->tal.
*/
struct deferred_cert deferred;
int error;
- pr_val_debug("TAL URI '%s' {", map_val_get_printable(ta));
-
validation_handler.handle_roa_v4 = handle_roa_v4;
validation_handler.handle_roa_v6 = handle_roa_v6;
validation_handler.handle_router_key = handle_router_key;
return ENSURE_NEGATIVE(error);
if (!str_ends_with(ta->url, ".cer")) {
- pr_op_err("TAL URI does not point to a certificate. (Expected .cer, got '%s')",
- ta->url);
+ pr_op_err("TAL URI lacks '.cer' extension: %s", ta->url);
error = EINVAL;
goto end;
}
/* Handle every other certificate. */
certstack = validation_certstack(state);
- if (certstack == NULL)
- pr_crit("Validation state has no certificate stack");
do {
error = deferstack_pop(certstack, &deferred);
} while (true);
end: validation_destroy(state);
- pr_val_debug("}");
return error;
}
args.db = db_table_create();
thread->error = cache_download_uri(&args.tal.urls, handle_ta, &args);
if (thread->error) {
- pr_op_err("None of the URIs of the TAL '%s' yielded a successful traversal.",
- thread->tal_file);
+ pr_op_err("None of the TAL URIs yielded a successful traversal.");
db_table_destroy(args.db);
} else {
thread->db = args.db;
int error = 0;
int tmperr;
- cache_setup();
+ cache_prepare();
/* TODO (fine) Maybe don't spawn threads if there's only one TAL */
if (foreach_file(config_get_tal(), ".tal", true, spawn_tal_thread,
SLIST_REMOVE_HEAD(&threads, next);
thread_destroy(thread);
}
- return NULL;
+
+ /*
+ * Commit even on failure, as there's no reason to throw away
+ * something we recently downloaded if it's marked as valid.
+ */
+ goto end;
}
/* Wait for all */
thread = SLIST_FIRST(&threads);
tmperr = pthread_join(thread->pid, NULL);
if (tmperr)
- pr_crit("pthread_join() threw %d (%s) on the '%s' thread.",
- tmperr, strerror(tmperr), thread->tal_file);
+ pr_crit("pthread_join() threw '%s' on the '%s' thread.",
+ strerror(tmperr), thread->tal_file);
SLIST_REMOVE_HEAD(&threads, next);
if (thread->error) {
error = thread->error;
- pr_op_warn("Validation from TAL '%s' yielded error %d (%s); discarding all validation results.",
- thread->tal_file, error, strerror(abs(error)));
+ pr_op_warn("Validation from TAL '%s' yielded '%s'; "
+ "discarding all validation results.",
+ thread->tal_file, strerror(abs(error)));
}
if (!error) {
thread_destroy(thread);
}
- cache_teardown();
-
- /* If one thread has errors, we can't keep the resulting table. */
+ /* If at least one thread had a fatal error, the table is unusable. */
if (error) {
db_table_destroy(db);
db = NULL;
}
+end: cache_commit();
return db;
}
if (pp->crl.stack != NULL)
return pr_val_err("Repository Publication Point has more than one CRL.");
- error = crl_load(map->path, &crl);
+ error = crl_load(map, &crl);
if (error)
return error;
int
rpp_add_file(struct rpp *pp, struct cache_mapping *map)
{
- if (str_ends_with(map->url, ".crl") == 0)
+ if (str_ends_with(map->url, ".crl"))
return set_crl(pp, map);
filelist_add(&pp->files, map);
STACK_OF(X509_CRL) *
rpp_crl(struct rpp *pp)
{
- return pp->crl.stack;
+ return (pp != NULL) ? pp->crl.stack : NULL;
}
/* Traverses through all of @pp's known files, validating them. */
static void
metadata_cleanup(struct file_metadata *meta)
{
- free(meta->hash);
free(meta->uri);
+ free(meta->hash);
}
static void
if (error)
goto end2;
error = parse_snapshot(&new->session, tmppath, notif);
- delete_file(tmppath);
+// delete_file(tmppath); XXX
end2: free(tmppath);
end1: fnstack_pop();
if (error)
goto end;
error = parse_delta(notif, delta, tmppath, notif_node);
- delete_file(tmppath);
+// delete_file(tmppath); XXX
free(tmppath);
end: fnstack_pop();
if (notif->dlerr)
goto end;
- if (remove(tmppath) == -1) {
- notif->dlerr = errno;
- pr_val_err("Can't remove notification's temporal file: %s",
- strerror(notif->dlerr));
- goto end;
- }
- if (mkdir(tmppath, 0777) == -1) {
- notif->dlerr = errno;
- pr_val_err("Can't create notification's temporal directory: %s",
- strerror(notif->dlerr));
- goto end;
- }
-
+// if (remove(tmppath) < 0) {
+// notif->dlerr = errno;
+// pr_val_err("Can't remove notification's temporal file: %s",
+// strerror(notif->dlerr));
+// update_notification_cleanup(new);
+// goto end;
+// }
+// if (mkdir(tmppath, 0777) < 0) {
+// notif->dlerr = errno;
+// pr_val_err("Can't create notification's temporal directory: %s",
+// strerror(notif->dlerr));
+// update_notification_cleanup(new);
+// goto end;
+// }
+
+ notif->flags |= CNF_FREE_TMPPATH;
notif->tmppath = tmppath;
return true;
}
void
-rrdp_notif_free(struct cachefile_notification *notif)
+rrdp_notif_cleanup(struct cachefile_notification *notif)
{
- if (notif == NULL)
- return;
-
session_cleanup(¬if->session);
+ cachent_delete(notif->subtree);
clear_delta_hashes(notif);
- free(notif);
+}
+
+void
+rrdp_notif_free(struct cachefile_notification *notif)
+{
+ if (notif != NULL) {
+ rrdp_notif_cleanup(notif);
+ free(notif);
+ }
}
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 *);
#endif /* SRC_RRDP_H_ */
pr_op_err("pthread_setspecific() returned %d.", error);
}
-/**
+/*
* Call this function every time you're about to start processing a new file.
* Any pr_op_err()s and friends will now include the new file name.
* Use fnstack_pop() to revert back to the previously stacked file name.
files->filenames[files->len++] = file;
}
-/**
- * See fnstack_push().
- *
- * This function cannot claim a reference for @map, so @map will have to outlive
- * the push/pop.
- */
+/* See fnstack_push(). @map needs to outlive the push/pop. */
void
fnstack_push_map(struct cache_mapping *map)
{
return inet_ntop(af, addr, buffer_cb(state), INET6_ADDRSTRLEN);
}
-/**
+/*
* Returns @addr, converted to a printable string. Intended for minimal clutter
* address printing.
*
return addr2str(AF_INET, addr, validation_get_ip_buffer1);
}
-/**
- * Same as v4addr2str(), except a different buffer is used.
- */
+/* Same as v4addr2str(), except a different buffer is used. */
char const *
v4addr2str2(struct in_addr const *addr)
{
return addr2str(AF_INET, addr, validation_get_ip_buffer2);
}
-/**
- * See v4addr2str().
- */
+/* See v4addr2str(). */
char const *
v6addr2str(struct in6_addr const *addr)
{
return addr2str(AF_INET6, addr, validation_get_ip_buffer1);
}
-/**
- * See v4addr2str2().
- */
+/* See v4addr2str2(). */
char const *
v6addr2str2(struct in6_addr const *addr)
{
return child;
}
+void
+map_copy(struct cache_mapping *dst, struct cache_mapping *src)
+{
+ dst->url = pstrdup(src->url);
+ dst->path = pstrdup(src->path);
+}
+
void
map_cleanup(struct cache_mapping *map)
{
void map_parent(struct cache_mapping *, struct cache_mapping *);
struct cache_mapping *map_child(struct cache_mapping *, char const *);
+void map_copy(struct cache_mapping *, struct cache_mapping *);
void map_cleanup(struct cache_mapping *);
#endif /* SRC_TYPES_MAP_H_ */
serial_test_SOURCES = types/serial_test.c
serial_test_LDADD = ${MY_LDADD}
-tal_test_SOURCES = tal_test.c
+tal_test_SOURCES = object/tal_test.c
tal_test_LDADD = ${MY_LDADD}
thread_pool_test_SOURCES = thread_pool_test.c
MOCK_ABORT_INT(rrdp_update, struct cache_node *notif)
__MOCK_ABORT(rrdp_notif2json, json_t *, NULL, struct cachefile_notification *notif)
+MOCK_ABORT_VOID(rrdp_notif_cleanup, struct cachefile_notification *notif)
MOCK_VOID(rrdp_notif_free, struct cachefile_notification *notif)
MOCK_ABORT_INT(rrdp_json2notif, json_t *json, struct cachefile_notification **result)
MOCK_VOID(__delete_node_cb, struct cache_node const *node)
static char deleted[16][6];
static unsigned int dn;
+MOCK_ABORT_VOID(rrdp_notif_cleanup, struct cachefile_notification *notif)
+
static void
__delete_node_cb(struct cache_node const *node)
{
#include "state.h"
#include "thread_var.h"
-/**
- * Some core functions, as linked from unit tests.
- */
+/* Some core functions, as linked from unit tests. */
MOCK_TRUE(log_val_enabled, unsigned int l)
MOCK_TRUE(log_op_enabled, unsigned int l)
MOCK(config_get_op_log_filename_format, enum filename_format, FNF_NAME, void)
MOCK(config_get_val_log_filename_format, enum filename_format, FNF_NAME, void)
+MOCK_VOID(fnstack_init, void)
MOCK_VOID(fnstack_push, char const *file)
MOCK_VOID(fnstack_push_map, struct cache_mapping *map)
MOCK_VOID(fnstack_pop, void)
+MOCK_VOID(fnstack_cleanup, void)
#include "types/path.c"
#include "types/url.c"
+MOCK_ABORT_VOID(rrdp_notif_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)
/* Mocks */
-MOCK_ABORT_VOID(cache_setup, void)
-MOCK(cache_create, struct rpki_cache *, NULL, void)
-MOCK_VOID(cache_destroy, struct rpki_cache *cache)
-MOCK_ABORT_INT(cache_download_alt, struct sia_uris *sias,
- validate_cb cb, void *arg)
-MOCK_ABORT_INT(cache_tmpfile, char **filename)
-MOCK_ABORT_VOID(cache_teardown, void)
-MOCK_ABORT_INT(certificate_traverse, struct rpp *rpp_parent,
- struct cache_mapping *cert_map)
+MOCK_ABORT_VOID(cache_prepare, void)
+MOCK_ABORT_VOID(cache_commit, void)
MOCK_ABORT_PTR(db_table_create, db_table, void)
MOCK_VOID(db_table_destroy, struct db_table *table)
MOCK_ABORT_INT(db_table_join, struct db_table *dst, struct db_table *src)
test_4urls("resources/tal/4urls-crlf.tal");
test_4urls("resources/tal/4urls-lf-comment.tal");
test_4urls("resources/tal/4urls-lf-comment-utf8.tal");
+ test_4urls("resources/tal/4urls-ignored-protos.tal");
}
END_TEST
--- /dev/null
+rsync://example.com/rpki/ta.cer
+https://example.com/rpki/ta.cer
+ftp://example.com/rpki/ta.cer
+rsync://www.example.com/potato/ta.cer
+http://example.com/rpki/ta.cer
+https://wx3.example.com/tomato/ta.cer
+
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqZEzhYK0+PtDOPfub/KR
+c3MeWx3neXx4/wbnJWGbNAtbYqXg3uU5J4HFzPgk/VIppgSKAhlO0H60DRP48by9
+gr5/yDHu2KXhOmnMg46sYsUIpfgtBS9+VtrqWziJfb+pkGtuOWeTnj6zBmBNZKK+
+5AlMCW1WPhrylIcB+XSZx8tk9GS/3SMQ+YfMVwwAyYjsex14Uzto4GjONALE5oh1
+M3+glRQduD6vzSwOD+WahMbc9vCOTED+2McLHRKgNaQf0YJ9a1jG9oJIvDkKXEqd
+fqDRktwyoD74cV57bW3tBAexB7GglITbInyQAsmdngtfg2LUMrcROHHP86QPZINj
+DQIDAQAB