aboutsummaryrefslogtreecommitdiff
path: root/rcynic
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2012-01-31 22:31:06 +0000
committerRob Austein <sra@hactrn.net>2012-01-31 22:31:06 +0000
commit362b7967c16155f9b24cf257ae7b63bab43c6af6 (patch)
treeeb02a4a81899a108a76c7463d45d1f37cdf2f579 /rcynic
parent5ff8fec168374a6591b2b140a2721c7e9d67e77c (diff)
Refactor CMS checks, which have gotten complex enough to be worth
attempting to share between different kinds of signed objects. This closes #82. svn path=/trunk/; revision=4276
Diffstat (limited to 'rcynic')
-rw-r--r--rcynic/rcynic.c297
1 files changed, 154 insertions, 143 deletions
diff --git a/rcynic/rcynic.c b/rcynic/rcynic.c
index de473a49..c136cebe 100644
--- a/rcynic/rcynic.c
+++ b/rcynic/rcynic.c
@@ -219,6 +219,7 @@ static const struct {
QB(bad_key_usage, "Bad keyUsage") \
QB(bad_manifest_digest_length, "Bad manifest digest length") \
QB(bad_public_key, "Bad public key") \
+ QB(bad_roa_asID, "Bad ROA asID") \
QB(bad_serial_number, "Bad serialNumber") \
QB(certificate_bad_signature, "Bad certificate signature") \
QB(certificate_failed_validation, "Certificate failed validation") \
@@ -253,6 +254,7 @@ static const struct {
QB(nonconformant_signature_algorithm, "Nonconformant signature algorithm")\
QB(nonconformant_digest_algorithm, "Nonconformant digest algorithm") \
QB(object_rejected, "Object rejected") \
+ QB(rfc3779_inheritance_required, "RFC 3779 inheritance required") \
QB(roa_contains_bad_afi_value, "ROA contains bad AFI value") \
QB(roa_resource_not_in_ee, "ROA resource not in EE") \
QB(roa_resources_malformed, "ROA resources malformed") \
@@ -3227,11 +3229,9 @@ static int check_x509(rcynic_ctx_t *rc,
ASN1_BIT_STRING *ski_pubkey = NULL;
STACK_OF(DIST_POINT) *crldp = NULL;
BASIC_CONSTRAINTS *bc = NULL;
- ASIdentifiers *asid = NULL;
- IPAddrBlocks *addr = NULL;
hashbuf_t ski_hashbuf;
unsigned ski_hashlen;
- int ok, crit, ex_count, ret = 0;
+ int ok, crit, loc, ex_count, ret = 0;
assert(rc && wsk && w && uri && x && w->cert);
@@ -3435,23 +3435,28 @@ static int check_x509(rcynic_ctx_t *rc,
}
}
- if ((addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, &crit, NULL)) != NULL) {
+ if (x->rfc3779_addr) {
ex_count--;
- if (!crit || !v3_addr_is_canonical(addr)) {
+ if ((loc = X509_get_ext_by_NID(x, NID_sbgp_ipAddrBlock, -1)) < 0 ||
+ !X509_EXTENSION_get_critical(X509_get_ext(x, loc)) ||
+ !v3_addr_is_canonical(x->rfc3779_addr)) {
log_validation_status(rc, uri, bad_ipaddrblocks, generation);
goto done;
}
}
- if ((asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum, &crit, NULL)) != NULL) {
+ if (x->rfc3779_asid) {
ex_count--;
- if (!crit || !v3_asid_is_canonical(asid)) {
+ if ((loc = X509_get_ext_by_NID(x, NID_sbgp_autonomousSysNum, -1)) < 0 ||
+ !X509_EXTENSION_get_critical(X509_get_ext(x, loc)) ||
+ !v3_asid_is_canonical(x->rfc3779_asid) ||
+ x->rfc3779_asid->rdi != NULL) {
log_validation_status(rc, uri, bad_asidentifiers, generation);
goto done;
}
}
- if (!addr && !asid) {
+ if (!x->rfc3779_addr && !x->rfc3779_asid) {
log_validation_status(rc, uri, missing_resources, generation);
goto done;
}
@@ -3598,6 +3603,130 @@ static int check_x509(rcynic_ctx_t *rc,
}
/**
+ * Check a signed CMS object.
+ */
+static int check_cms(rcynic_ctx_t *rc,
+ STACK_OF(walk_ctx_t) *wsk,
+ const uri_t *uri,
+ path_t *path,
+ const path_t *prefix,
+ CMS_ContentInfo **pcms,
+ X509 **px,
+ certinfo_t *certinfo,
+ BIO *bio,
+ const unsigned char *hash,
+ const size_t hashlen,
+ const unsigned char *expected_eContentType,
+ const size_t expected_eContentType_len,
+ const int require_inheritance,
+ const object_generation_t generation)
+{
+ const ASN1_OBJECT *eContentType = NULL;
+ STACK_OF(CMS_SignerInfo) *signer_infos = NULL;
+ STACK_OF(X509) *signers = NULL;
+ CMS_ContentInfo *cms = NULL;
+ CMS_SignerInfo *si = NULL;
+ ASN1_OCTET_STRING *sid = NULL;
+ X509_NAME *si_issuer = NULL;
+ ASN1_INTEGER *si_serial = NULL;
+ hashbuf_t hashbuf;
+ X509 *x = NULL;
+ certinfo_t certinfo_;
+ int i, result = 0;
+
+ assert(rc && wsk && uri && path && prefix && expected_eContentType);
+
+ if (!certinfo)
+ certinfo = &certinfo_;
+
+ if (!uri_to_filename(rc, uri, path, prefix))
+ goto error;
+
+ if (hash)
+ cms = read_cms(path, &hashbuf);
+ else
+ cms = read_cms(path, NULL);
+
+ if (!cms)
+ goto error;
+
+ if (hash && (hashlen > sizeof(hashbuf.h) ||
+ memcmp(hashbuf.h, hash, hashlen))) {
+ log_validation_status(rc, uri, digest_mismatch, generation);
+ if (!rc->allow_digest_mismatch)
+ goto error;
+ }
+
+ if (!(eContentType = CMS_get0_eContentType(cms)) ||
+ oid_cmp(eContentType, expected_eContentType,
+ expected_eContentType_len)) {
+ log_validation_status(rc, uri, bad_cms_econtenttype, generation);
+ goto error;
+ }
+
+ if (CMS_verify(cms, NULL, NULL, NULL, bio, CMS_NO_SIGNER_CERT_VERIFY) <= 0) {
+ log_validation_status(rc, uri, cms_validation_failure, generation);
+ goto error;
+ }
+
+ if (!(signers = CMS_get0_signers(cms)) || sk_X509_num(signers) != 1 ||
+ (x = sk_X509_value(signers, 0)) == NULL) {
+ log_validation_status(rc, uri, cms_signer_missing, generation);
+ goto error;
+ }
+
+ if ((signer_infos = CMS_get0_SignerInfos(cms)) == NULL ||
+ sk_CMS_SignerInfo_num(signer_infos) != 1 ||
+ (si = sk_CMS_SignerInfo_value(signer_infos, 0)) == NULL ||
+ !CMS_SignerInfo_get0_signer_id(si, &sid, &si_issuer, &si_serial) ||
+ sid == NULL || si_issuer != NULL || si_serial != NULL) {
+ log_validation_status(rc, uri, bad_cms_signer_infos, generation);
+ goto error;
+ }
+
+ if (CMS_SignerInfo_cert_cmp(si, x)) {
+ log_validation_status(rc, uri, cms_ski_mismatch, generation);
+ goto error;
+ }
+
+ if (!check_x509(rc, wsk, uri, x, certinfo, generation))
+ goto error;
+
+ if (require_inheritance && x->rfc3779_addr) {
+ for (i = 0; i < sk_IPAddressFamily_num(x->rfc3779_addr); i++) {
+ IPAddressFamily *f = sk_IPAddressFamily_value(x->rfc3779_addr, i);
+ if (f->ipAddressChoice->type != IPAddressChoice_inherit) {
+ log_validation_status(rc, uri, rfc3779_inheritance_required, generation);
+ goto error;
+ }
+ }
+ }
+
+ if (require_inheritance && x->rfc3779_asid && x->rfc3779_asid->asnum &&
+ x->rfc3779_asid->asnum->type != ASIdentifierChoice_inherit) {
+ log_validation_status(rc, uri, rfc3779_inheritance_required, generation);
+ goto error;
+ }
+
+ if (pcms) {
+ *pcms = cms;
+ cms = NULL;
+ }
+
+ if (px)
+ *px = x;
+
+ result = 1;
+
+ error:
+ CMS_ContentInfo_free(cms);
+
+ return result;
+}
+
+
+
+/**
* Load certificate, check against manifest, then run it through all
* the check_x509() tests.
*/
@@ -3707,43 +3836,21 @@ static Manifest *check_manifest_1(rcynic_ctx_t *rc,
const object_generation_t generation)
{
Manifest *manifest = NULL, *result = NULL;
- const ASN1_OBJECT *eContentType = NULL;
- STACK_OF(X509) *signers = NULL;
CMS_ContentInfo *cms = NULL;
FileAndHash *fah = NULL;
BIO *bio = NULL;
- X509 *ee;
+ X509 *x;
int i;
assert(rc && wsk && uri && path && prefix);
- if (!uri_to_filename(rc, uri, path, prefix) ||
- (cms = read_cms(path, NULL)) == NULL)
- goto done;
-
- if ((eContentType = CMS_get0_eContentType(cms)) == NULL ||
- oid_cmp(eContentType, id_ct_rpkiManifest, sizeof(id_ct_rpkiManifest))) {
- log_validation_status(rc, uri, bad_cms_econtenttype, generation);
- goto done;
- }
-
if ((bio = BIO_new(BIO_s_mem())) == NULL) {
logmsg(rc, log_sys_err, "Couldn't allocate BIO for manifest %s", uri->s);
goto done;
}
- if (CMS_verify(cms, NULL, NULL, NULL, bio, CMS_NO_SIGNER_CERT_VERIFY) <= 0) {
- log_validation_status(rc, uri, cms_validation_failure, generation);
- goto done;
- }
-
- if ((signers = CMS_get0_signers(cms)) == NULL || sk_X509_num(signers) != 1 ||
- (ee = sk_X509_value(signers, 0)) == NULL) {
- log_validation_status(rc, uri, cms_signer_missing, generation);
- goto done;
- }
-
- if (!check_x509(rc, wsk, uri, ee, certinfo, generation))
+ if (!check_cms(rc, wsk, uri, path, prefix, &cms, &x, certinfo, bio, NULL, 0,
+ id_ct_rpkiManifest, sizeof(id_ct_rpkiManifest), 1, generation))
goto done;
if ((manifest = ASN1_item_d2i_bio(ASN1_ITEM_rptr(Manifest), bio, NULL)) == NULL) {
@@ -3793,7 +3900,6 @@ static Manifest *check_manifest_1(rcynic_ctx_t *rc,
BIO_free(bio);
Manifest_free(manifest);
CMS_ContentInfo_free(cms);
- sk_X509_free(signers);
return result;
}
@@ -3949,21 +4055,12 @@ static int check_roa_1(rcynic_ctx_t *rc,
const size_t hashlen,
const object_generation_t generation)
{
- unsigned char addrbuf[ADDR_RAW_BUF_LEN];
- const ASN1_OBJECT *eContentType = NULL;
STACK_OF(IPAddressFamily) *roa_resources = NULL, *ee_resources = NULL;
- STACK_OF(CMS_SignerInfo) *signer_infos = NULL;
- STACK_OF(X509) *signers = NULL;
+ unsigned char addrbuf[ADDR_RAW_BUF_LEN];
CMS_ContentInfo *cms = NULL;
- CMS_SignerInfo *si = NULL;
- ASN1_OCTET_STRING *sid = NULL;
- X509_NAME *si_issuer = NULL;
- ASN1_INTEGER *si_serial = NULL;
- hashbuf_t hashbuf;
- ROA *roa = NULL;
BIO *bio = NULL;
+ ROA *roa = NULL;
X509 *x = NULL;
- certinfo_t certinfo;
int i, j, result = 0;
unsigned afi, *safi = NULL, safi_, prefixlen;
ROAIPAddressFamily *rf;
@@ -3971,62 +4068,14 @@ static int check_roa_1(rcynic_ctx_t *rc,
assert(rc && wsk && uri && path && prefix);
- if (!uri_to_filename(rc, uri, path, prefix))
- goto error;
-
- if (hash)
- cms = read_cms(path, &hashbuf);
- else
- cms = read_cms(path, NULL);
-
- if (!cms)
- goto error;
-
- if (hash && (hashlen > sizeof(hashbuf.h) ||
- memcmp(hashbuf.h, hash, hashlen))) {
- log_validation_status(rc, uri, digest_mismatch, generation);
- if (!rc->allow_digest_mismatch)
- goto error;
- }
-
- if (!(eContentType = CMS_get0_eContentType(cms)) ||
- oid_cmp(eContentType, id_ct_routeOriginAttestation,
- sizeof(id_ct_routeOriginAttestation))) {
- log_validation_status(rc, uri, bad_cms_econtenttype, generation);
- goto error;
- }
-
if ((bio = BIO_new(BIO_s_mem())) == NULL) {
logmsg(rc, log_sys_err, "Couldn't allocate BIO for ROA %s", uri->s);
goto error;
}
- if (CMS_verify(cms, NULL, NULL, NULL, bio, CMS_NO_SIGNER_CERT_VERIFY) <= 0) {
- log_validation_status(rc, uri, cms_validation_failure, generation);
- goto error;
- }
-
- if (!(signers = CMS_get0_signers(cms)) || sk_X509_num(signers) != 1 ||
- (x = sk_X509_value(signers, 0)) == NULL) {
- log_validation_status(rc, uri, cms_signer_missing, generation);
- goto error;
- }
-
- if ((signer_infos = CMS_get0_SignerInfos(cms)) == NULL ||
- sk_CMS_SignerInfo_num(signer_infos) != 1 ||
- (si = sk_CMS_SignerInfo_value(signer_infos, 0)) == NULL ||
- !CMS_SignerInfo_get0_signer_id(si, &sid, &si_issuer, &si_serial) ||
- sid == NULL || si_issuer != NULL || si_serial != NULL) {
- log_validation_status(rc, uri, bad_cms_signer_infos, generation);
- goto error;
- }
-
- if (CMS_SignerInfo_cert_cmp(si, x)) {
- log_validation_status(rc, uri, cms_ski_mismatch, generation);
- goto error;
- }
-
- if (!check_x509(rc, wsk, uri, x, &certinfo, generation))
+ if (!check_cms(rc, wsk, uri, path, prefix, &cms, &x, NULL, bio, NULL, 0,
+ id_ct_routeOriginAttestation, sizeof(id_ct_routeOriginAttestation),
+ 0, generation))
goto error;
if (!(roa = ASN1_item_d2i_bio(ASN1_ITEM_rptr(ROA), bio, NULL))) {
@@ -4039,12 +4088,12 @@ static int check_roa_1(rcynic_ctx_t *rc,
goto error;
}
- /*
- * ROA issuer doesn't need rights to the ASN, so we don't need to
- * check the asID field.
- */
+ if (ASN1_INTEGER_cmp(roa->asID, asn1_zero) < 0) {
+ log_validation_status(rc, uri, bad_roa_asID, generation);
+ goto error;
+ }
- ee_resources = X509_get_ext_d2i(sk_X509_value(signers, 0), NID_sbgp_ipAddrBlock, NULL, NULL);
+ ee_resources = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
/*
* Extract prefixes from ROA and convert them into a resource set.
@@ -4134,7 +4183,6 @@ static int check_roa_1(rcynic_ctx_t *rc,
BIO_free(bio);
ROA_free(roa);
CMS_ContentInfo_free(cms);
- sk_X509_free(signers);
sk_IPAddressFamily_pop_free(roa_resources, IPAddressFamily_free);
sk_IPAddressFamily_pop_free(ee_resources, IPAddressFamily_free);
@@ -4199,41 +4247,13 @@ static int check_ghostbuster_1(rcynic_ctx_t *rc,
const size_t hashlen,
const object_generation_t generation)
{
- const ASN1_OBJECT *eContentType = NULL;
- STACK_OF(X509) *signers = NULL;
CMS_ContentInfo *cms = NULL;
- hashbuf_t hashbuf;
BIO *bio = NULL;
- certinfo_t certinfo;
+ X509 *x;
int result = 0;
assert(rc && wsk && uri && path && prefix);
- if (!uri_to_filename(rc, uri, path, prefix))
- goto error;
-
- if (hash)
- cms = read_cms(path, &hashbuf);
- else
- cms = read_cms(path, NULL);
-
- if (!cms)
- goto error;
-
- if (hash && (hashlen > sizeof(hashbuf.h) ||
- memcmp(hashbuf.h, hash, hashlen))) {
- log_validation_status(rc, uri, digest_mismatch, generation);
- if (!rc->allow_digest_mismatch)
- goto error;
- }
-
- if (!(eContentType = CMS_get0_eContentType(cms)) ||
- oid_cmp(eContentType, id_ct_rpkiGhostbusters,
- sizeof(id_ct_rpkiGhostbusters))) {
- log_validation_status(rc, uri, bad_cms_econtenttype, generation);
- goto error;
- }
-
#if 0
/*
* May want this later if we're going to inspect the VCard. For now,
@@ -4245,15 +4265,10 @@ static int check_ghostbuster_1(rcynic_ctx_t *rc,
}
#endif
- if (CMS_verify(cms, NULL, NULL, NULL, bio, CMS_NO_SIGNER_CERT_VERIFY) <= 0) {
- log_validation_status(rc, uri, cms_validation_failure, generation);
+ if (!check_cms(rc, wsk, uri, path, prefix, &cms, &x, NULL, bio, NULL, 0,
+ id_ct_rpkiGhostbusters, sizeof(id_ct_rpkiGhostbusters),
+ 1, generation))
goto error;
- }
-
- if (!(signers = CMS_get0_signers(cms)) || sk_X509_num(signers) != 1) {
- log_validation_status(rc, uri, cms_signer_missing, generation);
- goto error;
- }
#if 0
/*
@@ -4262,15 +4277,11 @@ static int check_ghostbuster_1(rcynic_ctx_t *rc,
*/
#endif
- if (!check_x509(rc, wsk, uri, sk_X509_value(signers, 0), &certinfo, generation))
- goto error;
-
result = 1;
error:
BIO_free(bio);
CMS_ContentInfo_free(cms);
- sk_X509_free(signers);
return result;
}