diff options
author | Rob Austein <sra@hactrn.net> | 2008-06-20 01:04:51 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2008-06-20 01:04:51 +0000 |
commit | 85e728762f8631def71a25b0754a55efa023d0de (patch) | |
tree | 77b6ef5152a94f5a013cb12b9f346c4ff1c4a52f | |
parent | 9892d5f9a8404c52cfd92b18445acd38a19ec807 (diff) |
Checkpoint
svn path=/rcynic/rcynic.c; revision=1907
-rw-r--r-- | rcynic/rcynic.c | 97 |
1 files changed, 76 insertions, 21 deletions
diff --git a/rcynic/rcynic.c b/rcynic/rcynic.c index 46e3465e..ad890c9b 100644 --- a/rcynic/rcynic.c +++ b/rcynic/rcynic.c @@ -170,6 +170,11 @@ static const struct { QQ(aia_mismatch, "Mismatched AIA extensions") \ QQ(unknown_verify_error, "Unknown OpenSSL verify error") \ QQ(current_cert_recheck, "Certificates rechecked") \ + QQ(manifest_invalid_ee, "Invalid manifest certificates") \ + QQ(manifest_invalid_cms, "Manifest validation failures") \ + QQ(manifest_decode_error, "Manifest decode errors") \ + QQ(stale_manifest, "Stale manifests") \ + QQ(manifest_not_yet_valid, "Manifests not yet valid") \ MIB_COUNTERS_FROM_OPENSSL #define QV(x) QQ(mib_openssl_##x, 0) @@ -218,8 +223,8 @@ typedef struct rcynic_ctx { char *authenticated, *old_authenticated, *unauthenticated; char *jane, *rsync_program; STACK *rsync_cache, *host_counters, *backup_cache; - int indent, rsync_timeout, use_syslog, allow_stale_crl, use_links; - int priority[LOG_LEVEL_T_MAX]; + int indent, use_syslog, allow_stale_crl, allow_stale_manifest, use_links; + int rsync_timeout, priority[LOG_LEVEL_T_MAX]; log_level_t log_level; X509_STORE *x509_store; } rcynic_ctx_t; @@ -532,6 +537,18 @@ static int uri_to_filename(const char *name, } /* + * OID comparison. + */ +static int oid_cmp(const ASN1_OBJECT *obj, const unsigned char *oid, const size_t oidlen) +{ + assert(obj != NULL && oid != NULL); + if (obj->length != oidlen) + return obj->length - oidlen; + else + return memcmp(obj->data, oid, oidlen); +} + +/* * Host MIB counter comparision. This relies on hostname[] being the * first element of a host_mib_counter_t, hence the (unreadable, but * correct ANSI/ISO C) assertion. Given all the icky casts involved @@ -1223,8 +1240,7 @@ static void extract_access_uri(const AUTHORITY_INFO_ACCESS *xia, assert(a != NULL); if (a->location->type != GEN_URI) return; - if (a->method->length == oidlen && - !memcmp(a->method->data, oid, oidlen) && + if (!oid_cmp(a->method, oid, oidlen) && is_rsync((char *) a->location->d.uniformResourceIdentifier->data) && urilen > a->location->d.uniformResourceIdentifier->length) { strcpy(uri, (char *) a->location->d.uniformResourceIdentifier->data); @@ -1357,7 +1373,10 @@ static Manifest *check_manifest_1(const rcynic_ctx_t *rc, const char *prefix, STACK_OF(X509) *certs) { + const unsigned char id_ct_rpkiManifest[] = {0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x1a}; + const unsigned char id_sha256[] = {0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}; CMS_ContentInfo *cms = NULL; + const ASN1_OBJECT *eContentType = NULL; STACK_OF(X509) *signers = NULL; STACK_OF(X509_CRL) *crls = NULL; X509_CRL *crl = NULL; @@ -1372,6 +1391,10 @@ static Manifest *check_manifest_1(const rcynic_ctx_t *rc, (cms = read_cms(path, NULL, 0)) == NULL) goto done1; + if ((eContentType = CMS_get0_eContentType(cms)) == NULL || + oid_cmp(eContentType, id_ct_rpkiManifest, sizeof(id_ct_rpkiManifest))) + goto done1; + if ((signers = CMS_get0_signers(cms)) == NULL || sk_X509_num(signers) != 1) goto done1; @@ -1408,7 +1431,8 @@ static Manifest *check_manifest_1(const rcynic_ctx_t *rc, OBJ_txt2obj("1.3.6.1.5.5.7.14.2", 0)); if (X509_verify_cert(&rctx.ctx) <= 0) { - logmsg(rc, log_data_err, "Validation failure for CMS EE certificate"); + logmsg(rc, log_data_err, "Validation failure for manifest EE certificate"); + mib_increment(rc, uri, manifest_invalid_ee); goto done2; } @@ -1416,22 +1440,43 @@ static Manifest *check_manifest_1(const rcynic_ctx_t *rc, goto done2; if (CMS_verify(cms, NULL, NULL, NULL, bio, CMS_NO_SIGNER_CERT_VERIFY) <= 0) { - logmsg(rc, log_data_err, "Validation failure for CMS message"); + logmsg(rc, log_data_err, "Validation failure for manifest CMS message"); + mib_increment(rc, uri, manifest_invalid_cms); goto done2; } if ((manifest = ASN1_item_d2i_bio(ASN1_ITEM_rptr(Manifest), bio, NULL)) == NULL) { logmsg(rc, log_data_err, "Failure decoding manifest"); + mib_increment(rc, uri, manifest_decode_error); goto done2; } - /* - * Still need to check manifest internals for sanity (dates, etc). - */ + if (X509_cmp_current_time(manifest->thisUpdate) > 0) { + logmsg(rc, log_data_err, "Manifest not yet valid"); + mib_increment(rc, uri, manifest_not_yet_valid); + goto done2; + } + + if (X509_cmp_current_time(manifest->nextUpdate) < 0) { + logmsg(rc, log_data_err, "Stale manifest"); + mib_increment(rc, uri, stale_manifest); + if (!rc->allow_stale_manifest) + goto done2; + } + + if (manifest->fileHashAlg == NULL || + oid_cmp(manifest->fileHashAlg, id_sha256, sizeof(id_sha256))) + goto done2; + +#warning Still need to check CRL against manifest + + result = manifest; + manifest = NULL; done2: X509_STORE_CTX_cleanup(&rctx.ctx); BIO_free(bio); + Manifest_free(manifest); done1: CMS_ContentInfo_free(cms); @@ -1443,22 +1488,27 @@ static Manifest *check_manifest_1(const rcynic_ctx_t *rc, static Manifest *check_manifest(const rcynic_ctx_t *rc, const char *uri, - STACK_OF(X509) *certs, - X509_CRL *crl) + STACK_OF(X509) *certs) { + CMS_ContentInfo *cms = NULL; + Manifest *manifest = NULL; char path[FILENAME_MAX]; - Manifest *manifest; + BIO *bio = NULL; -#if 0 - /* - * This snippet should just read a manifest that's already been - * checked, without verifying it. We could write such a function, - * but let's see if we need it first.... - */ - if (uri_to_filename(uri, path, sizeof(path), rc->authenticated) && - (manifest = read_manifest(path, NULL, 0)) != NULL) + if (uri_to_filename(uri, path, sizeof(path), rc->authenticated) && + (cms = read_cms(path, NULL, 0)) != NULL && + (bio = BIO_new(BIO_s_mem()))!= NULL && + CMS_verify(cms, NULL, NULL, NULL, bio, + CMS_NO_SIGNER_CERT_VERIFY | + CMS_NO_ATTR_VERIFY | + CMS_NO_CONTENT_VERIFY) > 0) + manifest = ASN1_item_d2i_bio(ASN1_ITEM_rptr(Manifest), bio, NULL); + + CMS_ContentInfo_free(cms); + BIO_free(bio); + + if (manifest != NULL) return manifest; -#endif logmsg(rc, log_telemetry, "Checking manifest %s", uri); @@ -1850,6 +1900,7 @@ int main(int argc, char *argv[]) set_directory(&rc.unauthenticated, "rcynic-data/unauthenticated/"); rc.log_level = log_telemetry; rc.allow_stale_crl = 1; + rc.allow_stale_manifest = 1; #define QQ(x,y) rc.priority[x] = y; LOG_LEVELS; @@ -1970,6 +2021,10 @@ int main(int argc, char *argv[]) !configure_boolean(&rc, &rc.allow_stale_crl, val->value)) goto done; + else if (!name_cmp(val->name, "allow-stale-manifest") && + !configure_boolean(&rc, &rc.allow_stale_manifest, val->value)) + goto done; + else if (!name_cmp(val->name, "use-links") && !configure_boolean(&rc, &rc.use_links, val->value)) goto done; |