diff options
author | Rob Austein <sra@hactrn.net> | 2015-11-18 07:25:09 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2015-11-18 07:25:09 +0000 |
commit | 6c98d241fbb8e28c24b980dca0b8ce67891c4ca8 (patch) | |
tree | f3ec0ae4b146522ede33c5a114b48db22d4f931d | |
parent | cbb1c240fb629c89760c26019d24717af965bfd7 (diff) |
Move StatusCode out of POW.c. New API still needs work, but this
makes the C code considerably simpler.
svn path=/branches/tk705/; revision=6180
-rw-r--r-- | ext/POW.c | 485 | ||||
-rwxr-xr-x | rp/rcynic/rcynicng | 2 | ||||
-rw-r--r-- | rpki/POW/__init__.py | 173 |
3 files changed, 189 insertions, 471 deletions
@@ -355,8 +355,7 @@ static PyTypeObject POW_ROA_Type, POW_Manifest_Type, POW_ROA_Type, - POW_PKCS10_Type, - POW_StatusCode_Type; + POW_PKCS10_Type; /* * Object internals. @@ -422,14 +421,6 @@ typedef struct { X509_EXTENSIONS *exts; } pkcs10_object; -typedef struct { - PyObject_HEAD - long code; /* Really validation_status_t */ - PyObject *name; /* Name of symbol */ - PyObject *text; /* Human-readable explanation */ - PyObject *kind; /* good/bad/warn */ -} status_code_object; - /* @@ -501,19 +492,20 @@ typedef struct { #define lose_validation_error_from_code(_status_, _code_) \ do { \ - if (record_validation_status(_status_, _code_)) \ - PyErr_SetObject(ValidationErrorObject, \ - PyTuple_GetItem(status_codes, _code_)); \ + 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 (!(_test_)) \ - lose_validation_error_from_code(_status_, _code_); \ - else if (!record_validation_status(_status_, _code_)) \ + if (!_record_validation_status(_status_, #_code_)) \ goto error; \ - } while (0) + if (_test_) \ + break; \ + PyErr_SetString(ValidationErrorObject, #_code_); \ + goto error; \ + } while (0) #define assert_no_unhandled_openssl_errors() \ do { \ @@ -1198,432 +1190,29 @@ whack_ec_key_to_namedCurve(EVP_PKEY *pkey) /* - * Validation status codes. Still under construction. Modeled after - * rcynic's validation status database, conceptually anyway. - * - * Assuming we go this way, should we PySet_Clear() the status set - * upon entering the _verify function? Probably. - * - * How to handle CMS cases: keep common command parser etc, but add an argument - * to that helper function which takes a function pointer to do the extended - * checking for this particular flavor of CMS object. - */ - -/* - * Arguably most of this awful code could be replaced by a tiny - * separate module written in Python and imported here using - * PyImport_ImportModule(), after which we could grab objects from - * that module using PyObject_GetAttrString(). If necessary, that - * module could also contain code which, when invoked as a script - * rather than imported, dumped out a .h file we could import here, - * but it's probably not necessary, plain C strings here as names for - * objects in that module would probably be fine for our purposes. - */ - -/* - * There's some ugly C preprocessor junk here. Sorry, but it's the - * simplest way to keep all the definitions in a single place and - * expand them into all the forms we need in both C and Python. We - * undef the macros once we're done with them to localize the mess. - */ - -/* - * Status codes derived from OpenSSL. Long list of validation failure - * codes from OpenSSL (crypto/x509/x509_vfy.h). - */ - -#define VALIDATION_STATUS_CODES_FROM_OPENSSL \ - QV( X509_V_ERR_UNABLE_TO_GET_CRL) \ - QV( X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE) \ - QV( X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE) \ - QV( X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY) \ - QV( X509_V_ERR_CERT_SIGNATURE_FAILURE) \ - QV( X509_V_ERR_CRL_SIGNATURE_FAILURE) \ - QV( X509_V_ERR_CERT_NOT_YET_VALID) \ - QV( X509_V_ERR_CERT_HAS_EXPIRED) \ - QV( X509_V_ERR_CRL_NOT_YET_VALID) \ - QV( X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD) \ - QV( X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD) \ - QV( X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD) \ - QV( X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD) \ - QV( X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) \ - QV( X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \ - QV( X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) \ - QV( X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) \ - QV( X509_V_ERR_CERT_CHAIN_TOO_LONG) \ - QV( X509_V_ERR_CERT_REVOKED) \ - QV( X509_V_ERR_INVALID_CA) \ - QV( X509_V_ERR_PATH_LENGTH_EXCEEDED) \ - QV( X509_V_ERR_INVALID_PURPOSE) \ - QV( X509_V_ERR_CERT_UNTRUSTED) \ - QV( X509_V_ERR_CERT_REJECTED) \ - QV( X509_V_ERR_AKID_SKID_MISMATCH) \ - QV( X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH) \ - QV( X509_V_ERR_KEYUSAGE_NO_CERTSIGN) \ - QV( X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER) \ - QV( X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) \ - QV( X509_V_ERR_KEYUSAGE_NO_CRL_SIGN) \ - QV( X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION) \ - QV( X509_V_ERR_INVALID_NON_CA) \ - QV( X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED) \ - QV( X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE) \ - QV( X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED) \ - QV( X509_V_ERR_INVALID_EXTENSION) \ - QV( X509_V_ERR_INVALID_POLICY_EXTENSION) \ - QV( X509_V_ERR_NO_EXPLICIT_POLICY) \ - QV( X509_V_ERR_UNNESTED_RESOURCE) - -/* - * Status codes specific to our validation code. - * - * XXX Need to check this later, this is the full list of codes from rcynic.c, - * some of which will almost certainly be handled in Python rather than here. - */ - -#define VALIDATION_STATUS_CODES \ - VALIDATION_STATUS_CODES_FROM_OPENSSL \ - QB( AIA_EXTENSION_MISSING, "AIA extension missing") \ - QB( AIA_EXTENSION_FORBIDDEN, "AIA extension forbidden") \ - QB( AIA_URI_MISSING, "AIA URI missing") \ - QB( AKI_EXTENSION_ISSUER_MISMATCH, "AKI extension issuer mismatch") \ - QB( AKI_EXTENSION_MISSING, "AKI extension missing") \ - QB( AKI_EXTENSION_WRONG_FORMAT, "AKI extension is wrong format") \ - QB( BAD_ASIDENTIFIERS, "Bad ASIdentifiers extension") \ - QB( BAD_CERTIFICATE_POLICY, "Bad certificate policy") \ - QB( BAD_CMS_ECONTENTTYPE, "Bad CMS eContentType") \ - QB( BAD_CMS_SI_CONTENTTYPE, "Bad CMS SI ContentType") \ - QB( BAD_CMS_SIGNER, "Bad CMS signer") \ - QB( BAD_CMS_SIGNER_INFOS, "Bad CMS signerInfos") \ - QB( BAD_CRL, "Bad CRL") \ - QB( BAD_IPADDRBLOCKS, "Bad IPAddrBlocks extension") \ - 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_CERTIFICATE_SERIAL_NUMBER, "Bad certificate serialNumber") \ - QB( BAD_MANIFEST_NUMBER, "Bad manifestNumber") \ - QB( CERTIFICATE_BAD_SIGNATURE, "Bad certificate signature") \ - QB( CERTIFICATE_FAILED_VALIDATION, "Certificate failed validation") \ - QB( CMS_ECONTENT_DECODE_ERROR, "CMS eContent decode error") \ - QB( CMS_INCLUDES_CRLS, "CMS includes CRLs") \ - QB( CMS_SIGNER_MISSING, "CMS signer missing") \ - QB( CMS_SKI_MISMATCH, "CMS SKI mismatch") \ - QB( CMS_VALIDATION_FAILURE, "CMS validation failure") \ - QB( CRL_ISSUER_NAME_MISMATCH, "CRL issuer name mismatch") \ - QB( CRL_NOT_IN_MANIFEST, "CRL not listed in manifest") \ - QB( CRL_NOT_YET_VALID, "CRL not yet valid") \ - QB( CRL_NUMBER_EXTENSION_MISSING, "CRL number extension missing") \ - QB( CRL_NUMBER_IS_NEGATIVE, "CRL number is negative") \ - QB( CRL_NUMBER_OUT_OF_RANGE, "CRL number out of range") \ - QB( CRLDP_DOESNT_MATCH_ISSUER_SIA, "CRLDP doesn't match issuer's SIA") \ - QB( CRLDP_URI_MISSING, "CRLDP URI missing") \ - QB( DISALLOWED_X509V3_EXTENSION, "Disallowed X.509v3 extension") \ - QB( DUPLICATE_NAME_IN_MANIFEST, "Duplicate name in manifest") \ - QB( INAPPROPRIATE_EKU_EXTENSION, "Inappropriate EKU extension") \ - QB( MALFORMED_AIA_EXTENSION, "Malformed AIA extension") \ - QB( MALFORMED_SIA_EXTENSION, "Malformed SIA extension") \ - QB( MALFORMED_BASIC_CONSTRAINTS, "Malformed basicConstraints") \ - QB( MALFORMED_TRUST_ANCHOR, "Malformed trust anchor") \ - QB( MALFORMED_CADIRECTORY_URI, "Malformed caDirectory URI") \ - QB( MALFORMED_CRLDP_EXTENSION, "Malformed CRDLP extension") \ - QB( MALFORMED_CRLDP_URI, "Malformed CRDLP URI") \ - QB( MALFORMED_ROA_ADDRESSFAMILY, "Malformed ROA addressFamily") \ - QB( MALFORMED_TAL_URI, "Malformed TAL URI") \ - QB( MANIFEST_CAREPOSITORY_MISMATCH, "Manifest caRepository mismatch") \ - QB( MANIFEST_INTERVAL_OVERRUNS_CERT, "Manifest interval overruns certificate") \ - QB( MANIFEST_LISTS_MISSING_OBJECT, "Manifest lists missing object") \ - QB( MANIFEST_NOT_YET_VALID, "Manifest not yet valid") \ - QB( MISSING_RESOURCES, "Missing resources") \ - QB( NONCONFORMANT_ASN1_TIME_VALUE, "Nonconformant ASN.1 time value") \ - QB( NONCONFORMANT_PUBLIC_KEY_ALGORITHM, "Nonconformant public key algorithm") \ - QB( NONCONFORMANT_SIGNATURE_ALGORITHM, "Nonconformant signature algorithm") \ - QB( NONCONFORMANT_DIGEST_ALGORITHM, "Nonconformant digest algorithm") \ - QB( NONCONFORMANT_CERTIFICATE_UID, "Nonconformant certificate UID") \ - 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_MAX_PREFIXLEN_TOO_SHORT, "ROA maxPrefixlen too short") \ - QB( ROA_RESOURCE_NOT_IN_EE, "ROA resource not in EE") \ - QB( ROA_RESOURCES_MALFORMED, "ROA resources malformed") \ - QB( RSYNC_TRANSFER_FAILED, "rsync transfer failed") \ - QB( RSYNC_TRANSFER_TIMED_OUT, "rsync transfer timed out") \ - QB( SAFI_NOT_ALLOWED, "SAFI not allowed") \ - QB( SIA_CADIRECTORY_URI_MISSING, "SIA caDirectory URI missing") \ - QB( SIA_EXTENSION_MISSING, "SIA extension missing") \ - QB( SIA_MANIFEST_URI_MISSING, "SIA manifest URI missing") \ - QB( SKI_EXTENSION_MISSING, "SKI extension missing") \ - QB( SKI_PUBLIC_KEY_MISMATCH, "SKI public key mismatch") \ - QB( TRUST_ANCHOR_KEY_MISMATCH, "Trust anchor key mismatch") \ - QB( TRUST_ANCHOR_WITH_CRLDP, "Trust anchor can't have CRLDP") \ - QB( UNKNOWN_AFI, "Unknown AFI") \ - QB( UNKNOWN_OPENSSL_VERIFY_ERROR, "Unknown OpenSSL verify error") \ - QB( UNREADABLE_TRUST_ANCHOR, "Unreadable trust anchor") \ - QB( UNREADABLE_TRUST_ANCHOR_LOCATOR, "Unreadable trust anchor locator") \ - QB( WRONG_OBJECT_VERSION, "Wrong object version") \ - QW( AIA_DOESNT_MATCH_ISSUER, "AIA doesn't match issuer") \ - QW( BACKUP_THISUPDATE_NEWER_THAN_CURRENT, "Backup thisUpdate newer than current") \ - QW( BACKUP_NUMBER_HIGHER_THAN_CURRENT, "Backup number higher than current") \ - QW( BAD_THISUPDATE, "Bad CRL thisUpdate") \ - QW( BAD_CMS_SI_SIGNED_ATTRIBUTES, "Bad CMS SI signed attributes") \ - QW( BAD_SIGNED_OBJECT_URI, "Bad signedObject URI") \ - QW( CRLDP_NAMES_NEWER_CRL, "CRLDP names newer CRL") \ - QW( DIGEST_MISMATCH, "Digest mismatch") \ - QW( EE_CERTIFICATE_WITH_1024_BIT_KEY, "EE certificate with 1024 bit key") \ - QW( ISSUER_USES_MULTIPLE_CRLDP_VALUES, "Issuer uses multiple CRLDP values")\ - QW( MULTIPLE_RSYNC_URIS_IN_EXTENSION, "Multiple rsync URIs in extension") \ - QW( NONCONFORMANT_ISSUER_NAME, "Nonconformant X.509 issuer name") \ - QW( NONCONFORMANT_SUBJECT_NAME, "Nonconformant X.509 subject name") \ - QW( POLICY_QUALIFIER_CPS, "Policy Qualifier CPS") \ - QW( RSYNC_PARTIAL_TRANSFER, "rsync partial transfer") \ - QW( RSYNC_TRANSFER_SKIPPED, "rsync transfer skipped") \ - QW( SIA_EXTENSION_MISSING_FROM_EE, "SIA extension missing from EE") \ - QW( SKIPPED_BECAUSE_NOT_IN_MANIFEST, "Skipped because not in manifest") \ - QW( STALE_CRL_OR_MANIFEST, "Stale CRL or 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( TRUST_ANCHOR_SKIPPED, "Trust anchor skipped") \ - QW( UNKNOWN_OBJECT_TYPE_SKIPPED, "Unknown object type skipped") \ - QW( URI_TOO_LONG, "URI too long") \ - QW( WRONG_CMS_SI_SIGNATURE_ALGORITHM, "Wrong CMS SI signature algorithm") \ - QW( WRONG_CMS_SI_DIGEST_ALGORITHM, "Wrong CMS SI digest algorithm") \ - QG( NON_RSYNC_URI_IN_EXTENSION, "Non-rsync URI in extension") \ - QG( OBJECT_ACCEPTED, "Object accepted") \ - QG( RECHECKING_OBJECT, "Rechecking object") \ - QG( RSYNC_TRANSFER_SUCCEEDED, "rsync transfer succeeded") \ - QG( VALIDATION_OK, "OK") - -/* - * Enumerated type for use in C. - */ - -#define QV(x) QB(STATUS_CODE_##x, 0) -#define QB(x,y) QQ(x) -#define QW(x,y) QQ(x) -#define QG(x,y) QQ(x) -#define QQ(x) x, - -typedef enum { VALIDATION_STATUS_CODES MAX_VALIDATION_STATUS_CODES } validation_status_t; - -/* - * Add these enum symbols to the module. - */ - -#undef QV -#undef QB -#undef QW -#undef QG -#undef QQ - -/* - * Build Python objects corresponding to these codes. We define a - * trivial read-only type for this, and allocate one instance for each - * status code. - * - * We don't provide .__new__() or .__init__() for the StatusCode type, - * and all access is read-only via getter methods, because these are - * read-only objects created when this module is initialized and are - * not (currently?) intended for any other use. - */ - -static void -status_code_object_dealloc(status_code_object *self) -{ - Py_XDECREF(self->name); - Py_XDECREF(self->text); - Py_XDECREF(self->kind); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -status_code_object_str(status_code_object *self) -{ - Py_XINCREF(self->name); - return self->name; -} - -static PyObject * -status_code_object_repr(status_code_object *self) -{ - const char *text = PyString_AsString(self->text); - if (text == NULL) - return NULL; - return PyString_FromFormat("<%s object \"%s\" at %p>", self->ob_type->tp_name, text, self); -} - - -static long -status_code_object_hash(status_code_object *self) -{ - return self->code; -} - -static int -status_code_object_compare(status_code_object *obj1, status_code_object *obj2) -{ - if (obj1->code < obj2->code) - return -1; - if (obj1->code > obj2->code) - return 1; - return 0; -} - -static PyObject * -status_code_object_get_code(status_code_object *self, GCC_UNUSED void *closure) -{ - return PyInt_FromLong(self->code); -} - -static PyObject * -status_code_object_get_name(status_code_object *self, GCC_UNUSED void *closure) -{ - Py_XINCREF(self->name); - return self->name; -} - -static PyObject * -status_code_object_get_text(status_code_object *self, GCC_UNUSED void *closure) -{ - Py_XINCREF(self->text); - return self->text; -} - -static PyObject * -status_code_object_get_kind(status_code_object *self, GCC_UNUSED void *closure) -{ - Py_XINCREF(self->text); - return self->kind; -} - -static PyGetSetDef status_code_object_getsetters[] = { - {"code", (getter) status_code_object_get_code}, - {"name", (getter) status_code_object_get_name}, - {"text", (getter) status_code_object_get_text}, - {"kind", (getter) status_code_object_get_kind}, - {NULL} -}; - -static char POW_StatusCode_Type__doc__[] = - "This class represents a validation status code.\n" - ; - -static PyTypeObject POW_StatusCode_Type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "rpki.POW.StatusCode", /* tp_name */ - sizeof(status_code_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) status_code_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc) status_code_object_compare, /* tp_compare */ - (reprfunc) status_code_object_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) status_code_object_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) status_code_object_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - POW_StatusCode_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - status_code_object_getsetters /* tp_getset */ -}; - -/* - * Build a tuple containing StatusCode instances, indexed by the - * numeric codes, so that using the C enum as an index into the - * sequence yields the corresponding StatusCode object. - * - * Return value of this function is the tuple. + * 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 + * Python side (see rpki/POW/__init__.py). */ -static PyObject * -build_status_codes(void) -{ - PyObject *result = NULL; - PyObject *object = NULL; - PyObject *good = NULL; - PyObject *warn = NULL; - PyObject *bad = NULL; - - if ((good = PyString_FromString("good")) == NULL || - (warn = PyString_FromString("warn")) == NULL || - (bad = PyString_FromString("bad")) == NULL) - goto error; - - if ((result = PyTuple_New(MAX_VALIDATION_STATUS_CODES)) == NULL) - goto error; - -#define QV(x) QQ(STATUS_CODE_##x, #x, X509_verify_cert_error_string(x), bad) -#define QB(x,y) QQ(x, #x, y, bad) -#define QW(x,y) QQ(x, #x, y, warn) -#define QG(x,y) QQ(x, #x, y, good) - -#define QQ(_code_, _name_, _text_, _kind_) \ - { \ - status_code_object *obj; \ - if ((object = POW_StatusCode_Type.tp_alloc(&POW_StatusCode_Type, 0)) == NULL) \ - goto error; \ - obj = (status_code_object *) object; \ - Py_INCREF(_kind_); \ - obj->code = _code_; \ - obj->kind = _kind_; \ - if ((obj->name = PyString_FromString(_name_)) == NULL || \ - (obj->text = Py_BuildValue("s", _text_)) == NULL || \ - PyTuple_SetItem(result, _code_, object) != 0) \ - goto error; \ - object = NULL; \ - } - - VALIDATION_STATUS_CODES; - -#undef QV -#undef QB -#undef QW -#undef QG -#undef QQ - - Py_XDECREF(good); - Py_XDECREF(warn); - Py_XDECREF(bad); - return result; - - error: - Py_XDECREF(good); - Py_XDECREF(warn); - Py_XDECREF(bad); - Py_XDECREF(object); - Py_XDECREF(result); - return NULL; -} - /* * Add code to status object, return C boolean indicating success. * Do nothing and return success if the status object is None. */ +#define record_validation_status(_status_, _code_) \ + _record_validation_status(_status_, #_code_) + static int -record_validation_status(PyObject *status, const validation_status_t code) +_record_validation_status(PyObject *status, const char *code) { if (status == Py_None) return 1; - PyObject *value = PyTuple_GetItem(status_codes, code); + PyObject *value = PyString_FromString(code); if (value == NULL) return 0; - Py_XINCREF(value); int result = PySet_Add(status, value); Py_XDECREF(value); return result == 0; @@ -1690,34 +1279,19 @@ validation_status_x509_verify_cert_cb(int ok, X509_STORE_CTX *ctx, PyObject *sta return ok; /* - * Handle known OpenSSL verify errors except the ones we handle - * explicitly above. + * Handle all other OpenSSL verify errors by stuffing an integer + * into the status set. */ -#define QV(x) \ - case x: \ - record_validation_status(status, STATUS_CODE_##x); \ - return ok; - VALIDATION_STATUS_CODES_FROM_OPENSSL; -#undef QV - default: - /* - * If you see this, it means that OpenSSL returned a status code - * we don't know about, so it's time to check the list of known - * OpenSSL verify errors to find out what's missing. - */ - record_validation_status(status, UNKNOWN_OPENSSL_VERIFY_ERROR); + if (status != Py_None) { + PyObject *value = PyInt_FromLong(ctx->error); + PySet_Add(status, value); + Py_XDECREF(value); + } return ok; } } -/* - * Done with the sick macros. - */ - -#undef VALIDATION_STATUS_CODES -#undef VALIDATION_STATUS_CODES_FROM_OPENSSL - /* @@ -10561,7 +10135,6 @@ init_POW(void) Define_Class(POW_Manifest_Type); Define_Class(POW_ROA_Type); Define_Class(POW_PKCS10_Type); - Define_Class(POW_StatusCode_Type); #undef Define_Class @@ -10669,12 +10242,6 @@ init_POW(void) #undef Define_Integer_Constant - /* Validation status codes */ - - status_codes = build_status_codes(); - Py_XINCREF(status_codes); - PyModule_AddObject(m, "_validation_status_codes", status_codes); - /* * Initialise library. * diff --git a/rp/rcynic/rcynicng b/rp/rcynic/rcynicng index 61d83dc8..d6aaf56e 100755 --- a/rp/rcynic/rcynicng +++ b/rp/rcynic/rcynicng @@ -39,7 +39,7 @@ class Status(object): return "{time} {self.uri} {status} {self.generation}".format( self = self, time = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(self.timestamp)), - status = ",".join(s.name for s in sorted(self.status))) + status = ",".join(str(s) for s in sorted(self.status))) @classmethod def update(cls, uri, generation = None): diff --git a/rpki/POW/__init__.py b/rpki/POW/__init__.py index 7f18b548..7f92c2cd 100644 --- a/rpki/POW/__init__.py +++ b/rpki/POW/__init__.py @@ -19,21 +19,172 @@ # pylint: disable=W0401,W0622 -from rpki.POW._POW import * -from rpki.POW._POW import __doc__ +from ._POW import * +from ._POW import __doc__ -# Set callback to let POW construct rpki.sundial.datetime objects + +# Set callback to let POW construct rpki.sundial.datetime objects. from rpki.sundial import datetime as sundial_datetime customDatetime(sundial_datetime) del sundial_datetime -# Construct friendlier representation for validation status codes. -from rpki.POW._POW import _validation_status_codes -class validation_status(object): - "RPKI validation status codes." -for code in _validation_status_codes: - setattr(validation_status, code.name, code) -del code # pylint: disable=W0631 -del _validation_status_codes +# Status code mechanism, (mostly) moved out of POW.c. + +class StatusCode(object): + + def __init__(self, name, text, kind, code = None): + assert code is None or isinstance(code, int) + assert kind in ("good", "bad", "warn") + self.code = code + self.name = name + self.text = text + self.kind = kind + + def __str__(self): + return self.name + + def __repr__(self): + return "<StatusCode object \"{}\" at {}>".format(self.text, id(self)) + + def __hash__(self): + return hash(self.name) + + def __cmp__(self, other): + return cmp(self.name, other.name) + + +class StatusCodeDB(object): + + def __init__(self, bad, warn, good): + for k, v in bad.iteritems(): + setattr(self, k, StatusCode(name = k, text = v, kind = "bad")) + for k, v in warn.iteritems(): + setattr(self, k, StatusCode(name = k, text = v, kind = "warn")) + for k, v in good.iteritems(): + setattr(self, k, StatusCode(name = k, text = v, kind = "good")) + + # Do we want something to let us use the OpenSSL symbolic names + # for the X509_V_ERR_* codes, or just skip that entirely? + # + # Sort that out when we get to the Python-side API for this stuff. + + +validation_status = StatusCodeDB( + bad = dict( + AIA_EXTENSION_MISSING = "AIA extension missing", + AIA_EXTENSION_FORBIDDEN = "AIA extension forbidden", + AIA_URI_MISSING = "AIA URI missing", + AKI_EXTENSION_ISSUER_MISMATCH = "AKI extension issuer mismatch", + AKI_EXTENSION_MISSING = "AKI extension missing", + AKI_EXTENSION_WRONG_FORMAT = "AKI extension is wrong format", + BAD_ASIDENTIFIERS = "Bad ASIdentifiers extension", + BAD_CERTIFICATE_POLICY = "Bad certificate policy", + BAD_CMS_ECONTENTTYPE = "Bad CMS eContentType", + BAD_CMS_SI_CONTENTTYPE = "Bad CMS SI ContentType", + BAD_CMS_SIGNER = "Bad CMS signer", + BAD_CMS_SIGNER_INFOS = "Bad CMS signerInfos", + BAD_CRL = "Bad CRL", + BAD_IPADDRBLOCKS = "Bad IPAddrBlocks extension", + BAD_KEY_USAGE = "Bad keyUsage", + BAD_MANIFEST_DIGEST_LENGTH = "Bad manifest digest length", + BAD_PUBLIC_KEY = "Bad public key", + BAD_ROA_ASID = "Bad ROA asID", + BAD_CERTIFICATE_SERIAL_NUMBER = "Bad certificate serialNumber", + BAD_MANIFEST_NUMBER = "Bad manifestNumber", + CERTIFICATE_BAD_SIGNATURE = "Bad certificate signature", + CERTIFICATE_FAILED_VALIDATION = "Certificate failed validation", + CMS_ECONTENT_DECODE_ERROR = "CMS eContent decode error", + CMS_INCLUDES_CRLS = "CMS includes CRLs", + CMS_SIGNER_MISSING = "CMS signer missing", + CMS_SKI_MISMATCH = "CMS SKI mismatch", + CMS_VALIDATION_FAILURE = "CMS validation failure", + CRL_ISSUER_NAME_MISMATCH = "CRL issuer name mismatch", + CRL_NOT_IN_MANIFEST = "CRL not listed in manifest", + CRL_NOT_YET_VALID = "CRL not yet valid", + CRL_NUMBER_EXTENSION_MISSING = "CRL number extension missing", + CRL_NUMBER_IS_NEGATIVE = "CRL number is negative", + CRL_NUMBER_OUT_OF_RANGE = "CRL number out of range", + CRLDP_DOESNT_MATCH_ISSUER_SIA = "CRLDP doesn't match issuer's SIA", + CRLDP_URI_MISSING = "CRLDP URI missing", + DISALLOWED_X509V3_EXTENSION = "Disallowed X.509v3 extension", + DUPLICATE_NAME_IN_MANIFEST = "Duplicate name in manifest", + INAPPROPRIATE_EKU_EXTENSION = "Inappropriate EKU extension", + MALFORMED_AIA_EXTENSION = "Malformed AIA extension", + MALFORMED_SIA_EXTENSION = "Malformed SIA extension", + MALFORMED_BASIC_CONSTRAINTS = "Malformed basicConstraints", + MALFORMED_TRUST_ANCHOR = "Malformed trust anchor", + MALFORMED_CADIRECTORY_URI = "Malformed caDirectory URI", + MALFORMED_CRLDP_EXTENSION = "Malformed CRDLP extension", + MALFORMED_CRLDP_URI = "Malformed CRDLP URI", + MALFORMED_ROA_ADDRESSFAMILY = "Malformed ROA addressFamily", + MALFORMED_TAL_URI = "Malformed TAL URI", + MANIFEST_CAREPOSITORY_MISMATCH = "Manifest caRepository mismatch", + MANIFEST_INTERVAL_OVERRUNS_CERT = "Manifest interval overruns certificate", + MANIFEST_LISTS_MISSING_OBJECT = "Manifest lists missing object", + MANIFEST_NOT_YET_VALID = "Manifest not yet valid", + MISSING_RESOURCES = "Missing resources", + NONCONFORMANT_ASN1_TIME_VALUE = "Nonconformant ASN.1 time value", + NONCONFORMANT_PUBLIC_KEY_ALGORITHM = "Nonconformant public key algorithm", + NONCONFORMANT_SIGNATURE_ALGORITHM = "Nonconformant signature algorithm", + NONCONFORMANT_DIGEST_ALGORITHM = "Nonconformant digest algorithm", + NONCONFORMANT_CERTIFICATE_UID = "Nonconformant certificate UID", + OBJECT_REJECTED = "Object rejected", + RFC3779_INHERITANCE_REQUIRED = "RFC 3779 inheritance required", + ROA_CONTAINS_BAD_AFI_VALUE = "ROA contains bad AFI value", + ROA_MAX_PREFIXLEN_TOO_SHORT = "ROA maxPrefixlen too short", + ROA_RESOURCE_NOT_IN_EE = "ROA resource not in EE", + ROA_RESOURCES_MALFORMED = "ROA resources malformed", + RSYNC_TRANSFER_FAILED = "rsync transfer failed", + RSYNC_TRANSFER_TIMED_OUT = "rsync transfer timed out", + SAFI_NOT_ALLOWED = "SAFI not allowed", + SIA_CADIRECTORY_URI_MISSING = "SIA caDirectory URI missing", + SIA_EXTENSION_MISSING = "SIA extension missing", + SIA_MANIFEST_URI_MISSING = "SIA manifest URI missing", + SKI_EXTENSION_MISSING = "SKI extension missing", + SKI_PUBLIC_KEY_MISMATCH = "SKI public key mismatch", + TRUST_ANCHOR_KEY_MISMATCH = "Trust anchor key mismatch", + TRUST_ANCHOR_WITH_CRLDP = "Trust anchor can't have CRLDP", + UNKNOWN_AFI = "Unknown AFI", + UNKNOWN_OPENSSL_VERIFY_ERROR = "Unknown OpenSSL verify error", + UNREADABLE_TRUST_ANCHOR = "Unreadable trust anchor", + UNREADABLE_TRUST_ANCHOR_LOCATOR = "Unreadable trust anchor locator", + WRONG_OBJECT_VERSION = "Wrong object version"), + + warn = dict( + AIA_DOESNT_MATCH_ISSUER = "AIA doesn't match issuer", + BACKUP_THISUPDATE_NEWER_THAN_CURRENT = "Backup thisUpdate newer than current", + BACKUP_NUMBER_HIGHER_THAN_CURRENT = "Backup number higher than current", + BAD_THISUPDATE = "Bad CRL thisUpdate", + BAD_CMS_SI_SIGNED_ATTRIBUTES = "Bad CMS SI signed attributes", + BAD_SIGNED_OBJECT_URI = "Bad signedObject URI", + CRLDP_NAMES_NEWER_CRL = "CRLDP names newer CRL", + DIGEST_MISMATCH = "Digest mismatch", + EE_CERTIFICATE_WITH_1024_BIT_KEY = "EE certificate with 1024 bit key", + ISSUER_USES_MULTIPLE_CRLDP_VALUES = "Issuer uses multiple CRLDP values",\ + MULTIPLE_RSYNC_URIS_IN_EXTENSION = "Multiple rsync URIs in extension", + NONCONFORMANT_ISSUER_NAME = "Nonconformant X.509 issuer name", + NONCONFORMANT_SUBJECT_NAME = "Nonconformant X.509 subject name", + POLICY_QUALIFIER_CPS = "Policy Qualifier CPS", + RSYNC_PARTIAL_TRANSFER = "rsync partial transfer", + RSYNC_TRANSFER_SKIPPED = "rsync transfer skipped", + SIA_EXTENSION_MISSING_FROM_EE = "SIA extension missing from EE", + SKIPPED_BECAUSE_NOT_IN_MANIFEST = "Skipped because not in manifest", + STALE_CRL_OR_MANIFEST = "Stale CRL or manifest", + TAINTED_BY_STALE_CRL = "Tainted by stale CRL", + TAINTED_BY_STALE_MANIFEST = "Tainted by stale manifest", + TAINTED_BY_NOT_BEING_IN_MANIFEST = "Tainted by not being in manifest", + TRUST_ANCHOR_NOT_SELF_SIGNED = "Trust anchor not self-signed", + TRUST_ANCHOR_SKIPPED = "Trust anchor skipped", + UNKNOWN_OBJECT_TYPE_SKIPPED = "Unknown object type skipped", + URI_TOO_LONG = "URI too long", + WRONG_CMS_SI_SIGNATURE_ALGORITHM = "Wrong CMS SI signature algorithm", + WRONG_CMS_SI_DIGEST_ALGORITHM = "Wrong CMS SI digest algorithm"), + + good = dict( + NON_RSYNC_URI_IN_EXTENSION = "Non-rsync URI in extension", + OBJECT_ACCEPTED = "Object accepted", + RECHECKING_OBJECT = "Rechecking object", + RSYNC_TRANSFER_SUCCEEDED = "rsync transfer succeeded", + VALIDATION_OK = "OK")) |