aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/POW.c386
-rwxr-xr-xrp/rcynic/rcynicng57
-rw-r--r--rpki/POW/__init__.py3
3 files changed, 194 insertions, 252 deletions
diff --git a/ext/POW.c b/ext/POW.c
index 50844afa..88a694ab 100644
--- a/ext/POW.c
+++ b/ext/POW.c
@@ -314,17 +314,6 @@ static int x509_store_ctx_ex_data_idx = -1;
static const ASN1_INTEGER *asn1_zero, *asn1_four_octets, *asn1_twenty_octets;
-#warning TEMPORARY REPLACEMENTS FOR RUNTIME CONTROL FLAGS
-/*
- * These should become bit flags to the _verify() functions, or something.
- */
-
-static const int
- allow_nonconformant_name = 1,
- allow_1024_bit_ee_key = 1,
- allow_wrong_cms_si_attributes = 1,
- allow_non_self_signed_trust_anchor = 0;
-
/*
* Declarations of type objects (definitions come later).
*/
@@ -476,23 +465,6 @@ typedef struct {
goto error; \
} while (0)
-#define lose_validation_error_from_code(_status_, _code_) \
- do { \
- if (_record_validation_status(_status_, #_code_)) \
- PyErr_SetString(ValidationErrorObject, #_code_); \
- goto error; \
- } while (0)
-
-#define lose_validation_error_from_code_maybe(_test_, _status_, _code_) \
- do { \
- if (!_record_validation_status(_status_, #_code_)) \
- goto error; \
- if (_test_) \
- break; \
- PyErr_SetString(ValidationErrorObject, #_code_); \
- goto error; \
- } while (0)
-
#define assert_no_unhandled_openssl_errors() \
do { \
if (ERR_peek_error()) { \
@@ -1177,17 +1149,20 @@ whack_ec_key_to_namedCurve(EVP_PKEY *pkey)
* Validation status codes. Still under construction. Conceptually
* modeled after rcynic's validation status database, implementation
* somewhat different due to language issues and desire to keep the C
- * side of this as simple as possible. Depends on suppot from the
+ * side of this as simple as possible. Depends on support from the
* Python side (see rpki/POW/__init__.py).
*/
/*
- * Add code to status object, return C boolean indicating success.
- * Do nothing and return success if the status object is None.
+ * Add code to status object, throwing an error if something goes
+ * horribly wrong.
*/
-#define record_validation_status(_status_, _code_) \
- _record_validation_status(_status_, #_code_)
+#define record_validation_status(_status_, _code_) \
+ do { \
+ if (!_record_validation_status(_status_, #_code_)) \
+ goto error; \
+ } while (0)
static int
_record_validation_status(PyObject *status, const char *code)
@@ -1205,12 +1180,14 @@ _record_validation_status(PyObject *status, const char *code)
/*
* Validation callback code for use with x509_verify_cert().
*
- * In theory record_validation_status() can throw an exception, but
- * there's no direct way to handle that here, so we're depending on
- * x509_store_object_verify() calling PyErr_Occurred() to check (which
- * it has to do anyway to handle exceptions generated by Python
+ * There's no direct way to handle exceptions here, so we're depending
+ * on x509_store_object_verify() calling PyErr_Occurred() to check
+ * (which it has to do anyway to handle exceptions generated by Python
* callback handlers.
*/
+
+#warning Probably most of this callback handler should become Python code
+
static int
validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *status)
{
@@ -1233,7 +1210,7 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
* "expire".
*/
-#warning Should be kept in C
+#warning Could be done in Python
return 1;
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
@@ -1251,8 +1228,10 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
* output not to work with other OpenSSL-based applications.
*/
#warning Could be done in Python
+#if 0
if (allow_non_self_signed_trust_anchor)
ok = 1;
+#endif
record_validation_status(status, TRUST_ANCHOR_NOT_SELF_SIGNED);
return ok;
@@ -1269,6 +1248,9 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta
}
return ok;
}
+
+ error:
+ return ok;
}
@@ -1287,7 +1269,6 @@ 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;
@@ -1326,7 +1307,6 @@ 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) {
@@ -1346,42 +1326,12 @@ static int check_allowed_time_encoding(ASN1_TIME *t)
* Compare filename fields of two FileAndHash structures.
*/
-static int FileAndHash_name_cmp(const FileAndHash * const *a, const FileAndHash * const *b)
+static int check_manifest_FileAndHash_name_cmp(const FileAndHash * const *a, const FileAndHash * const *b)
{
return strcmp((char *) (*a)->file->data, (char *) (*b)->file->data);
}
/*
- * Check to see whether an AKI extension is present, is of the right
- * 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)
- lose_validation_error_from_code(status, AKI_EXTENSION_MISSING);
-
- if (!aki->keyid || aki->serial || aki->issuer)
- lose_validation_error_from_code(status, AKI_EXTENSION_WRONG_FORMAT);
-
- if (issuer != NULL && issuer->skid == NULL)
- /* Called for side effect of running x509v3_cache_extensions() */
- (void) X509_check_ca(issuer);
-
- if (issuer == NULL || issuer->skid == NULL)
- lose("Could not find issuer SKI");
-
- if (ASN1_OCTET_STRING_cmp(aki->keyid, issuer->skid))
- lose_validation_error_from_code(status, AKI_EXTENSION_ISSUER_MISMATCH);
-
- return 1;
-
- error:
- return 0;
-}
-
-/*
* Check a lot of pesky low-level things about RPKI certificates.
*/
@@ -1402,19 +1352,29 @@ static int check_x509(X509 *x,
unsigned ski_hashlen, afi;
int i, ok, crit, loc, ex_count, is_ca, routercert = 0, ret = 0;
-#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);
+ record_validation_status(status, NONCONFORMANT_ASN1_TIME_VALUE);
+
+ 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)
+ record_validation_status(status, NONCONFORMANT_SIGNATURE_ALGORITHM);
+
+ if (!check_allowed_dn(X509_get_subject_name(x)))
+ record_validation_status(status, NONCONFORMANT_SUBJECT_NAME);
+
+ if (!check_allowed_dn(X509_get_issuer_name(x)))
+ record_validation_status(status, NONCONFORMANT_ISSUER_NAME);
/*
* Apparently nothing ever looks at these fields, so there are no
* 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);
+ record_validation_status(status, NONCONFORMANT_CERTIFICATE_UID);
/*
* Keep track of allowed extensions we've seen. Once we've
@@ -1433,20 +1393,22 @@ static int check_x509(X509 *x,
if ((bc = X509_get_ext_d2i(x, NID_basic_constraints, &crit, NULL)) != NULL) {
ex_count--;
if (!crit || bc->ca <= 0 || bc->pathlen != NULL)
- lose_validation_error_from_code(status, MALFORMED_BASIC_CONSTRAINTS);
+ record_validation_status(status, MALFORMED_BASIC_CONSTRAINTS);
}
is_ca = bc != NULL;
if (is_ta && !is_ca)
- lose_validation_error_from_code(status, MALFORMED_TRUST_ANCHOR);
+ record_validation_status(status, MALFORMED_TRUST_ANCHOR);
/*
- * Check for presence of AIA, SIA, and CRLDP, but leave URI checking for Python code.
+ * Check for presence of AIA, SIA, and CRLDP, and make sure that
+ * they're in the correct format, but leave checking of the URIs for
+ * Python code.
*/
#warning Why are we not checking the critical flag on these extensions?
-#warning We may need to check that these extensions only contain URIs
+#warning We may need to check that these extensions only contain URIs (see extract_crldp_uri() and extract_access_uri())
if ((aia = X509_get_ext_d2i(x, NID_info_access, NULL, NULL)) != NULL)
ex_count--;
@@ -1472,33 +1434,12 @@ static int check_x509(X509 *x,
if ((eku = X509_get_ext_d2i(x, NID_ext_key_usage, &crit, NULL)) != NULL) {
ex_count--;
if (crit || is_ca || sk_ASN1_OBJECT_num(eku) == 0)
- lose_validation_error_from_code(status, INAPPROPRIATE_EKU_EXTENSION);
- for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++)
- routercert |= OBJ_obj2nid(sk_ASN1_OBJECT_value(eku, i)) == NID_id_kp_bgpsec_router;
+ record_validation_status(status, INAPPROPRIATE_EKU_EXTENSION);
+ else
+ for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++)
+ routercert |= OBJ_obj2nid(sk_ASN1_OBJECT_value(eku, i)) == NID_id_kp_bgpsec_router;
}
-#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 Part of this needs to remain in C
- 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;
@@ -1510,19 +1451,20 @@ static int check_x509(X509 *x,
(sk_POLICYQUALINFO_num(policy->qualifiers) == 1 &&
((qualifier = sk_POLICYQUALINFO_value(policy->qualifiers, 0)) == NULL ||
OBJ_obj2nid(qualifier->pqualid) != NID_id_qt_cps)))
- lose_validation_error_from_code(status, BAD_CERTIFICATE_POLICY);
- if (qualifier && !record_validation_status(status, POLICY_QUALIFIER_CPS))
- goto error;
+ record_validation_status(status, BAD_CERTIFICATE_POLICY);
+ else if (qualifier != NULL)
+ record_validation_status(status, POLICY_QUALIFIER_CPS);
}
-#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--;
+ if ((x->ex_flags & EXFLAG_KUSAGE) == 0)
+ record_validation_status(status, KEY_USAGE_MISSING);
+ else {
+ ex_count--;
+ if (!X509_EXTENSION_get_critical(X509_get_ext(x, X509_get_ext_by_NID(x, NID_key_usage, -1))) ||
+ x->ex_kusage != (is_ca ? KU_KEY_CERT_SIGN | KU_CRL_SIGN : KU_DIGITAL_SIGNATURE))
+ record_validation_status(status, BAD_KEY_USAGE);
+ }
-#warning Should remain in C
if (x->rfc3779_addr) {
ex_count--;
if (routercert ||
@@ -1530,18 +1472,18 @@ static int check_x509(X509 *x,
!X509_EXTENSION_get_critical(X509_get_ext(x, loc)) ||
!v3_addr_is_canonical(x->rfc3779_addr) ||
sk_IPAddressFamily_num(x->rfc3779_addr) == 0)
- lose_validation_error_from_code(status, BAD_IPADDRBLOCKS);
- for (i = 0; i < sk_IPAddressFamily_num(x->rfc3779_addr); i++) {
- IPAddressFamily *f = sk_IPAddressFamily_value(x->rfc3779_addr, i);
- afi = v3_addr_get_afi(f);
- if (afi != IANA_AFI_IPV4 && afi != IANA_AFI_IPV6)
- lose_validation_error_from_code(status, UNKNOWN_AFI);
- if (f->addressFamily->length != 2)
- lose_validation_error_from_code(status, SAFI_NOT_ALLOWED);
- }
+ record_validation_status(status, BAD_IPADDRBLOCKS);
+ else
+ for (i = 0; i < sk_IPAddressFamily_num(x->rfc3779_addr); i++) {
+ IPAddressFamily *f = sk_IPAddressFamily_value(x->rfc3779_addr, i);
+ afi = v3_addr_get_afi(f);
+ if (afi != IANA_AFI_IPV4 && afi != IANA_AFI_IPV6)
+ record_validation_status(status, UNKNOWN_AFI);
+ else if (f->addressFamily->length != 2)
+ record_validation_status(status, SAFI_NOT_ALLOWED);
+ }
}
-#warning Should remain in C
if (x->rfc3779_asid) {
ex_count--;
if ((loc = X509_get_ext_by_NID(x, NID_sbgp_autonomousSysNum, -1)) < 0 ||
@@ -1550,14 +1492,12 @@ static int check_x509(X509 *x,
x->rfc3779_asid->asnum == NULL ||
x->rfc3779_asid->rdi != NULL ||
(routercert && x->rfc3779_asid->asnum->type == ASIdentifierChoice_inherit))
- lose_validation_error_from_code(status, BAD_ASIDENTIFIERS);
+ record_validation_status(status, BAD_ASIDENTIFIERS);
}
-#warning Should remain in C
if (!x->rfc3779_addr && !x->rfc3779_asid)
- lose_validation_error_from_code(status, MISSING_RESOURCES);
+ record_validation_status(status, MISSING_RESOURCES);
-#warning Should remain in C
subject_pkey = X509_get_pubkey(x);
ok = subject_pkey != NULL;
if (ok) {
@@ -1568,16 +1508,19 @@ static int check_x509(X509 *x,
switch (OBJ_obj2nid(algorithm)) {
case NID_rsaEncryption:
- ok = EVP_PKEY_type(subject_pkey->type) == EVP_PKEY_RSA && BN_get_word(subject_pkey->pkey.rsa->e) == 65537;
- if (ok && BN_num_bits(subject_pkey->pkey.rsa->n) == 2048)
- break;
- ok = ok && !is_ca && allow_1024_bit_ee_key && BN_num_bits(subject_pkey->pkey.rsa->n) == 1024;
- if (ok && !record_validation_status(status, EE_CERTIFICATE_WITH_1024_BIT_KEY))
- goto error;
+ ok = (EVP_PKEY_type(subject_pkey->type) == EVP_PKEY_RSA &&
+ BN_get_word(subject_pkey->pkey.rsa->e) == 65537 &&
+ BN_num_bits(subject_pkey->pkey.rsa->n) == 2048);
break;
case NID_X9_62_id_ecPublicKey:
ok = !is_ca && routercert;
+ /*
+ * Perhaps this should also be testing:
+ *
+ * && EVP_PKEY_type(subject_pkey->type) == EVP_PKEY_EC)
+ * && EC_GROUP_get_curve_name(EC_KEY_get0_group(subject_pkey->pkey.ec)) == NID_X9_62_prime_field
+ */
break;
default:
@@ -1585,34 +1528,32 @@ 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,
- ski_hashbuf, &ski_hashlen, EVP_sha1(), NULL) ||
- ski_hashlen != 20 ||
- ski_hashlen != x->skid->length ||
- 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) {
+ record_validation_status(status, BAD_PUBLIC_KEY);
+
+ if (!x->skid)
+ record_validation_status(status, SKI_EXTENSION_MISSING);
+ else {
ex_count--;
- if (!check_aki(status, issuer, x->akid))
- goto error;
+ if ((ski_pubkey = X509_get0_pubkey_bitstr(x)) == NULL ||
+ !EVP_Digest(ski_pubkey->data, ski_pubkey->length,
+ ski_hashbuf, &ski_hashlen, EVP_sha1(), NULL) ||
+ ski_hashlen != 20 ||
+ ski_hashlen != x->skid->length ||
+ memcmp(ski_hashbuf, x->skid->data, ski_hashlen))
+ record_validation_status(status, SKI_PUBLIC_KEY_MISMATCH);
}
-#warning Could be done in Python
- if (!x->akid && !is_ta)
- lose_validation_error_from_code(status, AKI_EXTENSION_MISSING);
+ if (x->akid) {
+ ex_count--;
+ if (!x->akid->keyid || x->akid->serial || x->akid->issuer)
+ record_validation_status(status, AKI_EXTENSION_WRONG_FORMAT);
+ }
if ((issuer_pkey = X509_get_pubkey(issuer)) == NULL || X509_verify(x, issuer_pkey) <= 0)
- lose_validation_error_from_code(status, CERTIFICATE_BAD_SIGNATURE);
+ record_validation_status(status, CERTIFICATE_BAD_SIGNATURE);
if (ex_count > 0)
- lose_validation_error_from_code(status, DISALLOWED_X509V3_EXTENSION);
+ record_validation_status(status, DISALLOWED_X509V3_EXTENSION);
#warning Move policy stuff to optional OID in base X509.verify()
/*
@@ -1654,35 +1595,30 @@ static int check_crl(X509_CRL *crl,
EVP_PKEY *pkey;
int i, ret = 0;
-#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);
+ record_validation_status(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);
+ record_validation_status(status, NONCONFORMANT_ASN1_TIME_VALUE);
-#warning Could be done in Python
- if (!check_aki(status, issuer, crl->akid))
- goto error;
+ if (crl->akid == NULL)
+ record_validation_status(status, AKI_EXTENSION_MISSING);
+ else if (!crl->akid->keyid || crl->akid->serial || crl->akid->issuer)
+ record_validation_status(status, AKI_EXTENSION_WRONG_FORMAT);
-#warning Should be kept in C
- if (X509_CRL_get_ext_count(crl) != 2)
- lose_validation_error_from_code(status, DISALLOWED_X509V3_EXTENSION);
+ if (X509_CRL_get_ext_count(crl) > 2)
+ record_validation_status(status, DISALLOWED_X509V3_EXTENSION);
-#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);
+ record_validation_status(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);
+ record_validation_status(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);
@@ -1695,7 +1631,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,
@@ -1744,37 +1680,35 @@ 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);
+ record_validation_status(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 ||
!CMS_SignerInfo_get0_signer_id(si, &sid, &si_issuer, &si_serial) ||
sid == NULL || si_issuer != NULL || si_serial != NULL ||
CMS_unsigned_get_attr_count(si) != -1)
- lose_validation_error_from_code(status, BAD_CMS_SIGNER_INFOS);
+ record_validation_status(status, BAD_CMS_SIGNER_INFOS);
- CMS_SignerInfo_get0_algs(si, NULL, &x, &digest_alg, &signature_alg);
+ if (si != NULL)
+ CMS_SignerInfo_get0_algs(si, NULL, &x, &digest_alg, &signature_alg);
if (x == NULL)
- lose_validation_error_from_code(status, CMS_SIGNER_MISSING);
-
- if ((certs = CMS_get1_certs(cms)) == NULL ||
+ record_validation_status(status, CMS_SIGNER_MISSING);
+ else if ((certs = CMS_get1_certs(cms)) == NULL ||
sk_X509_num(certs) != 1 ||
X509_cmp(x, sk_X509_value(certs, 0)))
- lose_validation_error_from_code(status, BAD_CMS_SIGNER);
+ record_validation_status(status, BAD_CMS_SIGNER);
X509_ALGOR_get0(&oid, NULL, NULL, signature_alg);
i = OBJ_obj2nid(oid);
if (i != NID_sha256WithRSAEncryption && i != NID_rsaEncryption)
- lose_validation_error_from_code(status, WRONG_CMS_SI_SIGNATURE_ALGORITHM);
+ record_validation_status(status, WRONG_CMS_SI_SIGNATURE_ALGORITHM);
X509_ALGOR_get0(&oid, NULL, NULL, digest_alg);
if (OBJ_obj2nid(oid) != NID_sha256)
- lose_validation_error_from_code(status, WRONG_CMS_SI_DIGEST_ALGORITHM);
+ record_validation_status(status, WRONG_CMS_SI_DIGEST_ALGORITHM);
i = CMS_signed_get_attr_count(si);
@@ -1784,13 +1718,13 @@ static int check_cms(CMS_ContentInfo *cms,
(void) extract_si_datum(si, &i, 0, NID_pkcs9_messageDigest, V_ASN1_OCTET_STRING);
if (i != 0)
- lose_validation_error_from_code_maybe(allow_wrong_cms_si_attributes, status, BAD_CMS_SI_SIGNED_ATTRIBUTES);
+ record_validation_status(status, BAD_CMS_SI_SIGNED_ATTRIBUTES);
if (OBJ_cmp(oid, CMS_get0_eContentType(cms)) != 0)
- lose_validation_error_from_code(status, BAD_CMS_SI_CONTENTTYPE);
+ record_validation_status(status, BAD_CMS_SI_CONTENTTYPE);
if (CMS_SignerInfo_cert_cmp(si, x))
- lose_validation_error_from_code(status, CMS_SKI_MISMATCH);
+ record_validation_status(status, CMS_SKI_MISMATCH);
ret = 1;
@@ -1805,6 +1739,8 @@ static int check_cms(CMS_ContentInfo *cms,
* Check a lot of pesky low-level things about RPKI manifests.
*/
+#warning Almost everything in this function could be done in Python
+
static int check_manifest(CMS_ContentInfo *cms,
Manifest *manifest,
PyObject *status)
@@ -1816,40 +1752,43 @@ static int check_manifest(CMS_ContentInfo *cms,
#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);
+ record_validation_status(status, BAD_CMS_ECONTENTTYPE);
-#warning Should be kept in C
+#warning Can check value in Python, but not whether encoding was defaulted
if (manifest->version)
- lose_validation_error_from_code(status, WRONG_OBJECT_VERSION);
+ record_validation_status(status, WRONG_OBJECT_VERSION);
#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);
+ record_validation_status(status, BAD_CMS_SIGNER);
#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);
+ record_validation_status(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);
+ record_validation_status(status, NONCONFORMANT_DIGEST_ALGORITHM);
if ((sorted_fileList = sk_FileAndHash_dup(manifest->fileList)) == NULL)
lose_no_memory();
- (void) sk_FileAndHash_set_cmp_func(sorted_fileList, FileAndHash_name_cmp);
+#warning Could be done in Python
+ (void) sk_FileAndHash_set_cmp_func(sorted_fileList, check_manifest_FileAndHash_name_cmp);
sk_FileAndHash_sort(sorted_fileList);
+#warning Could be done in Python
for (i = 0; ((fah1 = sk_FileAndHash_value(sorted_fileList, i + 0)) != NULL &&
(fah2 = sk_FileAndHash_value(sorted_fileList, i + 1)) != NULL); i++)
if (!strcmp((char *) fah1->file->data, (char *) fah2->file->data))
- lose_validation_error_from_code(status, DUPLICATE_NAME_IN_MANIFEST);
+ record_validation_status(status, DUPLICATE_NAME_IN_MANIFEST);
+#warning Could be done in Python
for (i = 0; (fah1 = sk_FileAndHash_value(manifest->fileList, i)) != NULL; i++)
if (fah1->hash->length != HASH_SHA256_LEN ||
(fah1->hash->flags & (ASN1_STRING_FLAG_BITS_LEFT | 7)) > ASN1_STRING_FLAG_BITS_LEFT)
- lose_validation_error_from_code(status, BAD_MANIFEST_DIGEST_LENGTH);
+ record_validation_status(status, BAD_MANIFEST_DIGEST_LENGTH);
ret = 1;
@@ -1863,11 +1802,11 @@ static int check_manifest(CMS_ContentInfo *cms,
/*
* Extract a ROA prefix from the ASN.1 bitstring encoding.
*/
-static int extract_roa_prefix(const ROAIPAddress *ra,
- const unsigned afi,
- unsigned char *addr,
- unsigned *prefixlen,
- unsigned *max_prefixlen)
+static int check_roa_extract_roa_prefix(const ROAIPAddress *ra,
+ const unsigned afi,
+ unsigned char *addr,
+ unsigned *prefixlen,
+ unsigned *max_prefixlen)
{
unsigned length;
long maxlen;
@@ -1919,23 +1858,22 @@ static int check_roa(CMS_ContentInfo *cms,
#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);
+ record_validation_status(status, BAD_CMS_ECONTENTTYPE);
-#warning Should be kept in C
if (roa->version)
- lose_validation_error_from_code(status, WRONG_OBJECT_VERSION);
+ record_validation_status(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);
+ record_validation_status(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);
+ record_validation_status(status, BAD_CMS_SIGNER);
if ((ee_resources = X509_get_ext_d2i(sk_X509_value(certs, 0), NID_sbgp_ipAddrBlock, NULL, NULL)) == NULL)
- lose_validation_error_from_code(status, BAD_IPADDRBLOCKS);
+ record_validation_status(status, BAD_IPADDRBLOCKS);
/*
* Convert ROA prefixes to resource set. This goes on a bit.
@@ -1951,7 +1889,7 @@ static int check_roa(CMS_ContentInfo *cms,
lose_no_memory();
if (rf->addressFamily->length < 2 || rf->addressFamily->length > 3)
- lose_validation_error_from_code(status, MALFORMED_ROA_ADDRESSFAMILY);
+ record_validation_status(status, MALFORMED_ROA_ADDRESSFAMILY);
afi = (rf->addressFamily->data[0] << 8) | (rf->addressFamily->data[1]);
if (rf->addressFamily->length == 3)
@@ -1961,12 +1899,12 @@ static int check_roa(CMS_ContentInfo *cms,
ra = sk_ROAIPAddress_value(rf->addresses, j);
if (ra == NULL ||
- !extract_roa_prefix(ra, afi, addrbuf, &prefixlen, &max_prefixlen) ||
+ !check_roa_extract_roa_prefix(ra, afi, addrbuf, &prefixlen, &max_prefixlen) ||
!v3_addr_add_prefix(roa_resources, afi, safi, addrbuf, prefixlen))
- lose_validation_error_from_code(status, ROA_RESOURCES_MALFORMED);
+ record_validation_status(status, ROA_RESOURCES_MALFORMED);
- if (max_prefixlen < prefixlen)
- lose_validation_error_from_code(status, ROA_MAX_PREFIXLEN_TOO_SHORT);
+ else if (max_prefixlen < prefixlen)
+ record_validation_status(status, ROA_MAX_PREFIXLEN_TOO_SHORT);
}
}
@@ -1984,7 +1922,7 @@ static int check_roa(CMS_ContentInfo *cms,
IPAddressFamily *f = sk_IPAddressFamily_value(roa_resources, i);
if ((afi = v3_addr_get_afi(f)) == 0)
- lose_validation_error_from_code(status, ROA_CONTAINS_BAD_AFI_VALUE);
+ record_validation_status(status, ROA_CONTAINS_BAD_AFI_VALUE);
if (f->ipAddressChoice->type == IPAddressChoice_addressesOrRanges) {
IPAddressOrRanges *aors = f->ipAddressChoice->u.addressesOrRanges;
@@ -2001,7 +1939,7 @@ static int check_roa(CMS_ContentInfo *cms,
#warning Handling of length here looks weird, double check
if ((length = v3_addr_get_range(a, afi, a_min, a_max, RAW_IPADDR_BUFLEN)) == 0 ||
(length = v3_addr_get_range(b, afi, b_min, b_max, RAW_IPADDR_BUFLEN)) == 0)
- lose_validation_error_from_code(status, ROA_RESOURCES_MALFORMED);
+ record_validation_status(status, ROA_RESOURCES_MALFORMED);
if (memcmp(a_max, b_max, length) >= 0) {
(void) sk_IPAddressOrRange_delete(aors, j + 1);
@@ -2013,10 +1951,10 @@ static int check_roa(CMS_ContentInfo *cms,
}
if (!v3_addr_canonize(roa_resources))
- lose_validation_error_from_code(status, ROA_RESOURCES_MALFORMED);
+ record_validation_status(status, ROA_RESOURCES_MALFORMED);
- if (!v3_addr_subset(roa_resources, ee_resources))
- lose_validation_error_from_code(status, ROA_RESOURCE_NOT_IN_EE);
+ if (ee_resources == NULL || !v3_addr_subset(roa_resources, ee_resources))
+ record_validation_status(status, ROA_RESOURCE_NOT_IN_EE);
result = 1;
@@ -7490,10 +7428,8 @@ cms_object_verify_helper(cms_object *self, PyObject *args, PyObject *kwds, PyObj
assert_no_unhandled_openssl_errors();
if (CMS_verify(self->cms, certs_stack, NULL, NULL, bio, flags) <= 0) {
- if (*status == Py_None)
- lose_openssl_error("Couldn't verify CMS message");
- else
- lose_validation_error_from_code(*status, CMS_VALIDATION_FAILURE);
+ record_validation_status(*status, CMS_VALIDATION_FAILURE);
+ lose_openssl_error("Couldn't verify CMS message");
}
if (*status != Py_None && !check_cms(self->cms, *status))
@@ -7834,10 +7770,8 @@ manifest_object_verify(manifest_object *self, PyObject *args, PyObject *kwds)
goto error;
if (!ASN1_item_d2i_bio(ASN1_ITEM_rptr(Manifest), bio, &self->manifest)) {
- if (status == Py_None)
- lose_openssl_error("Couldn't decode manifest");
- else
- lose_validation_error_from_code(status, CMS_ECONTENT_DECODE_ERROR);
+ record_validation_status(status, CMS_ECONTENT_DECODE_ERROR);
+ lose_openssl_error("Couldn't decode manifest");
}
if (status != Py_None && !check_manifest(self->cms.cms, self->manifest, status))
@@ -8517,10 +8451,8 @@ roa_object_verify(roa_object *self, PyObject *args, PyObject *kwds)
goto error;
if (!ASN1_item_d2i_bio(ASN1_ITEM_rptr(ROA), bio, &self->roa)) {
- if (status == Py_None)
- lose_openssl_error("Couldn't decode ROA");
- else
- lose_validation_error_from_code(status, CMS_ECONTENT_DECODE_ERROR);
+ record_validation_status(status, CMS_ECONTENT_DECODE_ERROR);
+ lose_openssl_error("Couldn't decode ROA");
}
if (status != Py_None && !check_roa(self->cms.cms, self->roa, status))
diff --git a/rp/rcynic/rcynicng b/rp/rcynic/rcynicng
index 6c0a9b46..b06154cb 100755
--- a/rp/rcynic/rcynicng
+++ b/rp/rcynic/rcynicng
@@ -131,29 +131,30 @@ def install_object(obj):
def final_install():
- real_old = os.path.realpath(old_authenticated).rstrip("/")
- real_new = os.path.realpath(new_authenticated).rstrip("/")
-
- fn = args.authenticated.rstrip("/") + ".new"
- logger.debug("Symlinking %s to %s", os.path.basename(real_new), args.authenticated)
- if os.path.exists(fn):
- os.unlink(fn)
- os.symlink(os.path.basename(real_new), fn)
- os.rename(fn, args.authenticated)
-
- if os.path.isdir(real_old):
- fn = args.authenticated.rstrip("/") + ".old"
- logger.debug("Symlinking %s to %s", os.path.basename(real_old), fn)
- if os.path.exists(fn):
- os.unlink(fn)
- os.symlink(os.path.basename(real_old), fn)
-
- dn = os.path.dirname(args.authenticated.rstrip("/"))
- for fn in os.listdir(dn):
- fn = os.path.join(dn, fn)
- if fn.startswith(args.authenticated.rstrip("/") + ".") and os.path.realpath(fn) not in (real_new, real_old):
- logger.debug("Removing %s", fn)
- shutil.rmtree(fn)
+ cur_link = old_authenticated
+ new_link = cur_link + ".new"
+ old_link = cur_link + ".old"
+ dir_base = os.path.realpath(cur_link + ".")
+ new_real = os.path.realpath(new_authenticated)
+ old_real = os.path.realpath(old_authenticated)
+
+ if os.path.islink(old_link):
+ logger.debug("Unlinking %s", old_link)
+ os.unlink(old_link)
+
+ if os.path.isdir(old_real):
+ logger.debug("Symlinking %s to %s", os.path.basename(old_real), old_link)
+ os.symlink(os.path.basename(old_real), old_link)
+
+ logger.debug("Symlinking %s to %s", os.path.basename(new_real), cur_link)
+ os.symlink(os.path.basename(new_real), new_link)
+ os.rename(new_link, cur_link)
+
+ for path in os.listdir(os.path.dirname(dir_base)):
+ path = os.path.realpath(os.path.join(os.path.dirname(dir_base), path))
+ if path.startswith(dir_base) and path not in (new_real, old_real) and os.path.isdir(path):
+ logger.debug("Removing %s", path)
+ shutil.rmtree(path)
class X509(rpki.POW.X509):
@@ -225,6 +226,10 @@ class X509(rpki.POW.X509):
status.add(codes.CRLDP_EXTENSION_FORBIDDEN)
if not is_ta and self.crldp is None:
status.add(codes.CRLDP_EXTENSION_MISSING)
+ if not is_ta and self.aki is None:
+ status.add(codes.AKI_EXTENSION_MISSING)
+ elif not is_ta and self.aki != trusted[0].ski:
+ status.add(codes.AKI_EXTENSION_ISSUER_MISMATCH)
serial = self.getSerial()
if serial <= 0 or serial > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:
status.add(codes.BAD_CERTIFICATE_SERIAL_NUMBER)
@@ -308,6 +313,10 @@ class CRL(rpki.POW.CRL):
status.add(codes.CRL_NUMBER_OUT_OF_RANGE)
if self.getIssuer() != issuer.getSubject():
status.add(codes.CRL_ISSUER_NAME_MISMATCH)
+ if self.aki is None:
+ status.add(codes.AKI_EXTENSION_MISSING)
+ elif self.aki != issuer.ski:
+ status.add(codes.AKI_EXTENSION_ISSUER_MISMATCH)
return not any(s.kind == "bad" for s in status)
@@ -947,7 +956,7 @@ def main():
global new_authenticated, old_authenticated
new_authenticated = args.authenticated.rstrip("/") + time.strftime(".%Y-%m-%dT%H:%M:%SZ")
- old_authenticated = args.authenticated
+ old_authenticated = args.authenticated.rstrip("/")
Generation("current", args.unauthenticated)
Generation("backup", old_authenticated)
diff --git a/rpki/POW/__init__.py b/rpki/POW/__init__.py
index fdb2143b..a00c8fd8 100644
--- a/rpki/POW/__init__.py
+++ b/rpki/POW/__init__.py
@@ -164,7 +164,8 @@ validation_status = StatusCodeDB(
UNREADABLE_TRUST_ANCHOR = "Unreadable trust anchor",
UNREADABLE_TRUST_ANCHOR_LOCATOR = "Unreadable trust anchor locator",
WRONG_OBJECT_VERSION = "Wrong object version",
- OBJECT_NOT_FOUND = "Object not found"),
+ OBJECT_NOT_FOUND = "Object not found",
+ KEY_USAGE_MISSING = "Key usage missing"),
warn = dict(
AIA_DOESNT_MATCH_ISSUER = "AIA doesn't match issuer",