diff options
-rw-r--r-- | rcynic-ng/rcynic.c | 99 |
1 files changed, 53 insertions, 46 deletions
diff --git a/rcynic-ng/rcynic.c b/rcynic-ng/rcynic.c index 3ebaf5ce..f9d96008 100644 --- a/rcynic-ng/rcynic.c +++ b/rcynic-ng/rcynic.c @@ -200,6 +200,7 @@ static const struct { QB(certificate_failed_validation, "Certificate failed validation") \ QB(crl_digest_mismatch, "CRL digest mismatch") \ QB(crl_not_in_manifest, "CRL not listed in manifest") \ + QB(crl_not_yet_valid, "CRL not yet valid") \ QB(crldp_mismatch, "CRLDP doesn't match issuer's SIA") \ QB(crldp_missing, "CRLDP extension missing") \ QB(disallowed_extension, "Disallowed X.509v3 extension") \ @@ -213,7 +214,6 @@ static const struct { QB(malformed_crldp, "Malformed CRDLP extension") \ QB(malformed_roa_addressfamily, "Malformed ROA addressFamily") \ QB(malformed_sia, "Malformed SIA extension") \ - QB(manifest_bad_crl, "Manifest has bad CRL") \ QB(manifest_bad_econtenttype, "Bad manifest eContentType") \ QB(manifest_decode_error, "Manifest decode error") \ QB(manifest_invalid_cms, "Manifest validation failure") \ @@ -248,12 +248,14 @@ static const struct { QB(uri_too_long, "URI too long") \ QW(nonconformant_issuer_name, "Nonconformant X.509 issuer name") \ QW(nonconformant_subject_name, "Nonconformant X.509 subject name") \ - QW(object_not_in_manifest, "Object not in manifest") \ QW(rsync_skipped, "rsync transfer skipped") \ QW(stale_crl, "Stale CRL") \ QW(stale_manifest, "Stale manifest") \ + QW(tainted_by_stale_crl, "Tainted by stale CRL") \ + 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(unknown_object_type, "Unknown object type") \ + QW(unknown_object_type_skipped, "Unknown object type skipped") \ QG(current_cert_recheck, "Certificate rechecked") \ QG(object_accepted, "Object accepted") \ QG(rsync_succeeded, "rsync transfer succeeded") \ @@ -386,7 +388,7 @@ typedef struct walk_ctx { X509 *cert; Manifest *manifest; STACK_OF(OPENSSL_STRING) *filenames; - int manifest_iteration, filename_iteration; + int manifest_iteration, filename_iteration, stale_manifest; walk_state_t state; } walk_ctx_t; @@ -462,7 +464,7 @@ typedef struct rcynic_x509_store_ctx { struct rcynic_ctx { path_t authenticated, old_authenticated, unauthenticated; char *jane, *rsync_program; - STACK_OF(OPENSSL_STRING) *rsync_cache, *backup_cache, *stale_cache, *dead_host_cache; + STACK_OF(OPENSSL_STRING) *rsync_cache, *backup_cache, *dead_host_cache; STACK_OF(validation_status_t) *validation_status; STACK_OF(rsync_ctx_t) *rsync_queue; STACK_OF(task_t) *task_queue; @@ -896,6 +898,7 @@ static void log_validation_status(const rcynic_ctx_t *rc, const object_generation_t generation) { validation_status_t v_, *v = NULL; + int was_set; assert(rc && uri && code < MIB_COUNTER_T_MAX && generation < OBJECT_GENERATION_MAX); @@ -920,16 +923,19 @@ static void log_validation_status(const rcynic_ctx_t *rc, } } + was_set = validation_status_get_code(v, code); + v->timestamp = time(0); validation_status_set_code(v, code, 1); - logmsg(rc, log_verbose, "Recording \"%s\" for %s%s%s", - (mib_counter_desc[code] - ? mib_counter_desc[code] - : X509_verify_cert_error_string(mib_counter_openssl[code])), - (generation != object_generation_null ? object_generation_label[generation] : ""), - (generation != object_generation_null ? " " : ""), - uri->s); + if (!was_set) + logmsg(rc, log_verbose, "Recording \"%s\" for %s%s%s", + (mib_counter_desc[code] + ? mib_counter_desc[code] + : X509_verify_cert_error_string(mib_counter_openssl[code])), + (generation != object_generation_null ? object_generation_label[generation] : ""), + (generation != object_generation_null ? " " : ""), + uri->s); } /** @@ -1349,6 +1355,8 @@ static void walk_ctx_loop_init(const rcynic_ctx_t *rc, STACK_OF(walk_ctx_t) *wsk assert(w->filenames == NULL); w->filenames = directory_filenames(rc, w->state, &w->certinfo.sia); + w->stale_manifest = w->manifest != NULL && X509_cmp_current_time(w->manifest->nextUpdate) < 0; + w->manifest_iteration = 0; w->filename_iteration = 0; w->state++; @@ -2507,6 +2515,17 @@ static X509_CRL *check_crl_1(const rcynic_ctx_t *rc, goto punt; } + if (X509_cmp_current_time(X509_CRL_get_lastUpdate(crl)) > 0) { + log_validation_status(rc, uri, crl_not_yet_valid, generation); + goto punt; + } + + if (X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)) < 0) { + log_validation_status(rc, uri, stale_crl, generation); + if (!rc->allow_stale_crl) + goto punt; + } + if ((pkey = X509_get_pubkey(issuer)) == NULL) goto punt; ret = X509_CRL_verify(crl, pkey); @@ -2665,22 +2684,21 @@ static int check_x509_cb(int ok, X509_STORE_CTX *ctx) case X509_V_ERR_CRL_HAS_EXPIRED: /* - * This may not be an error at all. CRLs don't really "expire", - * although the signatures over them do. What OpenSSL really - * means by this error is just "it's now later than this source - * said it intended to publish a new CRL. Unclear whether this - * should be an error; current theory is that it should not be. + * This isn't really an error, exactly. CRLs don't really + * "expire", although the signatures over them do. What OpenSSL + * really means by this error is just "it's now later than the + * issuer said it intended to publish a new CRL". Whether we + * treat this as an error or not is configurable, see the + * allow_stale_crl parameter. + * + * Deciding whether to allow stale CRLs is check_crl_1()'s job, + * not ours. By the time this callback occurs, we've already + * accepted the CRL; this callback is just notifying us that the + * object being checked is tainted by a stale CRL. So we mark the + * object as tainted and carry on. */ - if (rctx->rc->allow_stale_crl) { - ok = 1; - if (sk_OPENSSL_STRING_find(rctx->rc->stale_cache, rctx->subject->crldp.s) >= 0) - return ok; - if (!sk_OPENSSL_STRING_push_strdup(rctx->rc->stale_cache, rctx->subject->crldp.s)) - logmsg(rctx->rc, log_sys_err, - "Couldn't cache stale CRLDP %s, blundering onward", rctx->subject->crldp.s); - } - log_validation_status(rctx->rc, &rctx->subject->crldp, stale_crl, rctx->subject->generation); - log_validation_status(rctx->rc, &rctx->subject->uri, stale_crl, rctx->subject->generation); + log_validation_status(rctx->rc, &rctx->subject->uri, tainted_by_stale_crl, rctx->subject->generation); + ok = 1; return ok; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: @@ -3065,15 +3083,10 @@ static Manifest *check_manifest_1(const rcynic_ctx_t *rc, goto done; } - if (X509_cmp_current_time(manifest->nextUpdate) < 0 && - sk_OPENSSL_STRING_find(rc->stale_cache, uri->s) < 0) { - if (!sk_OPENSSL_STRING_push_strdup(rc->stale_cache, uri->s)) - logmsg(rc, log_sys_err, "Couldn't cache stale manifest %s, blundering onward", uri->s); - if (!rc->allow_stale_manifest) { - log_validation_status(rc, uri, stale_manifest, generation); - goto done; - } + if (X509_cmp_current_time(manifest->nextUpdate) < 0) { log_validation_status(rc, uri, stale_manifest, generation); + if (!rc->allow_stale_manifest) + goto done; } if (manifest->fileHashAlg == NULL || @@ -3097,10 +3110,8 @@ static Manifest *check_manifest_1(const rcynic_ctx_t *rc, NULL, 0); } - if (!crl) { - log_validation_status(rc, uri, manifest_bad_crl, generation); + if (!crl) goto done; - } if ((crls = sk_X509_CRL_new_null()) == NULL || !sk_X509_CRL_push(crls, crl)) goto done; @@ -3821,7 +3832,9 @@ static void walk_cert(rcynic_ctx_t *rc, STACK_OF(walk_ctx_t) *wsk) } if (hash == NULL) - log_validation_status(rc, &uri, object_not_in_manifest, generation); + log_validation_status(rc, &uri, tainted_by_not_being_in_manifest, generation); + else if (w->stale_manifest) + log_validation_status(rc, &uri, tainted_by_stale_manifest, generation); if (hash == NULL && !rc->allow_object_not_in_manifest) { walk_ctx_loop_next(rc, wsk); @@ -3848,7 +3861,7 @@ static void walk_cert(rcynic_ctx_t *rc, STACK_OF(walk_ctx_t) *wsk) continue; } - log_validation_status(rc, &uri, unknown_object_type, object_generation_null); + log_validation_status(rc, &uri, unknown_object_type_skipped, object_generation_null); walk_ctx_loop_next(rc, wsk); continue; @@ -4146,11 +4159,6 @@ int main(int argc, char *argv[]) goto done; } - if ((rc.stale_cache = sk_OPENSSL_STRING_new(uri_cmp)) == NULL) { - logmsg(&rc, log_sys_err, "Couldn't allocate stale_cache stack"); - goto done; - } - if ((rc.dead_host_cache = sk_OPENSSL_STRING_new(uri_cmp)) == NULL) { logmsg(&rc, log_sys_err, "Couldn't allocate dead_host_cache stack"); goto done; @@ -4477,7 +4485,6 @@ int main(int argc, char *argv[]) */ sk_OPENSSL_STRING_pop_free(rc.rsync_cache, OPENSSL_STRING_free); sk_OPENSSL_STRING_pop_free(rc.backup_cache, OPENSSL_STRING_free); - sk_OPENSSL_STRING_pop_free(rc.stale_cache, OPENSSL_STRING_free); sk_OPENSSL_STRING_pop_free(rc.dead_host_cache, OPENSSL_STRING_free); sk_validation_status_t_pop_free(rc.validation_status, validation_status_t_free); X509_STORE_free(rc.x509_store); |