aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rcynic/rcynic.c251
1 files changed, 160 insertions, 91 deletions
diff --git a/rcynic/rcynic.c b/rcynic/rcynic.c
index 849f939c..83d41ef5 100644
--- a/rcynic/rcynic.c
+++ b/rcynic/rcynic.c
@@ -299,6 +299,7 @@ static const struct {
QW(tainted_by_stale_manifest, "Tainted by stale manifest") \
QW(tainted_by_not_being_in_manifest, "Tainted by not being in manifest") \
QW(trust_anchor_not_self_signed, "Trust anchor not self-signed") \
+ QW(trust_anchor_skipped, "Trust anchor skipped") \
QW(unknown_object_type_skipped, "Unknown object type skipped") \
QW(uri_too_long, "URI too long") \
QW(wrong_cms_si_signature_algorithm, "Wrong CMS SI signature algorithm") \
@@ -527,6 +528,15 @@ typedef struct task {
DECLARE_STACK_OF(task_t)
/**
+ * Trust anchor locator (TAL) fetch context.
+ */
+typedef struct tal_ctx {
+ uri_t uri;
+ path_t path;
+ EVP_PKEY *pkey;
+} tal_ctx_t;
+
+/**
* Extended context for verify callbacks. This is a wrapper around
* OpenSSL's X509_STORE_CTX, and the embedded X509_STORE_CTX @em must be
* the first element of this structure in order for the evil cast to
@@ -2335,6 +2345,39 @@ static int rsync_count_runable(const rcynic_ctx_t *rc)
}
/**
+ * Call rsync context handler, if one is set.
+ */
+static void rsync_call_handler(rcynic_ctx_t *rc,
+ rsync_ctx_t *ctx,
+ const rsync_status_t status)
+{
+ if (!ctx)
+ return;
+
+ switch (status) {
+
+ case rsync_status_pending:
+ case rsync_status_done:
+ break;
+
+ case rsync_status_failed:
+ log_validation_status(rc, &ctx->uri, rsync_transfer_failed, object_generation_null);
+ break;
+
+ case rsync_status_timed_out:
+ log_validation_status(rc, &ctx->uri, rsync_transfer_timed_out, object_generation_null);
+ break;
+
+ case rsync_status_skipped:
+ log_validation_status(rc, &ctx->uri, rsync_transfer_skipped, object_generation_null);
+ break;
+ }
+
+ if (ctx->handler)
+ ctx->handler(rc, ctx, status, &ctx->uri, ctx->cookie);
+}
+
+/**
* Run an rsync process.
*/
static void rsync_run(rcynic_ctx_t *rc,
@@ -2357,8 +2400,7 @@ static void rsync_run(rcynic_ctx_t *rc,
if (rsync_history_uri(rc, &ctx->uri)) {
logmsg(rc, log_verbose, "Late rsync cache hit for %s", ctx->uri.s);
- if (ctx->handler)
- ctx->handler(rc, ctx, rsync_status_done, &ctx->uri, ctx->cookie);
+ rsync_call_handler(rc, ctx, rsync_status_done);
(void) sk_rsync_ctx_t_delete_ptr(rc->rsync_queue, ctx);
free(ctx);
return;
@@ -2455,8 +2497,7 @@ static void rsync_run(rcynic_ctx_t *rc,
ctx->deadline = time(0) + rc->rsync_timeout;
logmsg(rc, log_verbose, "Subprocess %u started, queued %d, runable %d, running %d, max %d, URI %s",
(unsigned) ctx->pid, sk_rsync_ctx_t_num(rc->rsync_queue), rsync_count_runable(rc), rsync_count_running(rc), rc->max_parallel_fetches, ctx->uri.s);
- if (ctx->handler)
- ctx->handler(rc, ctx, rsync_status_pending, &ctx->uri, ctx->cookie);
+ rsync_call_handler(rc, ctx, rsync_status_pending);
return;
}
@@ -2468,8 +2509,7 @@ static void rsync_run(rcynic_ctx_t *rc,
(void) close(pipe_fds[1]);
if (rc->rsync_queue && ctx)
(void) sk_rsync_ctx_t_delete_ptr(rc->rsync_queue, ctx);
- if (ctx && ctx->handler)
- ctx->handler(rc, ctx, rsync_status_failed, &ctx->uri, ctx->cookie);
+ rsync_call_handler(rc, ctx, rsync_status_failed);
if (ctx->pid > 0) {
(void) kill(ctx->pid, SIGKILL);
ctx->pid = 0;
@@ -2693,8 +2733,7 @@ static void rsync_mgr(rcynic_ctx_t *rc)
rsync_status_to_mib_counter(rsync_status),
object_generation_null);
rsync_history_add(rc, ctx, rsync_status);
- if (ctx->handler)
- ctx->handler(rc, ctx, rsync_status, &ctx->uri, ctx->cookie);
+ rsync_call_handler(rc, ctx, rsync_status);
(void) sk_rsync_ctx_t_delete_ptr(rc->rsync_queue, ctx);
free(ctx);
ctx = NULL;
@@ -2843,8 +2882,7 @@ static void rsync_init(rcynic_ctx_t *rc,
if (!sk_rsync_ctx_t_push(rc->rsync_queue, ctx)) {
logmsg(rc, log_sys_err, "Couldn't push rsync state object onto queue, punting %s", ctx->uri.s);
- if (handler)
- handler(rc, ctx, rsync_status_failed, uri, cookie);
+ rsync_call_handler(rc, ctx, rsync_status_failed);
free(ctx);
return;
}
@@ -2856,13 +2894,16 @@ static void rsync_init(rcynic_ctx_t *rc,
}
/**
- * rsync a single file (trust anchor, CRL, manifest, ROA, whatever).
+ * rsync a trust anchor.
*/
-static void rsync_file(rcynic_ctx_t *rc,
- const uri_t *uri)
+static void rsync_ta(rcynic_ctx_t *rc,
+ const uri_t *uri,
+ tal_ctx_t *tctx,
+ void (*handler)(rcynic_ctx_t *, const rsync_ctx_t *,
+ const rsync_status_t, const uri_t *, void *))
{
- assert(!endswith(uri->s, "/"));
- rsync_init(rc, uri, NULL, NULL);
+ assert(endswith(uri->s, ".cer"));
+ rsync_init(rc, uri, tctx, handler);
}
/**
@@ -2870,11 +2911,12 @@ static void rsync_file(rcynic_ctx_t *rc,
*/
static void rsync_tree(rcynic_ctx_t *rc,
const uri_t *uri,
- void *cookie,
- void (*handler)(rcynic_ctx_t *, const rsync_ctx_t *, const rsync_status_t, const uri_t *, void *))
+ STACK_OF(walk_ctx_t) *wsk,
+ void (*handler)(rcynic_ctx_t *, const rsync_ctx_t *,
+ const rsync_status_t, const uri_t *, void *))
{
assert(endswith(uri->s, "/"));
- rsync_init(rc, uri, cookie, handler);
+ rsync_init(rc, uri, wsk, handler);
}
@@ -4747,38 +4789,22 @@ static void rsync_sia_callback(rcynic_ctx_t *rc,
assert(rc && wsk);
- switch (status) {
-
- case rsync_status_pending:
- if (rsync_count_runable(rc) >= rc->max_parallel_fetches)
- return;
-
- if ((wsk = walk_ctx_stack_clone(wsk)) == NULL) {
- logmsg(rc, log_sys_err, "walk_ctx_stack_clone() failed, probably memory exhaustion, blundering onwards without forking stack");
- return;
- }
-
- walk_ctx_stack_pop(wsk);
+ if (status != rsync_status_pending) {
+ w->state++;
task_add(rc, walk_cert, wsk);
return;
+ }
- case rsync_status_failed:
- log_validation_status(rc, uri, rsync_transfer_failed, object_generation_null);
- break;
-
- case rsync_status_timed_out:
- log_validation_status(rc, uri, rsync_transfer_timed_out, object_generation_null);
- break;
-
- case rsync_status_skipped:
- log_validation_status(rc, uri, rsync_transfer_skipped, object_generation_null);
- break;
+ if (rsync_count_runable(rc) >= rc->max_parallel_fetches)
+ return;
- case rsync_status_done:
- break;
+ if ((wsk = walk_ctx_stack_clone(wsk)) == NULL) {
+ logmsg(rc, log_sys_err,
+ "walk_ctx_stack_clone() failed, probably memory exhaustion, blundering onwards without forking stack");
+ return;
}
- w->state++;
+ walk_ctx_stack_pop(wsk);
task_add(rc, walk_cert, wsk);
}
@@ -4954,20 +4980,12 @@ static int check_ta(rcynic_ctx_t *rc, X509 *x, const uri_t *uri,
}
log_validation_status(rc, uri, object_accepted, generation);
-
task_add(rc, walk_cert, wsk);
-
- while (sk_task_t_num(rc->task_queue) > 0 || sk_rsync_ctx_t_num(rc->rsync_queue) > 0) {
- task_run_q(rc);
- rsync_mgr(rc);
- }
-
return 1;
}
-
/**
* Check a trust anchor read from a local file.
*/
@@ -4994,7 +5012,7 @@ static int check_ta_cer(rcynic_ctx_t *rc,
if ((x = read_cert(&path1, NULL)) == NULL) {
log_validation_status(rc, &uri, unreadable_trust_anchor, object_generation_null);
- return 1;
+ goto lose;
}
hash = X509_subject_name_hash(x);
@@ -5017,6 +5035,7 @@ static int check_ta_cer(rcynic_ctx_t *rc,
return check_ta(rc, x, &uri, &path1, &path2, object_generation_null);
lose:
+ log_validation_status(rc, &uri, trust_anchor_skipped, object_generation_null);
X509_free(x);
return 0;
}
@@ -5024,22 +5043,42 @@ static int check_ta_cer(rcynic_ctx_t *rc,
/**
+ * Allocate a new tal_ctx_t.
+ */
+static tal_ctx_t *tal_ctx_t_new(void)
+{
+ tal_ctx_t *tctx = malloc(sizeof(*tctx));
+ if (tctx)
+ memset(tctx, 0, sizeof(*tctx));
+ return tctx;
+}
+
+/**
+ * Free a tal_ctx_t.
+ */
+static void tal_ctx_t_free(tal_ctx_t *tctx)
+{
+ if (tctx) {
+ EVP_PKEY_free(tctx->pkey);
+ free(tctx);
+ }
+}
+
+/**
* Read a trust anchor from disk and compare with known public key.
*
* NB: EVP_PKEY_cmp() returns 1 for match, not 0 like every other
* xyz_cmp() function in the entire OpenSSL library. Go figure.
*/
-static int check_ta_tal_1(rcynic_ctx_t *rc,
- const uri_t *uri,
- const path_t *path2,
- const EVP_PKEY *pkey,
- object_generation_t generation)
+static int check_ta_tal_callback_1(rcynic_ctx_t *rc,
+ const tal_ctx_t *tctx,
+ object_generation_t generation)
{
const path_t *prefix = NULL;
- EVP_PKEY *xpkey = NULL;
+ EVP_PKEY *pkey = NULL;
X509 *x = NULL;
- path_t path1;
+ path_t path;
int ret = 0;
switch (generation) {
@@ -5053,88 +5092,111 @@ static int check_ta_tal_1(rcynic_ctx_t *rc,
goto done;
}
- if (!uri_to_filename(rc, uri, &path1, prefix)) {
- log_validation_status(rc, uri, unreadable_trust_anchor_locator, generation);
+ if (!uri_to_filename(rc, &tctx->uri, &path, prefix)) {
+ log_validation_status(rc, &tctx->uri, unreadable_trust_anchor_locator, generation);
goto done;
}
- if ((x = read_cert(&path1, NULL)) == NULL || (xpkey = X509_get_pubkey(x)) == NULL) {
- log_validation_status(rc, uri, unreadable_trust_anchor, generation);
+ if ((x = read_cert(&path, NULL)) == NULL || (pkey = X509_get_pubkey(x)) == NULL) {
+ log_validation_status(rc, &tctx->uri, unreadable_trust_anchor, generation);
goto done;
}
- if (EVP_PKEY_cmp(pkey, xpkey) != 1) {
- log_validation_status(rc, uri, trust_anchor_key_mismatch, generation);
+ if (EVP_PKEY_cmp(tctx->pkey, pkey) != 1) {
+ log_validation_status(rc, &tctx->uri, trust_anchor_key_mismatch, generation);
goto done;
}
- ret = check_ta(rc, x, uri, &path1, path2, generation);
+ ret = check_ta(rc, x, &tctx->uri, &path, &tctx->path, generation);
x = NULL;
done:
if (!ret)
- log_validation_status(rc, uri, object_rejected, generation);
- EVP_PKEY_free(xpkey);
+ log_validation_status(rc, &tctx->uri, object_rejected, generation);
+ EVP_PKEY_free(pkey);
X509_free(x);
return ret;
}
/**
+ * rsync callback for fetching a TAL.
+ */
+static void rsync_tal_callback(rcynic_ctx_t *rc,
+ const rsync_ctx_t *ctx,
+ const rsync_status_t status,
+ const uri_t *uri,
+ void *cookie)
+{
+ tal_ctx_t *tctx = cookie;
+
+ assert(rc && tctx);
+
+ if (status == rsync_status_pending)
+ return;
+
+ if (!check_ta_tal_callback_1(rc, tctx, object_generation_current) &&
+ !check_ta_tal_callback_1(rc, tctx, object_generation_backup))
+ log_validation_status(rc, &tctx->uri, trust_anchor_skipped, object_generation_null);
+
+ tal_ctx_t_free(tctx);
+}
+
+/**
* Check a trust anchor read from a trust anchor locator (TAL).
*/
static int check_ta_tal(rcynic_ctx_t *rc,
const char *fn)
{
- EVP_PKEY *pkey = NULL;
+ tal_ctx_t *tctx = NULL;
BIO *bio = NULL;
- path_t path2;
int ret = 1;
- uri_t uri;
assert(rc && fn);
logmsg(rc, log_telemetry, "Processing trust anchor locator from file %s", fn);
+ if ((tctx = tal_ctx_t_new()) == NULL) {
+ logmsg(rc, log_sys_err, "malloc(tal_ctxt_t) failed");
+ goto done;
+ }
+
bio = BIO_new_file(fn, "r");
- if (!bio || BIO_gets(bio, uri.s, sizeof(uri.s)) <= 0) {
- filename_to_uri(&uri, fn);
- log_validation_status(rc, &uri, unreadable_trust_anchor_locator, object_generation_null);
+ if (!bio || BIO_gets(bio, tctx->uri.s, sizeof(tctx->uri.s)) <= 0) {
+ uri_t furi;
+ filename_to_uri(&furi, fn);
+ log_validation_status(rc, &furi, unreadable_trust_anchor_locator, object_generation_null);
goto done;
}
- uri.s[strcspn(uri.s, " \t\r\n")] = '\0';
+ tctx->uri.s[strcspn(tctx->uri.s, " \t\r\n")] = '\0';
- if (!uri_to_filename(rc, &uri, &path2, &rc->new_authenticated)) {
- log_validation_status(rc, &uri, unreadable_trust_anchor_locator, object_generation_null);
+ if (!uri_to_filename(rc, &tctx->uri, &tctx->path, &rc->new_authenticated)) {
+ log_validation_status(rc, &tctx->uri, unreadable_trust_anchor_locator, object_generation_null);
goto done;
}
- if (!endswith(uri.s, ".cer")) {
- log_validation_status(rc, &uri, malformed_tal_uri, object_generation_null);
+ if (!endswith(tctx->uri.s, ".cer")) {
+ log_validation_status(rc, &tctx->uri, malformed_tal_uri, object_generation_null);
goto done;
}
bio = BIO_push(BIO_new(BIO_f_linebreak()), bio);
bio = BIO_push(BIO_new(BIO_f_base64()), bio);
if (bio)
- pkey = d2i_PUBKEY_bio(bio, NULL);
- if (!pkey) {
- log_validation_status(rc, &uri, unreadable_trust_anchor_locator, object_generation_null);
+ tctx->pkey = d2i_PUBKEY_bio(bio, NULL);
+ if (!tctx->pkey) {
+ log_validation_status(rc, &tctx->uri, unreadable_trust_anchor_locator, object_generation_null);
goto done;
}
- logmsg(rc, log_telemetry, "Processing trust anchor from URI %s", uri.s);
-
- rsync_file(rc, &uri);
- while (sk_rsync_ctx_t_num(rc->rsync_queue) > 0)
- rsync_mgr(rc);
+ logmsg(rc, log_telemetry, "Processing trust anchor from URI %s", tctx->uri.s);
- ret = (check_ta_tal_1(rc, &uri, &path2, pkey, object_generation_current) ||
- check_ta_tal_1(rc, &uri, &path2, pkey, object_generation_backup));
+ rsync_ta(rc, &tctx->uri, tctx, rsync_tal_callback);
+ tctx = NULL; /* Control has passed */
done:
- EVP_PKEY_free(pkey);
+ tal_ctx_t_free(tctx);
BIO_free_all(bio);
return ret;
}
@@ -5666,6 +5728,13 @@ int main(int argc, char *argv[])
if (*ta_dir.s != '\0' && !check_ta_dir(&rc, ta_dir.s))
goto done;
+ while (sk_task_t_num(rc.task_queue) > 0 || sk_rsync_ctx_t_num(rc.rsync_queue) > 0) {
+ task_run_q(&rc);
+ rsync_mgr(&rc);
+ }
+
+ logmsg(&rc, log_telemetry, "Event loop done, beginning final output and cleanup");
+
if (!finalize_directories(&rc))
goto done;