aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2015-11-29 03:58:51 +0000
committerRob Austein <sra@hactrn.net>2015-11-29 03:58:51 +0000
commit3b93c02c1e50afc7ba5eebe9791f1ee71f10de0e (patch)
tree535c42233f2825a4c1f8bc520b6439e81818e75a
parent2eebc88ed0692b1bb48ab11dde3ed45ed8298096 (diff)
rcynicng caught a bug in rpkid! Router certificates are forbidden
from having SIA extensions, unlike all other RPKI certificates which are required to have them. Start moving RPKI conformance checks which can be performed in Python out of POW.c, tag a bunch more for consideration. svn path=/branches/tk705/; revision=6204
-rw-r--r--ext/POW.c76
-rwxr-xr-xrp/rcynic/rcynicng4
-rw-r--r--rpki/rpkid_tasks.py5
-rw-r--r--rpki/rpkidb/models.py2
-rw-r--r--rpki/x509.py6
5 files changed, 64 insertions, 29 deletions
diff --git a/ext/POW.c b/ext/POW.c
index 654fd76c..9b30c789 100644
--- a/ext/POW.c
+++ b/ext/POW.c
@@ -1229,6 +1229,7 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
* is called in many places where failure to find an issuer is not
* a failure for the calling function. Just leave these alone.
*/
+#warning Could be done in Python
return ok;
case X509_V_ERR_CRL_HAS_EXPIRED:
@@ -1245,7 +1246,11 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
* object being checked is tainted by a stale CRL. So we mark the
* object as tainted and carry on.
*/
+
+#warning Could be done in Python
record_validation_status(status, TAINTED_BY_STALE_CRL);
+
+#warning Should be kept in C
return 1;
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
@@ -1262,6 +1267,7 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
* warned that enabling this feature may cause this program's
* output not to work with other OpenSSL-based applications.
*/
+#warning Could be done in Python
if (allow_non_self_signed_trust_anchor)
ok = 1;
record_validation_status(status, TRUST_ANCHOR_NOT_SELF_SIGNED);
@@ -1271,6 +1277,7 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
* Handle all other OpenSSL verify errors by stuffing an integer
* into the status set.
*/
+#warning Could be done in Python
default:
if (status != Py_None) {
PyObject *value = PyInt_FromLong(ctx->error);
@@ -1297,6 +1304,7 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
* must be of type PrintableString.
*/
+#warning Should be kept in C
static int check_allowed_dn(X509_NAME *dn)
{
X509_NAME_ENTRY *ne;
@@ -1335,6 +1343,7 @@ static int check_allowed_dn(X509_NAME *dn)
* Check whether an ASN.1 TIME value conforms to RFC 5280 4.1.2.5.
*/
+#warning Should be kept in C
static int check_allowed_time_encoding(ASN1_TIME *t)
{
switch (t->type) {
@@ -1351,23 +1360,6 @@ static int check_allowed_time_encoding(ASN1_TIME *t)
}
/*
- * Compare ASN1_TIME values.
- */
-
-static int asn1_time_cmp(ASN1_TIME *t1, ASN1_TIME *t2)
-{
- ASN1_GENERALIZEDTIME *g1 = ASN1_TIME_to_generalizedtime(t1, NULL);
- ASN1_GENERALIZEDTIME *g2 = ASN1_TIME_to_generalizedtime(t2, NULL);
-
- int cmp = ASN1_STRING_cmp(g1, g2);
-
- ASN1_GENERALIZEDTIME_free(g1);
- ASN1_GENERALIZEDTIME_free(g2);
-
- return cmp;
-}
-
-/*
* Compare filename fields of two FileAndHash structures.
*/
@@ -1381,6 +1373,7 @@ static int FileAndHash_name_cmp(const FileAndHash * const *a, const FileAndHash
* form, and matches the issuer.
*/
+#warning Probably could be done in Python
static int check_aki(PyObject *status, const X509 *issuer, const AUTHORITY_KEYID *aki)
{
if (aki == NULL)
@@ -1426,10 +1419,12 @@ static int check_x509(X509 *x,
unsigned ski_hashlen, afi;
int i, ok, crit, loc, ex_count, is_ca, routercert = 0, ret = 0;
+#warning Could be done in Python
if (ASN1_INTEGER_cmp(X509_get_serialNumber(x), asn1_zero) <= 0 ||
ASN1_INTEGER_cmp(X509_get_serialNumber(x), asn1_twenty_octets) > 0)
lose_validation_error_from_code(status, BAD_CERTIFICATE_SERIAL_NUMBER);
+#warning Should remain in C
if (!check_allowed_time_encoding(X509_get_notBefore(x)) ||
!check_allowed_time_encoding(X509_get_notAfter(x)))
lose_validation_error_from_code(status, NONCONFORMANT_ASN1_TIME_VALUE);
@@ -1439,6 +1434,7 @@ static int check_x509(X509 *x,
* API functions for them. We wouldn't bother either if they
* weren't forbidden by the RPKI certificate profile.
*/
+#warning Should remain in C
if (!x->cert_info || x->cert_info->issuerUID || x->cert_info->subjectUID)
lose_validation_error_from_code(status, NONCONFORMANT_CERTIFICATE_UID);
@@ -1503,26 +1499,32 @@ static int check_x509(X509 *x,
routercert |= OBJ_obj2nid(sk_ASN1_OBJECT_value(eku, i)) == NID_id_kp_bgpsec_router;
}
+#warning Could be done in Python
if (X509_get_version(x) != 2)
lose_validation_error_from_code(status, WRONG_OBJECT_VERSION);
+#warning Should remain in C
if (x->cert_info == NULL ||
x->cert_info->signature == NULL ||
x->cert_info->signature->algorithm == NULL ||
OBJ_obj2nid(x->cert_info->signature->algorithm) != NID_sha256WithRSAEncryption)
lose_validation_error_from_code(status, NONCONFORMANT_SIGNATURE_ALGORITHM);
+#warning Could be done in Python
if (x->skid)
ex_count--;
else
lose_validation_error_from_code(status, SKI_EXTENSION_MISSING);
+#warning Should remain in C
if (!check_allowed_dn(X509_get_subject_name(x)))
lose_validation_error_from_code_maybe(allow_nonconformant_name, status, NONCONFORMANT_SUBJECT_NAME);
+#warning Should remain in C
if (!check_allowed_dn(X509_get_issuer_name(x)))
lose_validation_error_from_code_maybe(allow_nonconformant_name, status, NONCONFORMANT_ISSUER_NAME);
+#warning Should remain in C
if ((policies = X509_get_ext_d2i(x, NID_certificate_policies, &crit, NULL)) != NULL) {
POLICYQUALINFO *qualifier = NULL;
POLICYINFO *policy = NULL;
@@ -1539,12 +1541,14 @@ static int check_x509(X509 *x,
goto error;
}
+#warning Should remain in C
if (!X509_EXTENSION_get_critical(X509_get_ext(x, X509_get_ext_by_NID(x, NID_key_usage, -1))) ||
(x->ex_flags & EXFLAG_KUSAGE) == 0 ||
x->ex_kusage != (is_ca ? KU_KEY_CERT_SIGN | KU_CRL_SIGN : KU_DIGITAL_SIGNATURE))
lose_validation_error_from_code(status, BAD_KEY_USAGE);
ex_count--;
+#warning Should remain in C
if (x->rfc3779_addr) {
ex_count--;
if (routercert ||
@@ -1563,6 +1567,7 @@ static int check_x509(X509 *x,
}
}
+#warning Should remain in C
if (x->rfc3779_asid) {
ex_count--;
if ((loc = X509_get_ext_by_NID(x, NID_sbgp_autonomousSysNum, -1)) < 0 ||
@@ -1574,9 +1579,11 @@ static int check_x509(X509 *x,
lose_validation_error_from_code(status, BAD_ASIDENTIFIERS);
}
+#warning Should remain in C
if (!x->rfc3779_addr && !x->rfc3779_asid)
lose_validation_error_from_code(status, MISSING_RESOURCES);
+#warning Should remain in C
subject_pkey = X509_get_pubkey(x);
ok = subject_pkey != NULL;
if (ok) {
@@ -1606,6 +1613,7 @@ static int check_x509(X509 *x,
if (!ok)
lose_validation_error_from_code(status, BAD_PUBLIC_KEY);
+#warning Should remain in C
if (x->skid == NULL ||
(ski_pubkey = X509_get0_pubkey_bitstr(x)) == NULL ||
!EVP_Digest(ski_pubkey->data, ski_pubkey->length,
@@ -1615,12 +1623,14 @@ static int check_x509(X509 *x,
memcmp(ski_hashbuf, x->skid->data, ski_hashlen))
lose_validation_error_from_code(status, SKI_PUBLIC_KEY_MISMATCH);
+#warning Should remain in C (at least partially)
if (x->akid) {
ex_count--;
if (!check_aki(status, issuer, x->akid))
goto error;
}
+#warning Could be done in Python
if (!x->akid && !is_ta)
lose_validation_error_from_code(status, AKI_EXTENSION_MISSING);
@@ -1670,49 +1680,63 @@ static int check_crl(X509_CRL *crl,
EVP_PKEY *pkey;
int i, ret = 0;
+#warning Could be done in Python
if (X509_CRL_get_version(crl) != 1)
lose_validation_error_from_code(status, WRONG_OBJECT_VERSION);
+#warning Should be kept in C
if (!crl->crl || !crl->crl->sig_alg || !crl->crl->sig_alg->algorithm ||
OBJ_obj2nid(crl->crl->sig_alg->algorithm) != NID_sha256WithRSAEncryption)
lose_validation_error_from_code(status, NONCONFORMANT_SIGNATURE_ALGORITHM);
+#warning Should be kept in C
if (!check_allowed_time_encoding(X509_CRL_get_lastUpdate(crl)) ||
!check_allowed_time_encoding(X509_CRL_get_nextUpdate(crl)))
lose_validation_error_from_code(status, NONCONFORMANT_ASN1_TIME_VALUE);
+#warning Could be done in Python
if (X509_cmp_current_time(X509_CRL_get_lastUpdate(crl)) > 0)
lose_validation_error_from_code(status, CRL_NOT_YET_VALID);
+#warning Could be done in Python
if (X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)) < 0)
lose_validation_error_from_code_maybe(allow_stale_crl, status, STALE_CRL_OR_MANIFEST);
+#warning Could be done in Python
if (!check_aki(status, issuer, crl->akid))
goto error;
+#warning Could be done in Python
if (crl->crl_number == NULL)
lose_validation_error_from_code(status, CRL_NUMBER_EXTENSION_MISSING);
+#warning Could be done in Python
if (ASN1_INTEGER_cmp(crl->crl_number, asn1_zero) < 0)
lose_validation_error_from_code(status, CRL_NUMBER_IS_NEGATIVE);
+#warning Could be done in Python
if (ASN1_INTEGER_cmp(crl->crl_number, asn1_twenty_octets) > 0)
lose_validation_error_from_code(status, CRL_NUMBER_OUT_OF_RANGE);
+#warning Should be kept in C
if (X509_CRL_get_ext_count(crl) != 2)
lose_validation_error_from_code(status, DISALLOWED_X509V3_EXTENSION);
+#warning Could be done in Python
if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_subject_name(issuer)))
lose_validation_error_from_code(status, CRL_ISSUER_NAME_MISMATCH);
+#warning Should be kept in C
if (!check_allowed_dn(X509_CRL_get_issuer(crl)))
lose_validation_error_from_code_maybe(allow_nonconformant_name, status, NONCONFORMANT_ISSUER_NAME);
+#warning Should be kept in C
if ((revoked = X509_CRL_get_REVOKED(crl)) != NULL)
for (i = sk_X509_REVOKED_num(revoked) - 1; i >= 0; --i)
if (X509_REVOKED_get_ext_count(sk_X509_REVOKED_value(revoked, i)) > 0)
lose_validation_error_from_code(status, DISALLOWED_X509V3_EXTENSION);
+#warning Should be kept in C
if ((pkey = X509_get_pubkey(issuer)) != NULL) {
ret = X509_CRL_verify(crl, pkey) > 0;
EVP_PKEY_free(pkey);
@@ -1725,6 +1749,7 @@ static int check_crl(X509_CRL *crl,
/*
* Extract one datum from a CMS_SignerInfo.
*/
+#warning Should be kept in C
static void *extract_si_datum(CMS_SignerInfo *si,
int *n,
const int optional,
@@ -1773,9 +1798,11 @@ static int check_cms(CMS_ContentInfo *cms,
X509 *x = NULL;
int i, ret = 0;
+#warning Could be done in Python
if ((crls = CMS_get1_crls(cms)) != NULL)
lose_validation_error_from_code(status, CMS_INCLUDES_CRLS);
+#warning Should be kept in C
if ((signer_infos = CMS_get0_SignerInfos(cms)) == NULL ||
sk_CMS_SignerInfo_num(signer_infos) != 1 ||
(si = sk_CMS_SignerInfo_value(signer_infos, 0)) == NULL ||
@@ -1841,29 +1868,32 @@ static int check_manifest(CMS_ContentInfo *cms,
STACK_OF(X509) *certs = NULL;
int i, ret = 0;
+#warning Could be done in Python
if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_ct_rpkiManifest)
lose_validation_error_from_code(status, BAD_CMS_ECONTENTTYPE);
+#warning Should be kept in C
if (manifest->version)
lose_validation_error_from_code(status, WRONG_OBJECT_VERSION);
+#warning Could be done in Python
if (X509_cmp_current_time(manifest->thisUpdate) > 0)
lose_validation_error_from_code(status, MANIFEST_NOT_YET_VALID);
+#warning Could be done in Python
if (X509_cmp_current_time(manifest->nextUpdate) < 0)
lose_validation_error_from_code_maybe(allow_stale_manifest, status, STALE_CRL_OR_MANIFEST);
+#warning Could be done in Python
if ((certs = CMS_get1_certs(cms)) == NULL || sk_X509_num(certs) != 1)
lose_validation_error_from_code(status, BAD_CMS_SIGNER);
- if (asn1_time_cmp(manifest->thisUpdate, X509_get_notBefore(sk_X509_value(certs, 0))) < 0 ||
- asn1_time_cmp(manifest->nextUpdate, X509_get_notAfter(sk_X509_value(certs, 0))) > 0)
- lose_validation_error_from_code(status, MANIFEST_INTERVAL_OVERRUNS_CERT);
-
+#warning Could be done in Python
if (ASN1_INTEGER_cmp(manifest->manifestNumber, asn1_zero) < 0 ||
ASN1_INTEGER_cmp(manifest->manifestNumber, asn1_twenty_octets) > 0)
lose_validation_error_from_code(status, BAD_MANIFEST_NUMBER);
+#warning Could be done in Python
if (OBJ_obj2nid(manifest->fileHashAlg) != NID_sha256)
lose_validation_error_from_code(status, NONCONFORMANT_DIGEST_ALGORITHM);
@@ -1949,16 +1979,20 @@ static int check_roa(CMS_ContentInfo *cms,
ROAIPAddress *ra;
int i, j, result = 0;
+#warning Could be done in Python
if (OBJ_obj2nid(CMS_get0_eContentType(cms)) != NID_ct_ROA)
lose_validation_error_from_code(status, BAD_CMS_ECONTENTTYPE);
+#warning Should be kept in C
if (roa->version)
lose_validation_error_from_code(status, WRONG_OBJECT_VERSION);
+#warning Could be done in Python
if (ASN1_INTEGER_cmp(roa->asID, asn1_zero) < 0 ||
ASN1_INTEGER_cmp(roa->asID, asn1_four_octets) > 0)
lose_validation_error_from_code(status, BAD_ROA_ASID);
+#warning Could be done in Python
if ((certs = CMS_get1_certs(cms)) == NULL || sk_X509_num(certs) != 1)
lose_validation_error_from_code(status, BAD_CMS_SIGNER);
diff --git a/rp/rcynic/rcynicng b/rp/rcynic/rcynicng
index b98053e2..21cd9b6d 100755
--- a/rp/rcynic/rcynicng
+++ b/rp/rcynic/rcynicng
@@ -357,6 +357,10 @@ class Manifest(rpki.POW.Manifest):
self.nextUpdate = self.getNextUpdate()
self.number = self.getManifestNumber()
self.fah = self.getFiles()
+ self.notBefore = self.ee.getNotBefore()
+ self.notAfter = self.ee.getNotAfter()
+ if self.thisUpdate < self.notBefore or self.nextUpdate > self.notAfter:
+ status.add(codes.MANIFEST_INTERVAL_OVERRUNS_CERT)
codes.normalize(status)
return not any(s.kind == "bad" for s in status)
diff --git a/rpki/rpkid_tasks.py b/rpki/rpkid_tasks.py
index 9759deff..9fe193ae 100644
--- a/rpki/rpkid_tasks.py
+++ b/rpki/rpkid_tasks.py
@@ -586,13 +586,10 @@ class UpdateEECertificatesTask(AbstractTask):
for ca_detail in covering:
logger.debug("%r: No existing EE certificate for %s %s", self, gski, resources)
cn, sn = subject_name.extract_cn_and_sn()
- sia = (None, None,
- ca_detail.ca.sia_uri + subject_key.gSKI() + ".cer",
- ca_detail.ca.parent.repository.rrdp_notification_uri)
cert = ca_detail.issue_ee(
ca = ca_detail.ca,
subject_key = subject_key,
- sia = sia,
+ sia = None,
resources = resources,
notAfter = resources.valid_until,
cn = cn,
diff --git a/rpki/rpkidb/models.py b/rpki/rpkidb/models.py
index c2488738..5fd5785f 100644
--- a/rpki/rpkidb/models.py
+++ b/rpki/rpkidb/models.py
@@ -1845,7 +1845,7 @@ class EECertificate(models.Model):
ca = ca_detail.ca,
subject_key = self.cert.getPublicKey(),
eku = self.cert.get_EKU(),
- sia = (None, None, self.uri, ca_detail.ca.parent.repository.rrdp_notification_uri),
+ sia = None,
resources = resources,
notAfter = resources.valid_until,
cn = cn,
diff --git a/rpki/x509.py b/rpki/x509.py
index 67a597e6..0acb3859 100644
--- a/rpki/x509.py
+++ b/rpki/x509.py
@@ -776,9 +776,9 @@ class X509(DER_object):
Common code to issue an RPKI certificate.
"""
- assert sia and len(sia) == 4 and sia[3]
-
- sia = tuple((str(s),) if isinstance(s, (str, unicode)) else s for s in sia)
+ if sia is not None:
+ assert len(sia) == 4 and sia[3]
+ sia = tuple((str(s),) if isinstance(s, (str, unicode)) else s for s in sia)
now = rpki.sundial.now()
ski = subject_key.get_SKI()