diff options
Diffstat (limited to 'rpkid/ext/POW.c')
-rw-r--r-- | rpkid/ext/POW.c | 9253 |
1 files changed, 0 insertions, 9253 deletions
diff --git a/rpkid/ext/POW.c b/rpkid/ext/POW.c deleted file mode 100644 index b5d9ccaf..00000000 --- a/rpkid/ext/POW.c +++ /dev/null @@ -1,9253 +0,0 @@ -/* - * This module started out as the core of Peter Shannon's "Python - * OpenSSL Wrappers" package, an excellent but somewhat dated package - * which I encountered while looking for some halfway sane way to cram - * RFC 3779 certificate support code into Python. - * - * At this point enough of the code has been added or rewritten that - * it's unclear (either way) whether this code properly qualifies as a - * derivative work. Given that both Peter's original code and all of - * subsequent changes to it were done under something equivalent to a - * BSD license, this may not matter very much, but the following - * attempts to give proper credit to all concerned. - * - **** - * - * Copyright (C) 2009--2013 Internet Systems Consortium ("ISC") - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - **** - * - * Portions copyright (C) 2006--2008 American Registry for Internet - * Numbers ("ARIN") - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - **** - * - * Portions Copyright (c) 2001, 2002, Peter Shannon - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * * The name of the contributors may be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* $Id$ */ - -#define PY_SSIZE_T_CLEAN 1 -#include <Python.h> -#include <datetime.h> - -#include <openssl/opensslconf.h> -#include <openssl/crypto.h> -#include <openssl/rand.h> -#include <openssl/asn1.h> -#include <openssl/x509.h> -#include <openssl/x509v3.h> -#include <openssl/pem.h> -#include <openssl/evp.h> -#include <openssl/err.h> -#include <openssl/md5.h> -#include <openssl/sha.h> -#include <openssl/cms.h> - -#include <rpki/roa.h> -#include <rpki/manifest.h> - -#include <time.h> -#include <string.h> -#include <arpa/inet.h> -#include <sys/socket.h> - -/* - * GCC attribute to let us tell GCC not to whine about unused formal - * parameters when we're in maximal warning mode. - */ -#ifdef __GNUC__ -#define GCC_UNUSED __attribute__((unused)) -#else -define GCC_UNUSED -#endif - -/* - * Maximum size of a raw IP (v4 or v6) address, in bytes. - */ -#define RAW_IPADDR_BUFLEN 16 - -/* - * Maximum size of an ASN.1 Integer converted from a Python Long, in bytes. - */ -#define MAX_ASN1_INTEGER_LEN 20 - -/* Digests */ -#define MD5_DIGEST 2 -#define SHA_DIGEST 3 -#define SHA1_DIGEST 4 -#define SHA256_DIGEST 6 -#define SHA384_DIGEST 7 -#define SHA512_DIGEST 8 - -/* Object format */ -#define SHORTNAME_FORMAT 1 -#define LONGNAME_FORMAT 2 -#define OIDNAME_FORMAT 3 - -/* AsymmetricParam EC curves */ -#define EC_P256_CURVE NID_X9_62_prime256v1 - -/* Object check functions */ -#define POW_X509_Check(op) PyObject_TypeCheck(op, &POW_X509_Type) -#define POW_X509Store_Check(op) PyObject_TypeCheck(op, &POW_X509Store_Type) -#define POW_X509StoreCTX_Check(op) PyObject_TypeCheck(op, &POW_X509StoreCTX_Type) -#define POW_CRL_Check(op) PyObject_TypeCheck(op, &POW_CRL_Type) -#define POW_Asymmetric_Check(op) PyObject_TypeCheck(op, &POW_Asymmetric_Type) -#define POW_AsymmetricParams_Check(op) PyObject_TypeCheck(op, &POW_AsymmetricParams_Type) -#define POW_Digest_Check(op) PyObject_TypeCheck(op, &POW_Digest_Type) -#define POW_CMS_Check(op) PyObject_TypeCheck(op, &POW_CMS_Type) -#define POW_IPAddress_Check(op) PyObject_TypeCheck(op, &POW_IPAddress_Type) -#define POW_ROA_Check(op) PyObject_TypeCheck(op, &POW_ROA_Type) -#define POW_Manifest_Check(op) PyObject_TypeCheck(op, &POW_Manifest_Type) -#define POW_ROA_Check(op) PyObject_TypeCheck(op, &POW_ROA_Type) - -static char pow_module__doc__ [] = - "Python interface to RFC-3779-enabled OpenSSL. This code is intended\n" - "to support the rpki.net toolset.\n" - "\n" - "This code started out life as Peter Shannon's excellent \"Python OpenSSL\n" - "Wrappers\" package. It has been extensively modified since then, to add\n" - "support for things needed for the RPKI protocols, to upgrade the code\n" - "to use modern (circa Python 2.7) classes, and to remove code not\n" - "needed for RPKI.\n" - ; - -#define LAME_DISCLAIMER_IN_ALL_CLASS_DOCUMENTATION \ - "The documentation for this class used to provide a nice example of how\n" \ - "to use the class. Sadly, most of what was in that example is now\n" \ - "obsolete due to recent or impending API changes. Once the new API is\n" \ - "stable, this documentation should be rewritten to provide such examples.\n" - -/* - * Handle NIDs we wish OpenSSL knew about. This is carefully (we - * hope) written to do nothing at all for any NID that OpenSSL knows - * about; the intent is just to add definitions for things OpenSSL - * doesn't know about yet. Of necessity, this is a bit gross, since - * it confounds runtime static variables with predefined macro names, - * but we try to put all the magic associated with this in one place. - */ - -#ifndef NID_rpkiManifest -static int NID_rpkiManifest; -#endif - -#ifndef NID_signedObject -static int NID_signedObject; -#endif - -static const struct { - int *nid; - const char *oid; - const char *sn; - const char *ln; -} missing_nids[] = { - -#ifndef NID_rpkiManifest - {&NID_rpkiManifest, "1.3.6.1.5.5.7.48.10", "id-ad-rpkiManifest", "RPKI Manifest"}, -#endif - -#ifndef NID_signedObject - {&NID_signedObject, "1.3.6.1.5.5.7.48.11", "id-ad-signedObject", "Signed Object"} -#endif - -}; - -/* - * IP versions. - */ - -typedef struct ipaddress_version { - unsigned version; - unsigned afi; - unsigned af; - unsigned length; -} ipaddress_version; - -static const ipaddress_version ipaddress_version_4 = { - 4, IANA_AFI_IPV4, AF_INET, 4 -}; - -static const ipaddress_version ipaddress_version_6 = { - 6, IANA_AFI_IPV6, AF_INET6, 16 -}; - -static const ipaddress_version * const ipaddress_versions[] = { - &ipaddress_version_4, &ipaddress_version_6 -}; - -/* - * Names of bits in the KeyUsage BitString (RFC 5280 4.2.1.3). - */ - -static const char * const key_usage_bit_names[] = { - "digitalSignature", /* (0) */ - "nonRepudiation", /* (1) */ - "keyEncipherment", /* (2) */ - "dataEncipherment", /* (3) */ - "keyAgreement", /* (4) */ - "keyCertSign", /* (5) */ - "cRLSign", /* (6) */ - "encipherOnly", /* (7) */ - "decipherOnly", /* (8) */ - NULL -}; - -/* - * Exception objects. - */ - -static PyObject - *ErrorObject, - *OpenSSLErrorObject, - *POWErrorObject, - *NotVerifiedErrorObject; - -/* - * Constructor for customized datetime class. - */ - -static PyObject *custom_datetime; - -/* - * "ex_data" index for pointer we want to attach to X509_STORE_CTX so - * we can extract it in callbacks. - */ - -static int x509_store_ctx_ex_data_idx = -1; - -/* - * Declarations of type objects (definitions come later). - */ - -static PyTypeObject - POW_X509_Type, - POW_X509Store_Type, - POW_X509StoreCTX_Type, - POW_CRL_Type, - POW_Asymmetric_Type, - POW_AsymmetricParams_Type, - POW_Digest_Type, - POW_CMS_Type, - POW_IPAddress_Type, - POW_ROA_Type, - POW_Manifest_Type, - POW_ROA_Type, - POW_PKCS10_Type; - -/* - * Object internals. - */ - -typedef struct { - PyObject_HEAD - unsigned char address[16]; - const struct ipaddress_version *type; -} ipaddress_object; - -typedef struct { - PyObject_HEAD - X509 *x509; -} x509_object; - -typedef struct { - PyObject_HEAD - X509_STORE *store; - PyObject *ctxclass; -} x509_store_object; - -typedef struct { - PyObject_HEAD - X509_STORE_CTX *ctx; - x509_store_object *store; -} x509_store_ctx_object; - -typedef struct { - PyObject_HEAD - X509_CRL *crl; -} crl_object; - -typedef struct { - PyObject_HEAD - EVP_PKEY *pkey; -} asymmetric_object; - -typedef struct { - PyObject_HEAD - EVP_PKEY *pkey; -} asymmetric_params_object; - -typedef struct { - PyObject_HEAD - EVP_MD_CTX digest_ctx; - int digest_type; -} digest_object; - -typedef struct { - PyObject_HEAD - CMS_ContentInfo *cms; -} cms_object; - -typedef struct { - cms_object cms; /* Subclass of CMS */ - ROA *roa; -} roa_object; - -typedef struct { - cms_object cms; /* Subclass of CMS */ - Manifest *manifest; -} manifest_object; - -typedef struct { - PyObject_HEAD - X509_REQ *pkcs10; - X509_EXTENSIONS *exts; -} pkcs10_object; - - - -/* - * Utility functions. - */ - -/* - * Minimal intervention debug-by-printf() hack, use only for good. - */ - -#if 0 -#define KVETCH(_msg_) write(2, _msg_ "\n", sizeof(_msg_)) -#else -#define KVETCH(_msg_) ((void) 0) -#endif - -#if 0 -#define ENTERING(_name_) KVETCH("Entering " #_name_ "()") -#else -#define ENTERING(_name_) ((void) 0) -#endif - -/* - * Error handling macros. All of macros assume that there's a cleanup - * label named "error" which these macros can use as a goto target. - */ - -#define lose(_msg_) \ - do { \ - PyErr_SetString(POWErrorObject, (_msg_)); \ - goto error; \ - } while (0) - -#define lose_no_memory() \ - do { \ - PyErr_NoMemory(); \ - goto error; \ - } while (0) - -#define lose_type_error(_msg_) \ - do { \ - PyErr_SetString(PyExc_TypeError, (_msg_)); \ - goto error; \ - } while (0) - -#define lose_value_error(_msg_) \ - do { \ - PyErr_SetString(PyExc_ValueError, (_msg_)); \ - goto error; \ - } while (0) - -#define lose_openssl_error(_msg_) \ - do { \ - set_openssl_exception(OpenSSLErrorObject, (_msg_), 0); \ - goto error; \ - } while (0) - -#define lose_not_verified(_msg_) \ - do { \ - PyErr_SetString(NotVerifiedErrorObject, (_msg_)); \ - goto error; \ - } while (0) - -#define assert_no_unhandled_openssl_errors() \ - do { \ - if (ERR_peek_error()) { \ - set_openssl_exception(OpenSSLErrorObject, NULL, __LINE__); \ - goto error; \ - } \ - } while (0) - -#define POW_assert(_cond_) \ - do { \ - if (!(_cond_)) { \ - (void) PyErr_Format(POWErrorObject, \ - "Assertion %s failed at " __FILE__ ":%d", \ - #_cond_, __LINE__); \ - goto error; \ - } \ - } while (0) - -/* - * Consolidate some tedious EVP-related switch statements. - */ - -static const EVP_MD * -evp_digest_factory(int digest_type) -{ - switch (digest_type) { - case MD5_DIGEST: return EVP_md5(); - case SHA_DIGEST: return EVP_sha(); - case SHA1_DIGEST: return EVP_sha1(); - case SHA256_DIGEST: return EVP_sha256(); - case SHA384_DIGEST: return EVP_sha384(); - case SHA512_DIGEST: return EVP_sha512(); - default: return NULL; - } -} - -/* - * Raise an exception with data pulled from the OpenSSL error stack. - * Exception value is a tuple with some internal structure. - * - * If a string error message is supplied, that string is the first - * element of the exception value tuple. - * - * If a non-zero line number is supplied, a string listing this as an - * unhandled exception detected at that line will be the next element - * of the exception value tuple (or the first, if no error message was - * supplied). - * - * Remainder of exception value tuple is zero or more tuples, each - * representing one error from the stack. - * - * Each error tuple contains six slots: - * - the numeric error code - * - string translation of numeric error code ("reason") - * - name of library in which error occurred - * - name of function in which error occurred - * - name of file in which error occurred - * - line number in file where error occurred - */ - -static void -set_openssl_exception(PyObject *error_class, const char *msg, const int unhandled_line) -{ - PyObject *errtuple = NULL; - PyObject *errlist = NULL; - unsigned long err; - const char *file; - int line; - - if ((errlist = PyList_New(0)) == NULL) - return; - - if (msg) { - PyObject *s = PyString_FromString(msg); - (void) PyList_Append(errlist, s); - Py_XDECREF(s); - } - - if (unhandled_line) { - PyObject *s = PyString_FromFormat("Unhandled OpenSSL error at " __FILE__ ":%d!", unhandled_line); - (void) PyList_Append(errlist, s); - Py_XDECREF(s); - } - - while ((err = ERR_get_error_line(&file, &line)) != 0) { - PyObject *t = Py_BuildValue("(issssi)", - err, - ERR_reason_error_string(err), - ERR_lib_error_string(err), - ERR_func_error_string(err), - file, - line); - (void) PyList_Append(errlist, t); - Py_XDECREF(t); - } - - if ((errtuple = PyList_AsTuple(errlist)) != NULL) - PyErr_SetObject(error_class, errtuple); - - Py_XDECREF(errtuple); - Py_XDECREF(errlist); -} - -static X509_NAME * -x509_object_helper_set_name(PyObject *dn_obj) -{ - PyObject *rdn_obj = NULL; - PyObject *pair_obj = NULL; - PyObject *type_obj = NULL; - PyObject *value_obj = NULL; - X509_NAME *name = NULL; - char *type_str, *value_str; - int asn1_type, i, j; - - if ((name = X509_NAME_new()) == NULL) - lose_no_memory(); - - for (i = 0; i < PySequence_Size(dn_obj); i++) { - - if ((rdn_obj = PySequence_GetItem(dn_obj, i)) == NULL) - goto error; - - if (!PySequence_Check(rdn_obj) || PySequence_Size(rdn_obj) == 0) - lose_type_error("each RDN must be a sequence with at least one element"); - - for (j = 0; j < PySequence_Size(rdn_obj); j++) { - - if ((pair_obj = PySequence_GetItem(rdn_obj, j)) == NULL) - goto error; - - if (!PySequence_Check(pair_obj) || PySequence_Size(pair_obj) != 2) - lose_type_error("each name entry must be a two-element sequence"); - - if ((type_obj = PySequence_GetItem(pair_obj, 0)) == NULL || - (type_str = PyString_AsString(type_obj)) == NULL || - (value_obj = PySequence_GetItem(pair_obj, 1)) == NULL || - (value_str = PyString_AsString(value_obj)) == NULL) - goto error; - - if ((asn1_type = ASN1_PRINTABLE_type((unsigned char *) value_str, -1)) != V_ASN1_PRINTABLESTRING) - asn1_type = V_ASN1_UTF8STRING; - - if (!X509_NAME_add_entry_by_txt(name, type_str, asn1_type, - (unsigned char *) value_str, - strlen((char *) value_str), - -1, (j ? -1 : 0))) - lose("Unable to add name entry"); - - Py_XDECREF(pair_obj); - Py_XDECREF(type_obj); - Py_XDECREF(value_obj); - pair_obj = type_obj = value_obj = NULL; - } - - Py_XDECREF(rdn_obj); - rdn_obj = NULL; - } - - return name; - - error: - X509_NAME_free(name); - Py_XDECREF(rdn_obj); - Py_XDECREF(pair_obj); - Py_XDECREF(type_obj); - Py_XDECREF(value_obj); - return NULL; -} - -static PyObject * -x509_object_helper_get_name(X509_NAME *name, int format) -{ - X509_NAME_ENTRY *entry = NULL; - PyObject *result = NULL; - PyObject *rdn = NULL; - PyObject *item = NULL; - const char *oid = NULL; - char oidbuf[512]; - int i, set = -1; - - /* - * Overall theory here: multi-value RDNs are very rare in the wild. - * We should support them, so we don't throw an exception if handed - * one in a BPKI certificate, but with minimal effort. What we care - * about here is optimizing for the common case of single-valued RDNs. - */ - - if ((result = PyTuple_New(X509_NAME_entry_count(name))) == NULL) - goto error; - - for (i = 0; i < X509_NAME_entry_count(name); i++) { - - if ((entry = X509_NAME_get_entry(name, i)) == NULL) - lose("Couldn't get certificate name"); - - if (entry->set < 0 || entry->set < set || entry->set > set + 1) - lose("X509_NAME->set value out of expected range"); - - switch (format) { - case SHORTNAME_FORMAT: - oid = OBJ_nid2sn(OBJ_obj2nid(entry->object)); - break; - case LONGNAME_FORMAT: - oid = OBJ_nid2ln(OBJ_obj2nid(entry->object)); - break; - case OIDNAME_FORMAT: - oid = NULL; - break; - default: - lose("Unknown name format"); - } - - if (oid == NULL) { - if (OBJ_obj2txt(oidbuf, sizeof(oidbuf), entry->object, 1) <= 0) - lose_openssl_error("Couldn't translate OID"); - oid = oidbuf; - } - - if (entry->set > set) { - - set++; - if ((item = Py_BuildValue("((ss#))", oid, ASN1_STRING_data(entry->value), - (Py_ssize_t) ASN1_STRING_length(entry->value))) == NULL) - goto error; - PyTuple_SET_ITEM(result, set, item); - item = NULL; - - } else { - - if ((rdn = PyTuple_GetItem(result, set)) == NULL) - goto error; - (void) _PyTuple_Resize(&rdn, PyTuple_Size(rdn) + 1); - PyTuple_SET_ITEM(result, set, rdn); - if (rdn == NULL) - goto error; - if ((item = Py_BuildValue("(ss#)", oid, ASN1_STRING_data(entry->value), - (Py_ssize_t) ASN1_STRING_length(entry->value))) == NULL) - goto error; - PyTuple_SetItem(rdn, PyTuple_Size(rdn) - 1, item); - rdn = item = NULL; - - } - } - - if (++set != PyTuple_Size(result)) { - if (set < 0 || set > PyTuple_Size(result)) - lose("Impossible set count for DN, something went horribly wrong"); - _PyTuple_Resize(&result, set); - } - - return result; - - error: - Py_XDECREF(item); - Py_XDECREF(result); - return NULL; -} - -static STACK_OF(X509) * -x509_helper_iterable_to_stack(PyObject *iterable) -{ - STACK_OF(X509) *stack = NULL; - PyObject *iterator = NULL; - PyObject *item = NULL; - - if ((stack = sk_X509_new_null()) == NULL) - lose_no_memory(); - - if (iterable != Py_None) { - - if ((iterator = PyObject_GetIter(iterable)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if (!POW_X509_Check(item)) - lose_type_error("Inapropriate type"); - - if (!sk_X509_push(stack, ((x509_object *) item)->x509)) - lose("Couldn't add X509 object to stack"); - - Py_XDECREF(item); - item = NULL; - } - } - - Py_XDECREF(iterator); - return stack; - - error: - Py_XDECREF(iterator); - Py_XDECREF(item); - sk_X509_free(stack); - return NULL; -} - -/* - * Pull items off an OpenSSL STACK and put them into a Python tuple. - * Assumes that handler is stealing the OpenSSL references to the - * items in the STACK, so shifts consumed frames off the stack so that - * the appropriate _pop_free() destructor can clean up on failures. - * This is OK because all current uses of this function are processing - * the result of OpenSSL xxx_get1_xxx() methods which we have to free - * in any case. - */ - -static x509_object *x509_object_new_helper(PyTypeObject *, X509 *); -static crl_object *crl_object_new_helper (PyTypeObject *, X509_CRL *); - -static PyObject * -stack_to_tuple_helper(_STACK *sk, PyObject *(*handler)(void *)) -{ - PyObject *result = NULL; - PyObject *obj = NULL; - int i; - - if ((result = PyTuple_New(sk_num(sk))) == NULL) - goto error; - - for (i = 0; sk_num(sk); i++) { - if ((obj = handler(sk_value(sk, 0))) == NULL) - goto error; - sk_shift(sk); - if (PyTuple_SetItem(result, i, obj) != 0) - goto error; - obj = NULL; - } - - return result; - - error: - - Py_XDECREF(obj); - return NULL; -} - -static PyObject * -stack_to_tuple_helper_get_x509(void *cert) -{ - x509_object *obj; - - ENTERING(stack_to_tuple_helper_get_x509); - - if ((obj = x509_object_new_helper(NULL, cert)) == NULL) - return NULL; - - return (PyObject *) obj; -} - -static PyObject * -stack_to_tuple_helper_get_crl(void *crl) -{ - crl_object *obj; - - ENTERING(stack_to_tuple_helper_get_crl); - - if ((obj = crl_object_new_helper(NULL, crl)) == NULL) - return NULL; - - return (PyObject *) obj; -} - -/* - * Time conversion functions. Obvious mapping into Python data types - * is datetime, or, rather, our customized rpki.sundial.datetime. - * - * Unsuprisingly, it's easiest for us to map between GeneralizedTime - * (as restricted by RFC 5280) and datetime. Conversion between - * GeneralizedTime and UTCTime is handled automatically according to - * the RFC 5280 rules for those ASN.1 types where it's required. - */ - -static PyObject * -ASN1_TIME_to_Python(ASN1_TIME *t) -{ - ASN1_GENERALIZEDTIME *g = NULL; - PyObject *result = NULL; - int year, month, day, hour, minute, second; - - if ((g = ASN1_TIME_to_generalizedtime(t, NULL)) == NULL) - lose_openssl_error("Couldn't convert ASN.1 TIME"); - - if (sscanf((char *) g->data, "%4d%2d%2d%2d%2d%2dZ", - &year, &month, &day, &hour, &minute, &second) != 6) - lose("Couldn't scan ASN.1 TIME value"); - - if (custom_datetime != NULL && custom_datetime != Py_None) - result = PyObject_CallFunction(custom_datetime, "iiiiii", - year, month, day, hour, minute, second); - else - result = PyDateTime_FromDateAndTime(year, month, day, hour, minute, second, 0); - - error: - ASN1_GENERALIZEDTIME_free(g); - return result; -} - -static ASN1_TIME * -Python_to_ASN1_TIME(PyObject *arg, const int object_requires_utctime) -{ - char buf[sizeof("20010401123456Z") + 1]; - ASN1_TIME *result = NULL; - const char *s = NULL; - int ok; - - if (PyDateTime_Check(arg)) { - if (snprintf(buf, sizeof(buf), "%4d%02d%02d%02d%02d%02dZ", - PyDateTime_GET_YEAR(arg), - PyDateTime_GET_MONTH(arg), - PyDateTime_GET_DAY(arg), - PyDateTime_DATE_GET_HOUR(arg), - PyDateTime_DATE_GET_MINUTE(arg), - PyDateTime_DATE_GET_SECOND(arg)) >= (int) sizeof(buf)) - lose("Internal error -- GeneralizedTime buffer too small"); - s = buf; - } - - if (s == NULL && (s = PyString_AsString(arg)) == NULL) - goto error; - - if (strlen(s) < 10) - lose_type_error("String is too short to parse as a valid ASN.1 TIME"); - - if ((result = ASN1_TIME_new()) == NULL) - lose_no_memory(); - - if (object_requires_utctime && - ((s[0] == '1' && s[1] == '9' && s[2] > '4') || - (s[0] == '2' && s[1] == '0' && s[2] < '5'))) - ok = ASN1_UTCTIME_set_string(result, s + 2); - else - ok = ASN1_GENERALIZEDTIME_set_string(result, s); - - if (ok) - return result; - - error: - ASN1_TIME_free(result); - return NULL; -} - -/* - * Extract a Python string from a memory BIO. - */ -static PyObject * -BIO_to_PyString_helper(BIO *bio) -{ - char *ptr = NULL; - Py_ssize_t len = 0; - - if ((len = BIO_get_mem_data(bio, &ptr)) == 0) - lose_openssl_error("Unable to get BIO data"); - - return Py_BuildValue("s#", ptr, len); - - error: - return NULL; -} - -static PyObject * -read_from_string_helper(PyObject *(*object_read_helper)(PyTypeObject *, BIO *), - PyTypeObject *type, - PyObject *args) -{ - PyObject *result = NULL; - char *src = NULL; - BIO *bio = NULL; - Py_ssize_t len = 0; - - if (!PyArg_ParseTuple(args, "s#", &src, &len)) - goto error; - - if ((bio = BIO_new_mem_buf(src, len)) == NULL) - lose_no_memory(); - - result = object_read_helper(type, bio); - - error: - BIO_free(bio); - return result; -} - -static PyObject * -read_from_file_helper(PyObject *(*object_read_helper)(PyTypeObject *, BIO *), - PyTypeObject *type, - PyObject *args) -{ - const char *filename = NULL; - PyObject *result = NULL; - BIO *bio = NULL; - - if (!PyArg_ParseTuple(args, "s", &filename)) - goto error; - - if ((bio = BIO_new_file(filename, "rb")) == NULL) - lose_openssl_error("Could not open file"); - - result = object_read_helper(type, bio); - - error: - BIO_free(bio); - return result; -} - -/* - * Simplify entries in method definition tables. See the "Common - * Object Structures" section of the API manual for available flags. - */ -#define Define_Method(__python_name__, __c_name__, __flags__) \ - { #__python_name__, (PyCFunction) __c_name__, __flags__, __c_name__##__doc__ } - -#define Define_Class_Method(__python_name__, __c_name__, __flags__) \ - Define_Method(__python_name__, __c_name__, (__flags__) | METH_CLASS) - -/* - * Convert an ASN1_INTEGER into a Python integer or long. - */ -static PyObject * -ASN1_INTEGER_to_PyLong(ASN1_INTEGER *arg) -{ - PyObject *result = NULL; - PyObject *obj = NULL; - - if ((obj = _PyLong_FromByteArray(ASN1_STRING_data(arg), - ASN1_STRING_length(arg), - 0, 0)) != NULL) - result = PyNumber_Int(obj); - - Py_XDECREF(obj); - return result; -} - -/* - * Convert a Python long to an ASN1_INTEGER. - * This is just nasty, do not read on a full stomach. - * - * Maximum size of integer to be converted here is taken from RFC 5280 - * 4.1.2.2, which sets a maximum of 20 octets for an X.509 certificate - * serial number. - * - * In theory we could use _PyLong_NumBits() to determine the length of - * the long before converting, and raise OverflowError if it's too big. - * Hmm. - */ -static ASN1_INTEGER * -PyLong_to_ASN1_INTEGER(PyObject *arg) -{ - PyObject *obj = NULL; - ASN1_INTEGER *a = NULL; - unsigned char buf[MAX_ASN1_INTEGER_LEN]; - size_t len; - - memset(buf, 0, sizeof(buf)); - - /* - * Make sure argument is a PyLong small enough that its length (in - * bits!) doesn't overflow a size_t (which is a mis-use of size_t, - * but take that up with whoever wrote _PyLong_NumBits()...). - */ - if ((obj = PyNumber_Long(arg)) == NULL || - (len = _PyLong_NumBits(obj)) == (size_t) -1) - goto error; - - /* - * Next make sure it's a non-negative integer small enough to fit in - * our buffer. If we really thought we needed to support larger - * integers we could allocate this dynamically, but we don't, so - * it's not worth the overhead. - * - * Paranoia: We can't convert len to bytes yet, because that - * requires rounding up and we don't know yet that we have enough - * headroom to do that arithmetic without overflowing a size_t. - */ - if (_PyLong_Sign(obj) < 0 || (len / 8) + 1 > sizeof(buf)) { - PyErr_SetObject(PyExc_OverflowError, obj); - goto error; - } - - /* - * Now that we know we're dealing with a sane number of bits, - * convert it to bytes. - */ - len = (len + 7) / 8; - - /* - * Extract that many bytes. - */ - if (_PyLong_AsByteArray((PyLongObject *) obj, buf, len, 0, 0) < 0) - goto error; - - /* - * We're done with the PyLong now. - */ - Py_XDECREF(obj); - obj = NULL; - - /* - * Generate the ASN1_INTEGER and return it. - */ - if ((a = ASN1_INTEGER_new()) == NULL || - (a->length < (int) len + 1 && (a->data = OPENSSL_realloc(a->data, len + 1)) == NULL)) - lose_no_memory(); - - a->type = V_ASN1_INTEGER; - a->length = len; - a->data[len] = 0; - memcpy(a->data, buf, len); - - return a; - - error: - Py_XDECREF(obj); - ASN1_INTEGER_free(a); - return NULL; -} - -/* - * Handle missing NIDs. - */ - -static int -create_missing_nids(void) -{ - int i; - - for (i = 0; i < (int) (sizeof(missing_nids) / sizeof(*missing_nids)); i++) - if ((*missing_nids[i].nid = OBJ_txt2nid(missing_nids[i].oid)) == NID_undef && - (*missing_nids[i].nid = OBJ_create(missing_nids[i].oid, - missing_nids[i].sn, - missing_nids[i].ln)) == NID_undef) - return 0; - - return 1; -} - -static PyObject * -ASN1_OBJECT_to_PyString(const ASN1_OBJECT *oid) -{ - PyObject *result = NULL; - char buf[512]; - - ENTERING(ASN1_OBJECT_to_PyString); - - if (OBJ_obj2txt(buf, sizeof(buf), oid, 1) <= 0) - lose_openssl_error("Couldn't translate OID"); - - result = PyString_FromString(buf); - - error: - return result; -} - - - -/* - * Extension functions. Calling sequence here is a little weird, - * because it turns out that the simplest way to avoid massive - * duplication of code between classes is to work directly with - * X509_EXTENSIONS objects. - */ - -static PyObject * -extension_get_key_usage(X509_EXTENSIONS **exts) -{ - ASN1_BIT_STRING *ext = NULL; - PyObject *result = NULL; - PyObject *token = NULL; - int bit = -1; - - ENTERING(extension_get_key_usage); - - if (!exts) - goto error; - - if ((ext = X509V3_get_d2i(*exts, NID_key_usage, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - if ((result = PyFrozenSet_New(NULL)) == NULL) - goto error; - - for (bit = 0; key_usage_bit_names[bit] != NULL; bit++) { - if (ASN1_BIT_STRING_get_bit(ext, bit) && - ((token = PyString_FromString(key_usage_bit_names[bit])) == NULL || - PySet_Add(result, token) < 0)) - goto error; - Py_XDECREF(token); - token = NULL; - } - - ASN1_BIT_STRING_free(ext); - return result; - - error: - ASN1_BIT_STRING_free(ext); - Py_XDECREF(token); - Py_XDECREF(result); - return NULL; -} - -static PyObject * -extension_set_key_usage(X509_EXTENSIONS **exts, PyObject *args) -{ - ASN1_BIT_STRING *ext = NULL; - PyObject *iterable = NULL; - PyObject *critical = Py_True; - PyObject *iterator = NULL; - PyObject *item = NULL; - const char *token; - int bit = -1; - int ok = 0; - - ENTERING(extension_set_key_usage); - - if (!exts) - goto error; - - if ((ext = ASN1_BIT_STRING_new()) == NULL) - lose_no_memory(); - - if (!PyArg_ParseTuple(args, "O|O", &iterable, &critical) || - (iterator = PyObject_GetIter(iterable)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if ((token = PyString_AsString(item)) == NULL) - goto error; - - for (bit = 0; key_usage_bit_names[bit] != NULL; bit++) - if (!strcmp(token, key_usage_bit_names[bit])) - break; - - if (key_usage_bit_names[bit] == NULL) - lose("Unrecognized KeyUsage token"); - - if (!ASN1_BIT_STRING_set_bit(ext, bit, 1)) - lose_no_memory(); - - Py_XDECREF(item); - item = NULL; - } - - if (!X509V3_add1_i2d(exts, NID_key_usage, ext, - PyObject_IsTrue(critical), - X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add KeyUsage extension to OpenSSL object"); - - ok = 1; - - error: /* Fall through */ - ASN1_BIT_STRING_free(ext); - Py_XDECREF(iterator); - Py_XDECREF(item); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static PyObject * -extension_get_basic_constraints(X509_EXTENSIONS **exts) -{ - BASIC_CONSTRAINTS *ext = NULL; - PyObject *result = NULL; - - ENTERING(extension_get_basic_constraints); - - if (!exts) - goto error; - - if ((ext = X509V3_get_d2i(*exts, NID_basic_constraints, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - if (ext->pathlen == NULL) - result = Py_BuildValue("(NO)", PyBool_FromLong(ext->ca), Py_None); - else - result = Py_BuildValue("(Nl)", PyBool_FromLong(ext->ca), ASN1_INTEGER_get(ext->pathlen)); - - error: - BASIC_CONSTRAINTS_free(ext); - return result; -} - -static PyObject * -extension_set_basic_constraints(X509_EXTENSIONS **exts, PyObject *args) -{ - BASIC_CONSTRAINTS *ext = NULL; - PyObject *is_ca = NULL; - PyObject *pathlen_obj = Py_None; - PyObject *critical = Py_True; - long pathlen = -1; - int ok = 0; - - ENTERING(extension_set_basic_constraints); - - if (!exts) - goto error; - - if (!PyArg_ParseTuple(args, "O|OO", &is_ca, &pathlen_obj, &critical)) - goto error; - - if (pathlen_obj != Py_None && (pathlen = PyInt_AsLong(pathlen_obj)) < 0) - lose_type_error("Bad pathLenConstraint value"); - - if ((ext = BASIC_CONSTRAINTS_new()) == NULL) - lose_no_memory(); - - ext->ca = PyObject_IsTrue(is_ca) ? 0xFF : 0; - - if (pathlen_obj != Py_None && - ((ext->pathlen == NULL && (ext->pathlen = ASN1_INTEGER_new()) == NULL) || - !ASN1_INTEGER_set(ext->pathlen, pathlen))) - lose_no_memory(); - - if (!X509V3_add1_i2d(exts, NID_basic_constraints, ext, - PyObject_IsTrue(critical), X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add BasicConstraints extension to OpenSSL object"); - - ok = 1; - - error: - BASIC_CONSTRAINTS_free(ext); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static PyObject * -extension_get_sia(X509_EXTENSIONS **exts) -{ - AUTHORITY_INFO_ACCESS *ext = NULL; - PyObject *result = NULL; - PyObject *result_caRepository = NULL; - PyObject *result_rpkiManifest = NULL; - PyObject *result_signedObject = NULL; - int n_caRepository = 0; - int n_rpkiManifest = 0; - int n_signedObject = 0; - const char *uri; - PyObject *obj; - int i, nid; - - ENTERING(pkcs10_object_get_sia); - - if (!exts) - goto error; - - if ((ext = X509V3_get_d2i(*exts, NID_sinfo_access, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - /* - * Easiest to do this in two passes, first pass just counts URIs. - */ - - for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ext); i++) { - ACCESS_DESCRIPTION *a = sk_ACCESS_DESCRIPTION_value(ext, i); - if (a->location->type != GEN_URI) - continue; - nid = OBJ_obj2nid(a->method); - if (nid == NID_caRepository) { - n_caRepository++; - continue; - } - if (nid == NID_rpkiManifest) { - n_rpkiManifest++; - continue; - } - if (nid == NID_signedObject) { - n_signedObject++; - continue; - } - } - - if (((result_caRepository = PyTuple_New(n_caRepository)) == NULL) || - ((result_rpkiManifest = PyTuple_New(n_rpkiManifest)) == NULL) || - ((result_signedObject = PyTuple_New(n_signedObject)) == NULL)) - goto error; - - n_caRepository = n_rpkiManifest = n_signedObject = 0; - - for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ext); i++) { - ACCESS_DESCRIPTION *a = sk_ACCESS_DESCRIPTION_value(ext, i); - if (a->location->type != GEN_URI) - continue; - nid = OBJ_obj2nid(a->method); - uri = (char *) ASN1_STRING_data(a->location->d.uniformResourceIdentifier); - if (nid == NID_caRepository) { - if ((obj = PyString_FromString(uri)) == NULL) - goto error; - PyTuple_SET_ITEM(result_caRepository, n_caRepository++, obj); - continue; - } - if (nid == NID_rpkiManifest) { - if ((obj = PyString_FromString(uri)) == NULL) - goto error; - PyTuple_SET_ITEM(result_rpkiManifest, n_rpkiManifest++, obj); - continue; - } - if (nid == NID_signedObject) { - if ((obj = PyString_FromString(uri)) == NULL) - goto error; - PyTuple_SET_ITEM(result_signedObject, n_signedObject++, obj); - continue; - } - } - - result = Py_BuildValue("(OOO)", - result_caRepository, - result_rpkiManifest, - result_signedObject); - - error: - AUTHORITY_INFO_ACCESS_free(ext); - Py_XDECREF(result_caRepository); - Py_XDECREF(result_rpkiManifest); - Py_XDECREF(result_signedObject); - return result; -} - -static PyObject * -extension_set_sia(X509_EXTENSIONS **exts, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"caRepository", "rpkiManifest", "signedObject", NULL}; - AUTHORITY_INFO_ACCESS *ext = NULL; - PyObject *caRepository = Py_None; - PyObject *rpkiManifest = Py_None; - PyObject *signedObject = Py_None; - PyObject *iterator = NULL; - ASN1_OBJECT *oid = NULL; - PyObject **pobj = NULL; - PyObject *item = NULL; - ACCESS_DESCRIPTION *a = NULL; - int i, nid = NID_undef, ok = 0; - Py_ssize_t urilen; - char *uri; - - ENTERING(extension_set_sia); - - if (!exts) - goto error; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", kwlist, - &caRepository, &rpkiManifest, &signedObject)) - goto error; - - if ((ext = AUTHORITY_INFO_ACCESS_new()) == NULL) - lose_no_memory(); - - /* - * This is going to want refactoring, because it's ugly, because we - * want to reuse code for AIA, and because it'd be nice to support a - * single URI as an abbreviation for a collection containing one URI. - */ - - for (i = 0; i < 3; i++) { - switch (i) { - case 0: pobj = &caRepository; nid = NID_caRepository; break; - case 1: pobj = &rpkiManifest; nid = NID_rpkiManifest; break; - case 2: pobj = &signedObject; nid = NID_signedObject; break; - } - - if (*pobj == Py_None) - continue; - - if ((oid = OBJ_nid2obj(nid)) == NULL) - lose_openssl_error("Couldn't find SIA accessMethod OID"); - - if ((iterator = PyObject_GetIter(*pobj)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if (PyString_AsStringAndSize(item, &uri, &urilen) < 0) - goto error; - - if ((a = ACCESS_DESCRIPTION_new()) == NULL || - (a->method = OBJ_dup(oid)) == NULL || - (a->location->d.uniformResourceIdentifier = ASN1_IA5STRING_new()) == NULL || - !ASN1_OCTET_STRING_set(a->location->d.uniformResourceIdentifier, (unsigned char *) uri, urilen)) - lose_no_memory(); - - a->location->type = GEN_URI; - - if (!sk_ACCESS_DESCRIPTION_push(ext, a)) - lose_no_memory(); - - a = NULL; - Py_XDECREF(item); - item = NULL; - } - - Py_XDECREF(iterator); - iterator = NULL; - } - - if (!X509V3_add1_i2d(exts, NID_sinfo_access, ext, 0, X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add SIA extension to OpenSSL object"); - - ok = 1; - - error: - AUTHORITY_INFO_ACCESS_free(ext); - ACCESS_DESCRIPTION_free(a); - Py_XDECREF(item); - Py_XDECREF(iterator); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static PyObject * -extension_get_eku(X509_EXTENSIONS **exts) -{ - EXTENDED_KEY_USAGE *ext = NULL; - PyObject *result = NULL; - PyObject *oid = NULL; - int i; - - ENTERING(extension_get_eku); - - if (!exts) - goto error; - - if ((ext = X509V3_get_d2i(*exts, NID_ext_key_usage, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - if ((result = PyFrozenSet_New(NULL)) == NULL) - goto error; - - for (i = 0; i < sk_ASN1_OBJECT_num(ext); i++) { - if ((oid = ASN1_OBJECT_to_PyString(sk_ASN1_OBJECT_value(ext, i))) == NULL || - PySet_Add(result, oid) < 0) - goto error; - Py_XDECREF(oid); - oid = NULL; - } - - sk_ASN1_OBJECT_pop_free(ext, ASN1_OBJECT_free); - return result; - - error: - sk_ASN1_OBJECT_pop_free(ext, ASN1_OBJECT_free); - Py_XDECREF(oid); - Py_XDECREF(result); - return NULL; -} - -static PyObject * -extension_set_eku(X509_EXTENSIONS **exts, PyObject *args) -{ - EXTENDED_KEY_USAGE *ext = NULL; - PyObject *iterable = NULL; - PyObject *critical = Py_False; - PyObject *iterator = NULL; - PyObject *item = NULL; - ASN1_OBJECT *obj = NULL; - const char *txt; - int ok = 0; - - ENTERING(extension_set_eku); - - if (!exts) - goto error; - - if ((ext = sk_ASN1_OBJECT_new_null()) == NULL) - lose_no_memory(); - - if (!PyArg_ParseTuple(args, "O|O", &iterable, &critical) || - (iterator = PyObject_GetIter(iterable)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if ((txt = PyString_AsString(item)) == NULL) - goto error; - - if ((obj = OBJ_txt2obj(txt, 1)) == NULL) - lose("Couldn't parse OID"); - - if (!sk_ASN1_OBJECT_push(ext, obj)) - lose_no_memory(); - - obj = NULL; - Py_XDECREF(item); - item = NULL; - } - - if (sk_ASN1_OBJECT_num(ext) < 1) - lose("Empty ExtendedKeyUsage extension"); - - if (!X509V3_add1_i2d(exts, NID_ext_key_usage, ext, - PyObject_IsTrue(critical), - X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add ExtendedKeyUsage extension to OpenSSL object"); - - ok = 1; - - error: /* Fall through */ - sk_ASN1_OBJECT_pop_free(ext, ASN1_OBJECT_free); - Py_XDECREF(item); - Py_XDECREF(iterator); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static PyObject * -extension_get_ski(X509_EXTENSIONS **exts) -{ - ASN1_OCTET_STRING *ext = NULL; - PyObject *result = NULL; - - ENTERING(extension_get_ski); - - if (!exts) - goto error; - - if ((ext = X509V3_get_d2i(*exts, NID_subject_key_identifier, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - result = Py_BuildValue("s#", ASN1_STRING_data(ext), - (Py_ssize_t) ASN1_STRING_length(ext)); - - error: /* Fall through */ - ASN1_OCTET_STRING_free(ext); - return result; -} - -static PyObject * -extension_set_ski(X509_EXTENSIONS **exts, PyObject *args) -{ - ASN1_OCTET_STRING *ext = NULL; - const unsigned char *buf = NULL; - Py_ssize_t len; - int ok = 0; - - ENTERING(extension_set_ski); - - if (!exts) - goto error; - - if (!PyArg_ParseTuple(args, "s#", &buf, &len)) - goto error; - - if ((ext = ASN1_OCTET_STRING_new()) == NULL || - !ASN1_OCTET_STRING_set(ext, buf, len)) - lose_no_memory(); - - /* - * RFC 5280 says this MUST be non-critical. - */ - - if (!X509V3_add1_i2d(exts, NID_subject_key_identifier, - ext, 0, X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add SKI extension to OpenSSL object"); - - ok = 1; - - error: - ASN1_OCTET_STRING_free(ext); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static PyObject * -extension_get_aki(X509_EXTENSIONS **exts) -{ - AUTHORITY_KEYID *ext = NULL; - PyObject *result = NULL; - - ENTERING(extension_get_aki); - - if (!exts) - goto error; - - if ((ext = X509V3_get_d2i(*exts, NID_authority_key_identifier, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - result = Py_BuildValue("s#", ASN1_STRING_data(ext->keyid), - (Py_ssize_t) ASN1_STRING_length(ext->keyid)); - - error: /* Fall through */ - AUTHORITY_KEYID_free(ext); - return result; -} - -static PyObject * -extension_set_aki(X509_EXTENSIONS **exts, PyObject *args) -{ - AUTHORITY_KEYID *ext = NULL; - const unsigned char *buf = NULL; - Py_ssize_t len; - int ok = 0; - - ENTERING(extension_set_aki); - - assert (exts); - - if (!PyArg_ParseTuple(args, "s#", &buf, &len)) - goto error; - - if ((ext = AUTHORITY_KEYID_new()) == NULL || - (ext->keyid == NULL && (ext->keyid = ASN1_OCTET_STRING_new()) == NULL) || - !ASN1_OCTET_STRING_set(ext->keyid, buf, len)) - lose_no_memory(); - - /* - * RFC 5280 says this MUST be non-critical. - */ - - if (!X509V3_add1_i2d(exts, NID_authority_key_identifier, - ext, 0, X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add AKI extension to OpenSSL object"); - - ok = 1; - - error: - AUTHORITY_KEYID_free(ext); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - - - -/* - * IPAddress object. - */ - -static PyObject * -ipaddress_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"initializer", "version", NULL}; - ipaddress_object *self = NULL; - PyObject *init = NULL; - PyObject *pylong = NULL; - int version = 0; - const char *s = NULL; - int v; - - ENTERING(ipaddress_object_new); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &init, &version) || - (self = (ipaddress_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - if (POW_IPAddress_Check(init)) { - ipaddress_object *src = (ipaddress_object *) init; - memcpy(self->address, src->address, sizeof(self->address)); - self->type = src->type; - return (PyObject *) self; - } - - if ((s = PyString_AsString(init)) == NULL) - PyErr_Clear(); - else if (version == 0) - version = strchr(s, ':') ? 6 : 4; - - self->type = NULL; - - for (v = 0; v < (int) (sizeof(ipaddress_versions)/sizeof(*ipaddress_versions)); v++) - if ((unsigned) version == ipaddress_versions[v]->version) - self->type = ipaddress_versions[v]; - - if (self->type == NULL) - lose("Unknown IP version number"); - - if (s != NULL) { - if (inet_pton(self->type->af, s, self->address) <= 0) - lose("Couldn't parse IP address"); - return (PyObject *) self; - } - - if ((pylong = PyNumber_Long(init)) != NULL) { - if (_PyLong_AsByteArray((PyLongObject *) pylong, self->address, self->type->length, 0, 0) < 0) - goto error; - Py_XDECREF(pylong); - return (PyObject *) self; - } - - lose_type_error("Couldn't convert initializer to IPAddress"); - - error: - Py_XDECREF(self); - Py_XDECREF(pylong); - return NULL; -} - -static PyObject * -ipaddress_object_str(ipaddress_object *self) -{ - char addrstr[sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:255.255.255.255") + 1]; - - ENTERING(ipaddress_object_str); - - if (!inet_ntop(self->type->af, self->address, addrstr, sizeof(addrstr))) - lose("Couldn't convert IP address"); - - return PyString_FromString(addrstr); - - error: - return NULL; -} - -static PyObject * -ipaddress_object_repr(ipaddress_object *self) -{ - char addrstr[sizeof("aaaa:bbbb:cccc:dddd:eeee:ffff:255.255.255.255") + 1]; - - ENTERING(ipaddress_object_repr); - - if (!inet_ntop(self->type->af, self->address, addrstr, sizeof(addrstr))) - lose("Couldn't convert IP address"); - - return PyString_FromFormat("<%s object %s at %p>", - self->ob_type->tp_name, addrstr, self); - - error: - return NULL; -} - -static int -ipaddress_object_compare(PyObject *arg1, PyObject *arg2) -{ - PyObject *obj1 = PyNumber_Long(arg1); - PyObject *obj2 = PyNumber_Long(arg2); - int cmp = -1; - - ENTERING(ipaddress_object_compare); - - if (obj1 != NULL && obj2 != NULL) - cmp = PyObject_Compare(obj1, obj2); - - Py_XDECREF(obj1); - Py_XDECREF(obj2); - return cmp; -} - -static PyObject * -ipaddress_object_richcompare(PyObject *arg1, PyObject *arg2, int op) -{ - PyObject *obj1 = PyNumber_Long(arg1); - PyObject *obj2 = PyNumber_Long(arg2); - PyObject *result = NULL; - - ENTERING(ipaddress_object_richcompare); - - if (obj1 != NULL && obj2 != NULL) - result = PyObject_RichCompare(obj1, obj2, op); - - Py_XDECREF(obj1); - Py_XDECREF(obj2); - return result; -} - -static long -ipaddress_object_hash(ipaddress_object *self) -{ - unsigned long h = 0; - int i; - - ENTERING(ipaddress_object_hash); - - for (i = 0; (unsigned) i < self->type->length; i++) - h ^= self->address[i] << ((i & 3) << 3); - - return (long) h == -1 ? 0 : (long) h; -} - -static char ipaddress_object_from_bytes__doc__[] = - "Construct an IPAddress object from a sequence of bytes.\n" - "\n" - "Argument must be a Python string of exactly 4 or 16 bytes.\n" - ; - -static PyObject * -ipaddress_object_from_bytes(PyTypeObject *type, PyObject *args) -{ - ipaddress_object *result = NULL; - char *bytes = NULL; - Py_ssize_t len; - int v; - - ENTERING(ipaddress_object_from_bytes); - - if (!PyArg_ParseTuple(args, "s#", &bytes, &len)) - goto error; - - if ((result = (ipaddress_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - result->type = NULL; - - for (v = 0; v < (int) (sizeof(ipaddress_versions)/sizeof(*ipaddress_versions)); v++) - if (len == ipaddress_versions[v]->length) - result->type = ipaddress_versions[v]; - - if (result->type == NULL) - lose("Unknown IP version number"); - - memcpy(result->address, bytes, len); - return (PyObject *) result; - - error: - Py_XDECREF(result); - return NULL; -} - -static char ipaddress_object_to_bytes__doc__[] = - "Return the binary value of this IPAddress as a Python string\n" - "of exactly 4 or 16 bytes.\n" - ; - -static PyObject * -ipaddress_object_to_bytes(ipaddress_object *self) -{ - ENTERING(ipaddress_object_from_bytes); - return PyString_FromStringAndSize((char *) self->address, self->type->length); -} - -static PyObject * -ipaddress_object_get_bits(ipaddress_object *self, GCC_UNUSED void *closure) -{ - ENTERING(ipaddress_object_get_bits); - return PyInt_FromLong(self->type->length * 8); -} - -static PyObject * -ipaddress_object_get_version(ipaddress_object *self, GCC_UNUSED void *closure) -{ - ENTERING(ipaddress_object_get_version); - return PyInt_FromLong(self->type->version); -} - -static PyObject * -ipaddress_object_number_binary_helper(binaryfunc function, PyObject *arg1, PyObject *arg2) -{ - ipaddress_object *addr = NULL; - ipaddress_object *addr1 = NULL; - ipaddress_object *addr2 = NULL; - ipaddress_object *result = NULL; - PyObject *obj1 = NULL; - PyObject *obj2 = NULL; - PyObject *obj3 = NULL; - PyObject *obj4 = NULL; - - if (POW_IPAddress_Check(arg1)) - addr1 = (ipaddress_object *) arg1; - - if (POW_IPAddress_Check(arg2)) - addr2 = (ipaddress_object *) arg2; - - if ((addr1 == NULL && addr2 == NULL) || - (addr1 != NULL && addr2 != NULL && addr1->type != addr2->type) || - (obj1 = PyNumber_Long(arg1)) == NULL || - (obj2 = PyNumber_Long(arg2)) == NULL) { - result = (ipaddress_object *) Py_NotImplemented; - Py_INCREF(result); - goto error; - } - - if ((obj3 = function(obj1, obj2)) == NULL) - goto error; - - if ((obj4 = PyNumber_Long(obj3)) == NULL) - lose("Couldn't convert result"); - - addr = addr1 != NULL ? addr1 : addr2; - - if ((result = (ipaddress_object *) addr->ob_type->tp_alloc(addr->ob_type, 0)) == NULL) - goto error; - - result->type = addr->type; - - if (_PyLong_AsByteArray((PyLongObject *) obj4, result->address, result->type->length, 0, 0) < 0) { - Py_XDECREF(result); - result = NULL; - } - - error: /* Fall through */ - Py_XDECREF(obj1); - Py_XDECREF(obj2); - Py_XDECREF(obj3); - Py_XDECREF(obj4); - - return (PyObject *) result; -} - -static PyObject * -ipaddress_object_number_long(PyObject *arg) -{ - ipaddress_object *addr = (ipaddress_object *) arg; - - ENTERING(ipaddress_object_number_long); - - if (!POW_IPAddress_Check(arg)) - return Py_INCREF(Py_NotImplemented), Py_NotImplemented; - - return _PyLong_FromByteArray(addr->address, addr->type->length, 0, 0); -} - -static PyObject * -ipaddress_object_number_int(PyObject *arg) -{ - ENTERING(ipaddress_object_number_int); - return ipaddress_object_number_long(arg); -} - -static PyObject * -ipaddress_object_number_add(PyObject *arg1, PyObject *arg2) -{ - ENTERING(ipaddress_object_number_add); - return ipaddress_object_number_binary_helper(PyNumber_Add, arg1, arg2); -} - -static PyObject * -ipaddress_object_number_subtract(PyObject *arg1, PyObject *arg2) -{ - ENTERING(ipaddress_object_number_subtract); - return ipaddress_object_number_binary_helper(PyNumber_Subtract, arg1, arg2); -} - -static PyObject * -ipaddress_object_number_lshift(PyObject *arg1, PyObject *arg2) -{ - ENTERING(ipaddress_object_number_lshift); - return ipaddress_object_number_binary_helper(PyNumber_Lshift, arg1, arg2); -} - -static PyObject * -ipaddress_object_number_rshift(PyObject *arg1, PyObject *arg2) -{ - ENTERING(ipaddress_object_number_rshift); - return ipaddress_object_number_binary_helper(PyNumber_Rshift, arg1, arg2); -} - -static PyObject * -ipaddress_object_number_and(PyObject *arg1, PyObject *arg2) -{ - ENTERING(ipaddress_object_number_and); - return ipaddress_object_number_binary_helper(PyNumber_And, arg1, arg2); -} - -static PyObject * -ipaddress_object_number_xor(PyObject *arg1, PyObject *arg2) -{ - ENTERING(ipaddress_object_number_xor); - return ipaddress_object_number_binary_helper(PyNumber_Xor, arg1, arg2); -} - -static PyObject * -ipaddress_object_number_or(PyObject *arg1, PyObject *arg2) -{ - ENTERING(ipaddress_object_number_or); - return ipaddress_object_number_binary_helper(PyNumber_Or, arg1, arg2); -} - -static int -ipaddress_object_number_nonzero(ipaddress_object *self) -{ - int i; - - ENTERING(ipaddress_object_number_nonzero); - - for (i = 0; (unsigned) i < self->type->length; i++) - if (self->address[i] != 0) - return 1; - return 0; -} - -static PyObject * -ipaddress_object_number_invert(ipaddress_object *self) -{ - ipaddress_object *result = NULL; - int i; - - ENTERING(ipaddress_object_number_invert); - - if ((result = (ipaddress_object *) self->ob_type->tp_alloc(self->ob_type, 0)) == NULL) - goto error; - - result->type = self->type; - - for (i = 0; (unsigned) i < self->type->length; i++) - result->address[i] = ~self->address[i]; - - error: /* Fall through */ - return (PyObject *) result; -} - -static char ipaddress_object_copy__doc__[] = - "" - ; - -static PyObject * -ipaddress_object_copy(ipaddress_object *self, GCC_UNUSED PyObject *args) -{ - ipaddress_object *result = NULL; - - ENTERING(ipaddress_object_copy); - - if ((result = (ipaddress_object *) self->ob_type->tp_alloc(self->ob_type, 0)) == NULL) - goto error; - - memcpy(result->address, self->address, sizeof(result->address)); - result->type = self->type; - - error: - return (PyObject *) result; -} - -static struct PyMethodDef ipaddress_object_methods[] = { - Define_Method(__copy__, ipaddress_object_copy, METH_VARARGS), - Define_Method(__deepcopy__, ipaddress_object_copy, METH_VARARGS), - Define_Method(toBytes, ipaddress_object_to_bytes, METH_NOARGS), - Define_Class_Method(fromBytes, ipaddress_object_from_bytes, METH_VARARGS), - {NULL} -}; - -static PyGetSetDef ipaddress_object_getsetters[] = { - {"bits", (getter) ipaddress_object_get_bits}, - {"version", (getter) ipaddress_object_get_version}, - {NULL} -}; - -static PyNumberMethods ipaddress_NumberMethods = { - ipaddress_object_number_add, /* nb_add */ - ipaddress_object_number_subtract, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_divide */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - (inquiry) ipaddress_object_number_nonzero, /* nb_nonzero */ - (unaryfunc) ipaddress_object_number_invert, /* nb_invert */ - ipaddress_object_number_lshift, /* nb_lshift */ - ipaddress_object_number_rshift, /* nb_rshift */ - ipaddress_object_number_and, /* nb_and */ - ipaddress_object_number_xor, /* nb_xor */ - ipaddress_object_number_or, /* nb_or */ - 0, /* nb_coerce */ - ipaddress_object_number_int, /* nb_int */ - ipaddress_object_number_long, /* nb_long */ - 0, /* nb_float */ - 0, /* nb_oct */ - 0, /* nb_hex */ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ - 0, /* nb_inplace_divide */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - 0, /* nb_floor_divide */ - 0, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ - 0, /* nb_index */ -}; - -static PyTypeObject POW_IPAddress_Type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "rpki.POW.IPAddress", /* tp_name */ - sizeof(ipaddress_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - ipaddress_object_compare, /* tp_compare */ - (reprfunc) ipaddress_object_repr, /* tp_repr */ - &ipaddress_NumberMethods, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) ipaddress_object_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) ipaddress_object_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - ipaddress_object_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ipaddress_object_methods, /* tp_methods */ - 0, /* tp_members */ - ipaddress_object_getsetters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - ipaddress_object_new, /* tp_new */ -}; - - - -/* - * X509 object. - */ - -static x509_object * -x509_object_new_helper(PyTypeObject *type, X509 *x) -{ - x509_object *self; - - if (type == NULL) - type = &POW_X509_Type; - - if ((self = (x509_object *) type->tp_alloc(type, 0)) == NULL) - return NULL; - - self->x509 = x; - return self; -} - -static PyObject * -x509_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - x509_object *self = NULL; - X509 *x = NULL; - - ENTERING(x509_object_new); - - if ((x = X509_new()) == NULL) - lose_no_memory(); - - if ((self = x509_object_new_helper(type, x)) == NULL) - goto error; - - return (PyObject *) self; - - error: - X509_free(x); - return NULL; -} - -static void -x509_object_dealloc(x509_object *self) -{ - ENTERING(x509_object_dealloc); - X509_free(self->x509); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -x509_object_pem_read_helper(PyTypeObject *type, BIO *bio) -{ - x509_object *self = NULL; - - ENTERING(x509_object_pem_read_helper); - - if ((self = (x509_object *) x509_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!PEM_read_bio_X509(bio, &self->x509, NULL, NULL)) - lose_openssl_error("Couldn't load PEM encoded certificate"); - - return (PyObject *) self; - - error: - - Py_XDECREF(self); - return NULL; -} - -static PyObject * -x509_object_der_read_helper(PyTypeObject *type, BIO *bio) -{ - x509_object *self; - - ENTERING(x509_object_der_read_helper); - - if ((self = (x509_object *) x509_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!d2i_X509_bio(bio, &self->x509)) - lose_openssl_error("Couldn't load DER encoded certificate"); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static char x509_object_pem_read__doc__[] = - "Read a PEM-encoded X.509 object from a string.\n" - ; - -static PyObject * -x509_object_pem_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(x509_object_pem_read); - return read_from_string_helper(x509_object_pem_read_helper, type, args); -} - -static char x509_object_pem_read_file__doc__[] = - "Read a PEM-encoded X.509 object from a file.\n" - ; - -static PyObject * -x509_object_pem_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(x509_object_pem_read_file); - return read_from_file_helper(x509_object_pem_read_helper, type, args); -} - -static char x509_object_der_read__doc__[] = - "Read a DER-encoded X.509 object from a string.\n" - ; - -static PyObject * -x509_object_der_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(x509_object_der_read); - return read_from_string_helper(x509_object_der_read_helper, type, args); -} - -static char x509_object_der_read_file__doc__[] = - "Read a DER-encoded X.509 object from a file.\n" - ; - -static PyObject * -x509_object_der_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(x509_object_der_read_file); - return read_from_file_helper(x509_object_der_read_helper, type, args); -} - -static char x509_object_pem_write__doc__[] = - "Return the PEM encoding of this certificate, as a string.\n" - ; - -static PyObject * -x509_object_pem_write(x509_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(x509_object_pem_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!PEM_write_bio_X509(bio, self->x509)) - lose_openssl_error("Unable to write certificate"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char x509_object_der_write__doc__[] = - "Return the DER encoding of this certificate, as a string.\n" - ; - -static PyObject * -x509_object_der_write(x509_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(x509_object_der_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!i2d_X509_bio(bio, self->x509)) - lose_openssl_error("Unable to write certificate"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static X509_EXTENSIONS ** -x509_object_extension_helper(x509_object *self) -{ - if (self && self->x509 && self->x509->cert_info) - return &self->x509->cert_info->extensions; - PyErr_SetString(PyExc_ValueError, "Can't find X509_EXTENSIONS in X509 object"); - return NULL; -} - -static char x509_object_get_public_key__doc__[] = - "Return the public key from this certificate object,\n" - "as an Asymmetric object.\n" - ; - -static PyObject * -x509_object_get_public_key(x509_object *self) -{ - PyTypeObject *type = &POW_Asymmetric_Type; - asymmetric_object *asym = NULL; - - ENTERING(x509_object_get_public_key); - - if ((asym = (asymmetric_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - if ((asym->pkey = X509_get_pubkey(self->x509)) == NULL) - lose_openssl_error("Couldn't extract public key from certificate"); - - return (PyObject *) asym; - - error: - Py_XDECREF(asym); - return NULL; -} - -static char x509_object_set_public_key__doc__[] = - "Set the public key of this certificate object.\n" - "\n" - "The \"key\" parameter should be an instance of the Asymmetric class,\n" - "containing a public key.\n" - ; - -static PyObject * -x509_object_set_public_key(x509_object *self, PyObject *args) -{ - asymmetric_object *asym; - - ENTERING(x509_object_set_public_key); - - if (!PyArg_ParseTuple(args, "O!", &POW_Asymmetric_Type, &asym)) - goto error; - - if (!X509_set_pubkey(self->x509, asym->pkey)) - lose_openssl_error("Couldn't set certificate's public key"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char x509_object_sign__doc__[] = - "Sign a certificate with a private key.\n" - "\n" - "The \"key\" parameter should be an instance of the Asymmetric class,\n" - "containing a private key.\n" - "\n" - "The optional \"digest\" parameter indicates which digest to compute and\n" - "sign, and should be one of the following:\n" - "\n" - "* MD5_DIGEST\n" - "* SHA_DIGEST\n" - "* SHA1_DIGEST\n" - "* SHA256_DIGEST\n" - "* SHA384_DIGEST\n" - "* SHA512_DIGEST\n" - "\n" - "The default digest algorithm is SHA-256.\n" - ; - -static PyObject * -x509_object_sign(x509_object *self, PyObject *args) -{ - asymmetric_object *asym; - int digest_type = SHA256_DIGEST; - const EVP_MD *digest_method = NULL; - - ENTERING(x509_object_sign); - - if (!PyArg_ParseTuple(args, "O!|i", &POW_Asymmetric_Type, &asym, &digest_type)) - goto error; - - if ((digest_method = evp_digest_factory(digest_type)) == NULL) - lose("Unsupported digest algorithm"); - - if (!X509_sign(self->x509, asym->pkey, digest_method)) - lose_openssl_error("Couldn't sign certificate"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char x509_object_get_version__doc__[] = - "Return version number of this certificate.\n" - ; - -static PyObject * -x509_object_get_version(x509_object *self) -{ - ENTERING(x509_object_get_version); - return Py_BuildValue("l", X509_get_version(self->x509)); -} - -static char x509_object_set_version__doc__[] = - "Set version number of this certificate.\n" - "\n" - "The \"version\" parameter should be an integer.\n" - ; - -static PyObject * -x509_object_set_version(x509_object *self, PyObject *args) -{ - long version = 0; - - ENTERING(x509_object_set_version); - - if (!PyArg_ParseTuple(args, "l", &version)) - goto error; - - if (!X509_set_version(self->x509, version)) - lose("Couldn't set certificate version"); - - Py_RETURN_NONE; - - error: - - return NULL; -} - -static char x509_object_get_serial__doc__[] = - "Return the serial number of this certificate.\n" - ; - -static PyObject * -x509_object_get_serial(x509_object *self) -{ - ENTERING(x509_object_get_serial); - return Py_BuildValue("N", ASN1_INTEGER_to_PyLong(X509_get_serialNumber(self->x509))); -} - -static char x509_object_set_serial__doc__[] = - "Set the serial number of this certificate.\n" - "\n" - "The \"serial\" parameter should ba an integer.\n" - ; - -static PyObject * -x509_object_set_serial(x509_object *self, PyObject *args) -{ - ASN1_INTEGER *a_serial = NULL; - PyObject *p_serial = NULL; - int ok = 0; - - ENTERING(x509_object_set_serial); - - if (!PyArg_ParseTuple(args, "O", &p_serial) || - (a_serial = PyLong_to_ASN1_INTEGER(p_serial)) == NULL) - goto error; - - if (!X509_set_serialNumber(self->x509, a_serial)) - lose_no_memory(); - - ok = 1; - - error: - ASN1_INTEGER_free(a_serial); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char x509_object_get_issuer__doc__[] = - "Return this certificate's issuer name, represented as a tuple.\n" - "\n" - "Each element of this tuple is another tuple representing one\n" - "\"Relative Distinguished Name\" (RDN), each element of which in turn\n" - "is yet another tuple representing one AttributeTypeAndValue pair.\n" - "\n" - "In practice, RDNs containing multiple attributes are rare, thus the RDN\n" - "tuples will usually be exactly one element long, but using the\n" - "tuple-of-tuples-of-tuples format lets us represent the general case.\n" - "\n" - "The AttributeTypeANdValue pairs are two-element tuples, the first\n" - "element of which is a string representing an Object Identifier (OID),\n" - "the second of which contains the attribute value.\n" - "\n" - "This method takes an optional \"format\" parameter which controls\n" - "the format in which OIDs are returned. Allowed values are:\n" - "\n" - " * SHORTNAME_FORMAT (the OpenSSL \"short name\" for this OID)\n" - " * LONGNAME_FORMAT (the OpenSSL \"long name\" for this OID)\n" - " * OIDNAME_FORMAT (the OID in dotted decimal numeric format)\n" - "\n" - "The default is OIDNAME_FORMAT.\n" - "\n" - "See RFC 5280 section 4.1.2.4 for details of the ASN.1 structure.\n" - ; - -static PyObject * -x509_object_get_issuer(x509_object *self, PyObject *args) -{ - PyObject *result = NULL; - int format = OIDNAME_FORMAT; - - ENTERING(x509_object_get_issuer); - - if (!PyArg_ParseTuple(args, "|i", &format)) - goto error; - - result = x509_object_helper_get_name(X509_get_issuer_name(self->x509), - format); - - error: /* Fall through */ - return result; -} - -static char x509_object_get_subject__doc__[] = - "Return this certificate's subject name, as a tuple.\n" - "\n" - "See the documentation for the \"getIssuer\" method for details on the\n" - "structure of the return value and use of the optional \"format\"\n" - "parameter.\n" - ; - -static PyObject * -x509_object_get_subject(x509_object *self, PyObject *args) -{ - PyObject *result = NULL; - int format = OIDNAME_FORMAT; - - ENTERING(x509_object_get_subject); - - if (!PyArg_ParseTuple(args, "|i", &format)) - goto error; - - result = x509_object_helper_get_name(X509_get_subject_name(self->x509), - format); - - error: /* Fall through */ - return result; -} - -static char x509_object_set_subject__doc__[] = - "Set this certificate's subject name.\n" - "\n" - "The \"name\" parameter should be in the same format as the return\n" - "value from the \"getIssuer\" method.\n" - ; - -static PyObject * -x509_object_set_subject(x509_object *self, PyObject *args) -{ - PyObject *name_sequence = NULL; - X509_NAME *name = NULL; - - ENTERING(x509_object_set_subject); - - if (!PyArg_ParseTuple(args, "O", &name_sequence)) - goto error; - - if (!PySequence_Check(name_sequence)) - lose_type_error("Inapropriate type"); - - if ((name = x509_object_helper_set_name(name_sequence)) == NULL) - goto error; - - if (!X509_set_subject_name(self->x509, name)) - lose("Unable to set subject name"); - - X509_NAME_free(name); - - Py_RETURN_NONE; - - error: - X509_NAME_free(name); - return NULL; -} - -static char x509_object_set_issuer__doc__[] = - "Set this certificate's issuer name.\n" - "\n" - "The \"name\" parameter should be in the same format as the return\n" - "value from the \"getIssuer\" method.\n" - ; - -static PyObject * -x509_object_set_issuer(x509_object *self, PyObject *args) -{ - PyObject *name_sequence = NULL; - X509_NAME *name = NULL; - - ENTERING(x509_object_set_issuer); - - if (!PyArg_ParseTuple(args, "O", &name_sequence)) - goto error; - - if (!PySequence_Check(name_sequence)) - lose_type_error("Inapropriate type"); - - if ((name = x509_object_helper_set_name(name_sequence)) == NULL) - goto error; - - if (!X509_set_issuer_name(self->x509, name)) - lose("Unable to set issuer name"); - - X509_NAME_free(name); - - Py_RETURN_NONE; - - error: - X509_NAME_free(name); - return NULL; -} - -static char x509_object_get_not_before__doc__[] = - "Return this certificate's \"notBefore\" value as a datetime.\n" - ; - -static PyObject * -x509_object_get_not_before (x509_object *self) -{ - ENTERING(x509_object_get_not_before); - return ASN1_TIME_to_Python(X509_get_notBefore(self->x509)); -} - -static char x509_object_get_not_after__doc__[] = - "Return this certificate's \"notAfter\" value as a datetime.\n" - ; - -static PyObject * -x509_object_get_not_after (x509_object *self) -{ - ENTERING(x509_object_get_not_after); - return ASN1_TIME_to_Python(X509_get_notAfter(self->x509)); -} - -static char x509_object_set_not_after__doc__[] = - "Set this certificate's \"notAfter\" value.\n" - "\n" - "The \"time\" parameter should be a datetime object.\n" - ; - -static PyObject * -x509_object_set_not_after (x509_object *self, PyObject *args) -{ - PyObject *o = NULL; - ASN1_TIME *t = NULL; - - ENTERING(x509_object_set_not_after); - - if (!PyArg_ParseTuple(args, "O", &o)) - goto error; - - if ((t = Python_to_ASN1_TIME(o, 1)) == NULL) - lose("Couldn't convert notAfter string"); - - if (!X509_set_notAfter(self->x509, t)) - lose("Couldn't set notAfter"); - - ASN1_TIME_free(t); - Py_RETURN_NONE; - - error: - ASN1_TIME_free(t); - return NULL; -} - -static char x509_object_set_not_before__doc__[] = - "Set this certificate's \"notBefore\" value.\n" - "\n" - "The \"time\" parameter should be a datetime object.\n" - ; - -static PyObject * -x509_object_set_not_before (x509_object *self, PyObject *args) -{ - PyObject *o = NULL; - ASN1_TIME *t = NULL; - - ENTERING(x509_object_set_not_before); - - if (!PyArg_ParseTuple(args, "O", &o)) - goto error; - - if ((t = Python_to_ASN1_TIME(o, 1)) == NULL) - lose("Couldn't convert notBefore string"); - - if (!X509_set_notBefore(self->x509, t)) - lose("Couldn't set notBefore"); - - ASN1_TIME_free(t); - Py_RETURN_NONE; - - error: - ASN1_TIME_free(t); - return NULL; -} - -static char x509_object_clear_extensions__doc__[] = - "Clear all extensions attached to this certificate.\n" - ; - -static PyObject * -x509_object_clear_extensions(x509_object *self) -{ - X509_EXTENSION *ext; - - ENTERING(x509_object_clear_extensions); - - while ((ext = X509_delete_ext(self->x509, 0)) != NULL) - X509_EXTENSION_free(ext); - - Py_RETURN_NONE; -} - -static char x509_object_get_ski__doc__[] = - "Return the Subject Key Identifier (SKI) value for this\n" - "certificate, or None if the certificate has no SKI extension.\n" - ; - -static PyObject * -x509_object_get_ski(x509_object *self) -{ - return extension_get_ski(x509_object_extension_helper(self)); -} - -static char x509_object_set_ski__doc__[] = - "Set the Subject Key Identifier (SKI) value for this certificate.\n" - ; - -static PyObject * -x509_object_set_ski(x509_object *self, PyObject *args) -{ - return extension_set_ski(x509_object_extension_helper(self), args); -} - -static char x509_object_get_aki__doc__[] = - "Return the Authority Key Identifier (AKI) keyid value for this\n" - "certificate, or None if the certificate has no AKI extension or has an\n" - "AKI extension with no keyIdentifier value.\n" - ; - -static PyObject * -x509_object_get_aki(x509_object *self) -{ - return extension_get_aki(x509_object_extension_helper(self)); -} - -static char x509_object_set_aki__doc__[] = - "Set the Authority Key Identifier (AKI) value for this certificate.\n" - "\n" - "We only support the keyIdentifier method, as that's the only form\n" - "which is legal for RPKI certificates.\n" - ; - -static PyObject * -x509_object_set_aki(x509_object *self, PyObject *args) -{ - return extension_set_aki(x509_object_extension_helper(self), args); -} - -static char x509_object_get_key_usage__doc__[] = - "Return a FrozenSet of strings representing the KeyUsage\n" - "settings for this certificate, or None if the certificate has no\n" - "KeyUsage extension. The bits have the same names as in RFC 5280.\n" - ; - -static PyObject * -x509_object_get_key_usage(x509_object *self) -{ - return extension_get_key_usage(x509_object_extension_helper(self)); -} - -static char x509_object_set_key_usage__doc__[] = - "Set the KeyUsage extension for this certificate.\n" - "\n" - "Argument \"iterable\" should be an iterable object which returns zero or more\n" - "strings naming bits to be enabled. The bits have the same names as in RFC 5280.\n" - "\n" - "Optional argument \"critical\" is a boolean indicating whether the extension\n" - "should be marked as critical or not. RFC 5280 4.2.1.3 says this extension SHOULD\n" - "be marked as critical when used, so the default is True.\n" - ; - -static PyObject * -x509_object_set_key_usage(x509_object *self, PyObject *args) -{ - return extension_set_key_usage(x509_object_extension_helper(self), args); -} - -static char x509_object_get_eku__doc__[] = - "Return a FrozenSet of object identifiers representing the\n" - "ExtendedKeyUsage settings for this certificate, or None if\n" - "the certificate has no ExtendedKeyUsage extension.\n" - ; - -static PyObject * -x509_object_get_eku(x509_object *self) -{ - return extension_get_eku(x509_object_extension_helper(self)); -} - -static char x509_object_set_eku__doc__[] = - "Set the ExtendedKeyUsage extension for this certificate.\n" - "\n" - "Argument \"iterable\" should be an iterable object which returns one or more\n" - "object identifiers.\n" - "\n" - "Optional argument \"critical\" is a boolean indicating whether the extension\n" - "should be marked as critical or not. RFC 6487 4.8.5 says this extension\n" - "MUST NOT be marked as non-critical when used, so the default is False.\n" - ; - -static PyObject * -x509_object_set_eku(x509_object *self, PyObject *args) -{ - return extension_set_eku(x509_object_extension_helper(self), args); -} - -static char x509_object_get_rfc3779__doc__[] = - "Return this certificate's RFC 3779 resources.\n" - "\n" - "Return value is a three-element tuple: the first element is the ASN\n" - "resources, the second is the IPv4 resources, the third is the IPv6\n" - "resources. Each of these elements in turn is either the string\n" - "\"inherit\" or a tuple representing a set of ranges of ASNs or IP\n" - "addresses.\n" - "\n" - "Each range is a two-element tuple, respectively representing the low\n" - "and high ends of the range, inclusive. ASN ranges are represented by\n" - "pairs of integers, IP address ranges are represented by pairs of\n" - "IPAddress objects.\n" - ; - -static PyObject * -x509_object_get_rfc3779(x509_object *self) -{ - PyObject *result = NULL; - PyObject *asn_result = NULL; - PyObject *ipv4_result = NULL; - PyObject *ipv6_result = NULL; - PyObject *range = NULL; - PyObject *range_b = NULL; - PyObject *range_e = NULL; - ASIdentifiers *asid = NULL; - IPAddrBlocks *addr = NULL; - int i, j; - - ENTERING(x509_object_get_rfc3779); - - if ((asid = X509_get_ext_d2i(self->x509, NID_sbgp_autonomousSysNum, NULL, NULL)) != NULL && - asid->asnum != NULL) { - switch (asid->asnum->type) { - - case ASIdentifierChoice_inherit: - if ((asn_result = PyString_FromString("inherit")) == NULL) - goto error; - break; - - case ASIdentifierChoice_asIdsOrRanges: - - if ((asn_result = PyTuple_New(sk_ASIdOrRange_num(asid->asnum->u.asIdsOrRanges))) == NULL) - goto error; - - for (i = 0; i < sk_ASIdOrRange_num(asid->asnum->u.asIdsOrRanges); i++) { - ASIdOrRange *aor = sk_ASIdOrRange_value(asid->asnum->u.asIdsOrRanges, i); - ASN1_INTEGER *b = NULL; - ASN1_INTEGER *e = NULL; - - switch (aor->type) { - - case ASIdOrRange_id: - b = e = aor->u.id; - break; - - case ASIdOrRange_range: - b = aor->u.range->min; - e = aor->u.range->max; - break; - - default: - lose_type_error("Unexpected asIdsOrRanges type"); - } - - if (ASN1_STRING_type(b) == V_ASN1_NEG_INTEGER || - ASN1_STRING_type(e) == V_ASN1_NEG_INTEGER) - lose_type_error("I don't believe in negative ASNs"); - - if ((range_b = ASN1_INTEGER_to_PyLong(b)) == NULL || - (range_e = ASN1_INTEGER_to_PyLong(e)) == NULL || - (range = Py_BuildValue("(NN)", range_b, range_e)) == NULL) - goto error; - - PyTuple_SET_ITEM(asn_result, i, range); - range = range_b = range_e = NULL; - } - - break; - - default: - lose_type_error("Unexpected ASIdentifierChoice type"); - } - } - - if ((addr = X509_get_ext_d2i(self->x509, NID_sbgp_ipAddrBlock, NULL, NULL)) != NULL) { - for (i = 0; i < sk_IPAddressFamily_num(addr); i++) { - IPAddressFamily *f = sk_IPAddressFamily_value(addr, i); - const struct ipaddress_version *ip_type = NULL; - const unsigned int afi = v3_addr_get_afi(f); - PyObject **result_obj = NULL; - int addr_len = 0; - - switch (afi) { - case IANA_AFI_IPV4: result_obj = &ipv4_result; ip_type = &ipaddress_version_4; break; - case IANA_AFI_IPV6: result_obj = &ipv6_result; ip_type = &ipaddress_version_6; break; - default: lose_type_error("Unknown AFI"); - } - - if (*result_obj != NULL) - lose_type_error("Duplicate IPAddressFamily"); - - if (f->addressFamily->length > 2) - lose_type_error("Unsupported SAFI"); - - switch (f->ipAddressChoice->type) { - - case IPAddressChoice_inherit: - if ((*result_obj = PyString_FromString("inherit")) == NULL) - goto error; - continue; - - case IPAddressChoice_addressesOrRanges: - break; - - default: - lose_type_error("Unexpected IPAddressChoice type"); - } - - if ((*result_obj = PyTuple_New(sk_IPAddressOrRange_num(f->ipAddressChoice->u.addressesOrRanges))) == NULL) - goto error; - - for (j = 0; j < sk_IPAddressOrRange_num(f->ipAddressChoice->u.addressesOrRanges); j++) { - IPAddressOrRange *aor = sk_IPAddressOrRange_value(f->ipAddressChoice->u.addressesOrRanges, j); - ipaddress_object *addr_b = NULL; - ipaddress_object *addr_e = NULL; - - if ((range_b = POW_IPAddress_Type.tp_alloc(&POW_IPAddress_Type, 0)) == NULL || - (range_e = POW_IPAddress_Type.tp_alloc(&POW_IPAddress_Type, 0)) == NULL) - goto error; - - addr_b = (ipaddress_object *) range_b; - addr_e = (ipaddress_object *) range_e; - - if ((addr_len = v3_addr_get_range(aor, afi, addr_b->address, addr_e->address, - sizeof(addr_b->address))) == 0) - lose_type_error("Couldn't unpack IP addresses from BIT STRINGs"); - - addr_b->type = addr_e->type = ip_type; - - if ((range = Py_BuildValue("(NN)", range_b, range_e)) == NULL) - goto error; - - PyTuple_SET_ITEM(*result_obj, j, range); - range = range_b = range_e = NULL; - } - } - } - - result = Py_BuildValue("(OOO)", - (asn_result == NULL ? Py_None : asn_result), - (ipv4_result == NULL ? Py_None : ipv4_result), - (ipv6_result == NULL ? Py_None : ipv6_result)); - - error: /* Fall through */ - ASIdentifiers_free(asid); - sk_IPAddressFamily_pop_free(addr, IPAddressFamily_free); - Py_XDECREF(range_b); - Py_XDECREF(range_e); - Py_XDECREF(range); - Py_XDECREF(asn_result); - Py_XDECREF(ipv4_result); - Py_XDECREF(ipv6_result); - - return result; -} - -static char x509_object_set_rfc3779__doc__[] = - "Set this certificate's RFC 3779 resources.\n" - "\n" - "This method takes three arguments: \"asn\", \"ipv4\", and \"ipv6\".\n" - "\n" - "Each of these arguments can be:\n" - "\n" - "* None, to omit this kind of resource;\n" - "\n" - "* The string \"inherit\", to specify RFC 3779 resource inheritance; or\n" - "\n" - "* An iterable object which returns range pairs of the appropriate type.\n" - "\n" - "Range pairs are as returned by the .getRFC3779() method.\n" - ; - -static PyObject * -x509_object_set_rfc3779(x509_object *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"asn", "ipv4", "ipv6", NULL}; - PyObject *asn_arg = Py_None; - PyObject *ipv4_arg = Py_None; - PyObject *ipv6_arg = Py_None; - PyObject *iterator = NULL; - PyObject *item = NULL; - PyObject *fast = NULL; - ASIdentifiers *asid = NULL; - IPAddrBlocks *addr = NULL; - ASN1_INTEGER *asid_b = NULL; - ASN1_INTEGER *asid_e = NULL; - ipaddress_object *addr_b = NULL; - ipaddress_object *addr_e = NULL; - int empty = 0; - - ENTERING(x509_object_set_rfc3779); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", kwlist, &asn_arg, &ipv4_arg, &ipv6_arg)) - goto error; - - if (asn_arg != Py_None) { - - empty = 1; - - if ((asid = ASIdentifiers_new()) == NULL) - lose_no_memory(); - - if (PyString_Check(asn_arg)) { - - if (strcmp(PyString_AsString(asn_arg), "inherit")) - lose_type_error("ASID must be an iterable that returns range pairs, or the string \"inherit\""); - - if (!v3_asid_add_inherit(asid, V3_ASID_ASNUM)) - lose_no_memory(); - - empty = 0; - - } else { - - if ((iterator = PyObject_GetIter(asn_arg)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if ((fast = PySequence_Fast(item, "ASN range must be a sequence")) == NULL) - goto error; - - if (PySequence_Fast_GET_SIZE(fast) != 2) - lose_type_error("ASN range must be two-element sequence"); - - if ((asid_b = PyLong_to_ASN1_INTEGER(PySequence_Fast_GET_ITEM(fast, 0))) == NULL) - goto error; - - switch (PyObject_RichCompareBool(PySequence_Fast_GET_ITEM(fast, 0), - PySequence_Fast_GET_ITEM(fast, 1), Py_EQ)) { - case 0: - if ((asid_e = PyLong_to_ASN1_INTEGER(PySequence_Fast_GET_ITEM(fast, 1))) == NULL) - goto error; - break; - case 1: - break; - default: - goto error; - } - - if (!v3_asid_add_id_or_range(asid, V3_ASID_ASNUM, asid_b, asid_e)) - lose_openssl_error("Couldn't add range to ASID"); - - asid_b = asid_e = NULL; - Py_XDECREF(item); - Py_XDECREF(fast); - item = fast = NULL; - empty = 0; - } - - Py_XDECREF(iterator); - iterator = NULL; - } - - if (!empty && (!v3_asid_canonize(asid) || - !X509_add1_ext_i2d(self->x509, NID_sbgp_autonomousSysNum, - asid, 1, X509V3_ADD_REPLACE))) - lose_openssl_error("Couldn't add ASID extension to certificate"); - } - - if (ipv4_arg != Py_None || ipv6_arg != Py_None) { - int v; - - empty = 1; - - if ((addr = sk_IPAddressFamily_new_null()) == NULL) - lose_no_memory(); - - /* - * Cheap trick to let us inline all of this instead of being - * forced to use a separate function. Refactor, some day. - */ - - for (v = 0; v < (int) (sizeof(ipaddress_versions)/sizeof(*ipaddress_versions)); v++) { - const struct ipaddress_version *ip_type = ipaddress_versions[v]; - PyObject **argp; - - switch (ip_type->version) { - case 4: argp = &ipv4_arg; break; - case 6: argp = &ipv6_arg; break; - default: continue; /* Never happens */ - } - - if (PyString_Check(*argp)) { - - if (strcmp(PyString_AsString(*argp), "inherit")) - lose_type_error("Argument must be an iterable that returns range pairs, or the string \"inherit\""); - - if (!v3_addr_add_inherit(addr, ip_type->afi, NULL)) - lose_no_memory(); - - empty = 0; - - } else { - - if ((iterator = PyObject_GetIter(*argp)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if ((fast = PySequence_Fast(item, "Address range must be a sequence")) == NULL) - goto error; - - if (PySequence_Fast_GET_SIZE(fast) != 2 || - !POW_IPAddress_Check(PySequence_Fast_GET_ITEM(fast, 0)) || - !POW_IPAddress_Check(PySequence_Fast_GET_ITEM(fast, 1))) - lose_type_error("Address range must be two-element sequence of IPAddress objects"); - - addr_b = (ipaddress_object *) PySequence_Fast_GET_ITEM(fast, 0); - addr_e = (ipaddress_object *) PySequence_Fast_GET_ITEM(fast, 1); - - if (addr_b->type != ip_type || - addr_e->type != ip_type || - memcmp(addr_b->address, addr_e->address, ip_type->length) > 0) - lose("Address range must be two-element sequence of IPAddress objects in ascending order"); - - if (!v3_addr_add_range(addr, ip_type->afi, NULL, addr_b->address, addr_e->address)) - lose_openssl_error("Couldn't add range to IPAddrBlock"); - - Py_XDECREF(item); - Py_XDECREF(fast); - item = fast = NULL; - addr_b = addr_e = NULL; - empty = 0; - } - - Py_XDECREF(iterator); - iterator = NULL; - } - } - - if (!empty && (!v3_addr_canonize(addr) || - !X509_add1_ext_i2d(self->x509, NID_sbgp_ipAddrBlock, - addr, 1, X509V3_ADD_REPLACE))) - lose_openssl_error("Couldn't add IPAddrBlock extension to certificate"); - } - - Py_RETURN_NONE; - - error: - ASN1_INTEGER_free(asid_b); - ASN1_INTEGER_free(asid_e); - ASIdentifiers_free(asid); - sk_IPAddressFamily_pop_free(addr, IPAddressFamily_free); - Py_XDECREF(iterator); - Py_XDECREF(item); - Py_XDECREF(fast); - return NULL; -} - -static char x509_object_get_basic_constraints__doc__[] = - "Return BasicConstraints for this certificate.\n" - "\n" - "If this certificate has no BasicConstraints extension, this method\n" - "returns None.\n" - "\n" - "Otherwise, this method returns a two-element tuple. The first element\n" - "of the tuple is a boolean representing the extension's cA value; the\n" - "second element of the tuple is either an integer representing the\n" - "pathLenConstraint value or None if there is no pathLenConstraint.\n" - ; - -static PyObject * -x509_object_get_basic_constraints(x509_object *self) -{ - return extension_get_basic_constraints(x509_object_extension_helper(self)); -} - -static char x509_object_set_basic_constraints__doc__[] = - "Set BasicConstraints for this certificate.\n" - "\n" - "First argument \"ca\" is a boolean indicating whether the certificate\n" - "is a CA certificate or not.\n" - "\n" - "Optional second argument \"pathLenConstraint\" is a non-negative integer\n" - "specifying the pathLenConstraint value for this certificate; this value\n" - "may only be set for CA certificates." - "\n" - "Optional third argument \"critical\" specifies whether the extension\n" - "should be marked as critical. RFC 5280 4.2.1.9 requires that CA\n" - "certificates mark this extension as critical, so the default is True.\n" - ; - -static PyObject * -x509_object_set_basic_constraints(x509_object *self, PyObject *args) -{ - return extension_set_basic_constraints(x509_object_extension_helper(self), args); -} - -static char x509_object_get_sia__doc__[] = - "Get SIA values for this certificate.\n" - "\n" - "If the certificate has no SIA extension, this method returns None.\n" - "\n" - "Otherwise, it returns a tuple containing three values:\n" - "caRepository URIs, rpkiManifest URIs, and signedObject URIs.\n" - "Each of these values is a tuple of strings, representing an ordered\n" - "sequence of URIs. Any or all of these sequences may be empty.\n" - "\n" - "Any other accessMethods are ignored, as are any non-URI\n" - "accessLocations.\n" - ; - -static PyObject * -x509_object_get_sia(x509_object *self) -{ - return extension_get_sia(x509_object_extension_helper(self)); -} - -static char x509_object_set_sia__doc__[] = - "Set SIA values for this certificate. Takes three arguments:\n" - "\"caRepository\", \"rpkiManifest\", and \"signedObject\".\n" - "Each of these should be an iterable which returns URIs.\n" - "\n" - "None is acceptable as an alternate way of specifying an empty\n" - "collection of URIs for a particular argument.\n" - ; - -static PyObject * -x509_object_set_sia(x509_object *self, PyObject *args, PyObject *kwds) -{ - return extension_set_sia(x509_object_extension_helper(self), args, kwds); -} - -static char x509_object_get_aia__doc__[] = - "Get this certificate's AIA values.\n" - "\n" - "If the certificate has no AIA extension, this method returns None.\n" - "\n" - "Otherwise, this returns a sequence of caIssuers URIs.\n" - "\n" - "Any other accessMethods are ignored, as are any non-URI\n" - "accessLocations.\n" - ; - -static PyObject * -x509_object_get_aia(x509_object *self) -{ - AUTHORITY_INFO_ACCESS *ext = NULL; - PyObject *result = NULL; - const char *uri; - PyObject *obj; - int i, n = 0; - - ENTERING(x509_object_get_aia); - - if ((ext = X509_get_ext_d2i(self->x509, NID_info_access, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ext); i++) { - ACCESS_DESCRIPTION *a = sk_ACCESS_DESCRIPTION_value(ext, i); - if (a->location->type == GEN_URI && - OBJ_obj2nid(a->method) == NID_ad_ca_issuers) - n++; - } - - if (((result = PyTuple_New(n)) == NULL)) - goto error; - - n = 0; - - for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ext); i++) { - ACCESS_DESCRIPTION *a = sk_ACCESS_DESCRIPTION_value(ext, i); - if (a->location->type == GEN_URI && OBJ_obj2nid(a->method) == NID_ad_ca_issuers) { - uri = (char *) ASN1_STRING_data(a->location->d.uniformResourceIdentifier); - if ((obj = PyString_FromString(uri)) == NULL) - goto error; - PyTuple_SET_ITEM(result, n++, obj); - } - } - - AUTHORITY_INFO_ACCESS_free(ext); - return result; - - error: - AUTHORITY_INFO_ACCESS_free(ext); - Py_XDECREF(result); - return NULL; -} - -static char x509_object_set_aia__doc__[] = - "Set AIA URIs for this certificate.\n" - "\n" - "Argument is a iterable which returns caIssuers URIs.\n" - ; - -static PyObject * -x509_object_set_aia(x509_object *self, PyObject *args) -{ - AUTHORITY_INFO_ACCESS *ext = NULL; - PyObject *caIssuers = NULL; - PyObject *iterator = NULL; - ASN1_OBJECT *oid = NULL; - PyObject *item = NULL; - ACCESS_DESCRIPTION *a = NULL; - int ok = 0; - Py_ssize_t urilen; - char *uri; - - ENTERING(x509_object_set_aia); - - if (!PyArg_ParseTuple(args, "O", &caIssuers)) - goto error; - - if ((ext = AUTHORITY_INFO_ACCESS_new()) == NULL) - lose_no_memory(); - - if ((oid = OBJ_nid2obj(NID_ad_ca_issuers)) == NULL) - lose_openssl_error("Couldn't find AIA accessMethod OID"); - - if ((iterator = PyObject_GetIter(caIssuers)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if (PyString_AsStringAndSize(item, &uri, &urilen) < 0) - goto error; - - if ((a = ACCESS_DESCRIPTION_new()) == NULL || - (a->method = OBJ_dup(oid)) == NULL || - (a->location->d.uniformResourceIdentifier = ASN1_IA5STRING_new()) == NULL || - !ASN1_OCTET_STRING_set(a->location->d.uniformResourceIdentifier, (unsigned char *) uri, urilen)) - lose_no_memory(); - - a->location->type = GEN_URI; - - if (!sk_ACCESS_DESCRIPTION_push(ext, a)) - lose_no_memory(); - - a = NULL; - Py_XDECREF(item); - item = NULL; - } - - Py_XDECREF(iterator); - iterator = NULL; - - if (!X509_add1_ext_i2d(self->x509, NID_info_access, ext, 0, X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add AIA extension to certificate"); - - ok = 1; - - error: - AUTHORITY_INFO_ACCESS_free(ext); - ACCESS_DESCRIPTION_free(a); - Py_XDECREF(item); - Py_XDECREF(iterator); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char x509_object_get_crldp__doc__[] = - "Get CRL Distribution Point (CRLDP) values for this certificate.\n" - "\n" - "If the certificate has no CRLDP extension, this method returns None.\n" - "\n" - "Otherwise, it returns a sequence of URIs representing distributionPoint\n" - "fullName values found in the first Distribution Point. Other CRLDP\n" - "fields are ignored, as are subsequent Distribution Points and any non-URI\n" - "fullName values.\n" - ; - -static PyObject * -x509_object_get_crldp(x509_object *self) -{ - CRL_DIST_POINTS *ext = NULL; - DIST_POINT *dp = NULL; - PyObject *result = NULL; - const char *uri; - PyObject *obj; - int i, n = 0; - - ENTERING(x509_object_get_crldp); - - if ((ext = X509_get_ext_d2i(self->x509, NID_crl_distribution_points, NULL, NULL)) == NULL || - (dp = sk_DIST_POINT_value(ext, 0)) == NULL || - dp->distpoint == NULL || - dp->distpoint->type != 0) - Py_RETURN_NONE; - - for (i = 0; i < sk_GENERAL_NAME_num(dp->distpoint->name.fullname); i++) { - GENERAL_NAME *gn = sk_GENERAL_NAME_value(dp->distpoint->name.fullname, i); - if (gn->type == GEN_URI) - n++; - } - - if (((result = PyTuple_New(n)) == NULL)) - goto error; - - n = 0; - - for (i = 0; i < sk_GENERAL_NAME_num(dp->distpoint->name.fullname); i++) { - GENERAL_NAME *gn = sk_GENERAL_NAME_value(dp->distpoint->name.fullname, i); - if (gn->type == GEN_URI) { - uri = (char *) ASN1_STRING_data(gn->d.uniformResourceIdentifier); - if ((obj = PyString_FromString(uri)) == NULL) - goto error; - PyTuple_SET_ITEM(result, n++, obj); - } - } - - sk_DIST_POINT_pop_free(ext, DIST_POINT_free); - return result; - - error: - sk_DIST_POINT_pop_free(ext, DIST_POINT_free); - Py_XDECREF(result); - return NULL; -} - -static char x509_object_set_crldp__doc__[] = - "Set CRLDP values for this certificate.\n" - "\n" - "Argument is a iterable which returns distributionPoint fullName URIs.\n" - ; - -static PyObject * -x509_object_set_crldp(x509_object *self, PyObject *args) -{ - CRL_DIST_POINTS *ext = NULL; - PyObject *fullNames = NULL; - PyObject *iterator = NULL; - PyObject *item = NULL; - DIST_POINT *dp = NULL; - GENERAL_NAME *gn = NULL; - Py_ssize_t urilen; - char *uri; - int ok = 0; - - ENTERING(x509_object_set_crldp); - - if (!PyArg_ParseTuple(args, "O", &fullNames)) - goto error; - - if ((ext = sk_DIST_POINT_new_null()) == NULL || - (dp = DIST_POINT_new()) == NULL || - (dp->distpoint = DIST_POINT_NAME_new()) == NULL || - (dp->distpoint->name.fullname = sk_GENERAL_NAME_new_null()) == NULL) - lose_no_memory(); - - dp->distpoint->type = 0; - - if ((iterator = PyObject_GetIter(fullNames)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if (PyString_AsStringAndSize(item, &uri, &urilen) < 0) - goto error; - - if ((gn = GENERAL_NAME_new()) == NULL || - (gn->d.uniformResourceIdentifier = ASN1_IA5STRING_new()) == NULL || - !ASN1_OCTET_STRING_set(gn->d.uniformResourceIdentifier, (unsigned char *) uri, urilen)) - lose_no_memory(); - - gn->type = GEN_URI; - - if (!sk_GENERAL_NAME_push(dp->distpoint->name.fullname, gn)) - lose_no_memory(); - - gn = NULL; - Py_XDECREF(item); - item = NULL; - } - - Py_XDECREF(iterator); - iterator = NULL; - - if (!sk_DIST_POINT_push(ext, dp)) - lose_no_memory(); - - dp = NULL; - - if (!X509_add1_ext_i2d(self->x509, NID_crl_distribution_points, ext, 0, X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add CRLDP extension to certificate"); - - ok = 1; - - error: - sk_DIST_POINT_pop_free(ext, DIST_POINT_free); - DIST_POINT_free(dp); - GENERAL_NAME_free(gn); - Py_XDECREF(item); - Py_XDECREF(iterator); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char x509_object_get_certificate_policies__doc__[] = - "Get Certificate Policies values for this certificate.\n" - "\n" - "If this certificate has no Certificate Policies extension, this method\n" - "returns None.\n" - "\n" - "Otherwise, this method returns a sequence of Object Identifiers.\n" - "\n" - "Policy qualifiers, if any, are ignored.\n" - ; - -static PyObject * -x509_object_get_certificate_policies(x509_object *self) -{ - CERTIFICATEPOLICIES *ext = NULL; - PyObject *result = NULL; - PyObject *obj; - int i; - - ENTERING(x509_object_get_certificate_policies); - - if ((ext = X509_get_ext_d2i(self->x509, NID_certificate_policies, NULL, NULL)) == NULL) - Py_RETURN_NONE; - - if (((result = PyTuple_New(sk_POLICYINFO_num(ext))) == NULL)) - goto error; - - for (i = 0; i < sk_POLICYINFO_num(ext); i++) { - POLICYINFO *p = sk_POLICYINFO_value(ext, i); - - if ((obj = ASN1_OBJECT_to_PyString(p->policyid)) == NULL) - goto error; - - PyTuple_SET_ITEM(result, i, obj); - } - - sk_POLICYINFO_pop_free(ext, POLICYINFO_free); - return result; - - error: - sk_POLICYINFO_pop_free(ext, POLICYINFO_free); - Py_XDECREF(result); - return NULL; -} - -static char x509_object_set_certificate_policies__doc__[] = - "Set Certificate Policies for this certificate.\n" - "\n" - "Argument is a iterable which returns policy OIDs.\n" - "\n" - "Policy qualifier are not supported.\n" - "\n" - "The extension will be marked as critical, since there's not much point\n" - "in using this extension without making it critical.\n" - ; - -static PyObject * -x509_object_set_certificate_policies(x509_object *self, PyObject *args) -{ - CERTIFICATEPOLICIES *ext = NULL; - PyObject *policies = NULL; - PyObject *iterator = NULL; - POLICYINFO *pol = NULL; - PyObject *item = NULL; - const char *oid; - int ok = 0; - - ENTERING(x509_object_set_certificate_policies); - - if (!PyArg_ParseTuple(args, "O", &policies)) - goto error; - - if ((ext = sk_POLICYINFO_new_null()) == NULL) - lose_no_memory(); - - if ((iterator = PyObject_GetIter(policies)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if ((oid = PyString_AsString(item)) == NULL) - goto error; - - if ((pol = POLICYINFO_new()) == NULL) - lose_no_memory(); - - if ((pol->policyid = OBJ_txt2obj(oid, 1)) == NULL) - lose("Couldn't parse OID"); - - if (!sk_POLICYINFO_push(ext, pol)) - lose_no_memory(); - - pol = NULL; - Py_XDECREF(item); - item = NULL; - } - - Py_XDECREF(iterator); - iterator = NULL; - - if (!X509_add1_ext_i2d(self->x509, NID_certificate_policies, ext, 1, X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add CERTIFICATE_POLICIES extension to certificate"); - - ok = 1; - - error: - POLICYINFO_free(pol); - sk_POLICYINFO_pop_free(ext, POLICYINFO_free); - Py_XDECREF(item); - Py_XDECREF(iterator); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -/* - * May want EKU handlers eventually, skip for now. - */ - -static char x509_object_pprint__doc__[] = - "Return a pretty-printed rendition of this certificate.\n" - ; - -static PyObject * -x509_object_pprint(x509_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(x509_object_pprint); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!X509_print(bio, self->x509)) - lose_openssl_error("Unable to pretty-print certificate"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static struct PyMethodDef x509_object_methods[] = { - Define_Method(pemWrite, x509_object_pem_write, METH_NOARGS), - Define_Method(derWrite, x509_object_der_write, METH_NOARGS), - Define_Method(sign, x509_object_sign, METH_VARARGS), - Define_Method(getPublicKey, x509_object_get_public_key, METH_NOARGS), - Define_Method(setPublicKey, x509_object_set_public_key, METH_VARARGS), - Define_Method(getVersion, x509_object_get_version, METH_NOARGS), - Define_Method(setVersion, x509_object_set_version, METH_VARARGS), - Define_Method(getSerial, x509_object_get_serial, METH_NOARGS), - Define_Method(setSerial, x509_object_set_serial, METH_VARARGS), - Define_Method(getIssuer, x509_object_get_issuer, METH_VARARGS), - Define_Method(setIssuer, x509_object_set_issuer, METH_VARARGS), - Define_Method(getSubject, x509_object_get_subject, METH_VARARGS), - Define_Method(setSubject, x509_object_set_subject, METH_VARARGS), - Define_Method(getNotBefore, x509_object_get_not_before, METH_NOARGS), - Define_Method(getNotAfter, x509_object_get_not_after, METH_NOARGS), - Define_Method(setNotAfter, x509_object_set_not_after, METH_VARARGS), - Define_Method(setNotBefore, x509_object_set_not_before, METH_VARARGS), - Define_Method(clearExtensions, x509_object_clear_extensions, METH_NOARGS), - Define_Method(pprint, x509_object_pprint, METH_NOARGS), - Define_Method(getSKI, x509_object_get_ski, METH_NOARGS), - Define_Method(setSKI, x509_object_set_ski, METH_VARARGS), - Define_Method(getAKI, x509_object_get_aki, METH_NOARGS), - Define_Method(setAKI, x509_object_set_aki, METH_VARARGS), - Define_Method(getKeyUsage, x509_object_get_key_usage, METH_NOARGS), - Define_Method(setKeyUsage, x509_object_set_key_usage, METH_VARARGS), - Define_Method(getEKU, x509_object_get_eku, METH_NOARGS), - Define_Method(setEKU, x509_object_set_eku, METH_VARARGS), - Define_Method(getRFC3779, x509_object_get_rfc3779, METH_NOARGS), - Define_Method(setRFC3779, x509_object_set_rfc3779, METH_KEYWORDS), - Define_Method(getBasicConstraints, x509_object_get_basic_constraints, METH_NOARGS), - Define_Method(setBasicConstraints, x509_object_set_basic_constraints, METH_VARARGS), - Define_Method(getSIA, x509_object_get_sia, METH_NOARGS), - Define_Method(setSIA, x509_object_set_sia, METH_KEYWORDS), - Define_Method(getAIA, x509_object_get_aia, METH_NOARGS), - Define_Method(setAIA, x509_object_set_aia, METH_VARARGS), - Define_Method(getCRLDP, x509_object_get_crldp, METH_NOARGS), - Define_Method(setCRLDP, x509_object_set_crldp, METH_VARARGS), - Define_Method(getCertificatePolicies, x509_object_get_certificate_policies, METH_NOARGS), - Define_Method(setCertificatePolicies, x509_object_set_certificate_policies, METH_VARARGS), - Define_Class_Method(pemRead, x509_object_pem_read, METH_VARARGS), - Define_Class_Method(pemReadFile, x509_object_pem_read_file, METH_VARARGS), - Define_Class_Method(derRead, x509_object_der_read, METH_VARARGS), - Define_Class_Method(derReadFile, x509_object_der_read_file, METH_VARARGS), - {NULL} -}; - -static char POW_X509_Type__doc__[] = - "This class represents an X.509 certificate.\n" - "\n" - LAME_DISCLAIMER_IN_ALL_CLASS_DOCUMENTATION - ; - -static PyTypeObject POW_X509_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.X509", /* tp_name */ - sizeof(x509_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)x509_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_X509_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - x509_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - x509_object_new, /* tp_new */ -}; - - - -/* - * X509Store object. - */ - -static PyObject * -x509_store_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - x509_store_object *self = NULL; - - ENTERING(x509_store_object_new); - - if ((self = (x509_store_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - if ((self->store = X509_STORE_new()) == NULL) - lose_no_memory(); - - self->ctxclass = (PyObject *) &POW_X509StoreCTX_Type; - Py_XINCREF(self->ctxclass); - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static void -x509_store_object_dealloc(x509_store_object *self) -{ - ENTERING(x509_store_object_dealloc); - X509_STORE_free(self->store); - Py_XDECREF(self->ctxclass); - self->ob_type->tp_free((PyObject*) self); -} - -static char x509_store_object_add_trust__doc__[] = - "Add a trusted certificate to this certificate store object.\n" - "\n" - "The \"certificate\" parameter should be an instance of the X509 class.\n" - ; - -static PyObject * -x509_store_object_add_trust(x509_store_object *self, PyObject *args) -{ - x509_object *x509 = NULL; - - ENTERING(x509_store_object_add_trust); - - if (!PyArg_ParseTuple(args, "O!", &POW_X509_Type, &x509)) - goto error; - - X509_STORE_add_cert(self->store, x509->x509); - - Py_RETURN_NONE; - - error: - - return NULL; -} - -static char x509_store_object_add_crl__doc__[] = - "Add a CRL to this certificate store object.\n" - "\n" - "The \"crl\" parameter should be an instance of the CRL class.\n" - ; - -static PyObject * -x509_store_object_add_crl(x509_store_object *self, PyObject *args) -{ - crl_object *crl = NULL; - - ENTERING(x509_store_object_add_crl); - - if (!PyArg_ParseTuple(args, "O!", &POW_CRL_Type, &crl)) - goto error; - - X509_STORE_add_crl(self->store, crl->crl); - - Py_RETURN_NONE; - - error: - - return NULL; -} - -static char x509_store_object_set_flags__doc__[] = - "Set validation flags for this X509Store.\n" - "\n" - "Argument is an integer containing bit flags to set.\n" - ; - -static PyObject * -x509_store_object_set_flags (x509_store_object *self, PyObject *args) -{ - unsigned long flags; - - if (!PyArg_ParseTuple(args, "k", &flags)) - goto error; - - if (!X509_VERIFY_PARAM_set_flags(self->store->param, flags)) - lose_openssl_error("X509_VERIFY_PARAM_set_flags() failed"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char x509_store_object_clear_flags__doc__[] = - "Clear validation flags for this X509Store.\n" - "\n" - "Argument is an integer containing bit flags to clear.\n" - ; - -static PyObject * -x509_store_object_clear_flags (x509_store_object *self, PyObject *args) -{ - unsigned long flags; - - if (!PyArg_ParseTuple(args, "k", &flags)) - goto error; - - if (!X509_VERIFY_PARAM_clear_flags(self->store->param, flags)) - lose_openssl_error("X509_VERIFY_PARAM_clear_flags() failed"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char x509_store_object_set_context_class__doc__[] = - "Set validation context class factory for this X509Store.\n" - "\n" - "This must be a callable object which takes one argument, an X509Store,\n" - "and returns a subclass of X509StoreCTX. The callable can be a class\n" - "object but need not be, so long as calling it returns an instance of an\n" - "appropriate class. The default is X509StoreCTX.\n" - ; - -static PyObject * -x509_store_object_set_context_class (x509_store_object *self, PyObject *args) -{ - PyObject *ctxclass = (PyObject *) &POW_X509StoreCTX_Type; - - if (!PyArg_ParseTuple(args, "|O", &ctxclass)) - goto error; - - if (!PyCallable_Check(ctxclass)) - lose("Context class must be callable"); - - Py_XDECREF(self->ctxclass); - self->ctxclass = ctxclass; - Py_XINCREF(self->ctxclass); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char x509_store_object_verify__doc__[] = - "Verify an X509 certificate object using this certificate store.\n" - "\n" - "Optional second argument is an iterable that supplies untrusted certificates\n" - "to be considered when building a chain to the trust anchor.\n" - "\n" - "This method returns an instance of the store's verification context class.\n" - ; - -static PyObject * -x509_store_object_verify(x509_store_object *self, PyObject *args) -{ - x509_store_ctx_object *ctx = NULL; - STACK_OF(X509) *stack = NULL; - x509_object *x509 = NULL; - PyObject *chain = Py_None; - int ok; - - if (!PyArg_ParseTuple(args, "O!|O", &POW_X509_Type, &x509, &chain)) - goto error; - - if ((ctx = (x509_store_ctx_object *) PyObject_CallFunctionObjArgs(self->ctxclass, self, NULL)) == NULL) - goto error; - - if (!POW_X509StoreCTX_Check(ctx)) - lose_type_error("Returned context is not a X509StoreCTX"); - - if (ctx->ctx == NULL) - lose("Uninitialized X509StoreCTX"); - - if (chain != Py_None && (stack = x509_helper_iterable_to_stack(chain)) == NULL) - goto error; - - Py_XINCREF(x509); - Py_XINCREF(chain); - X509_STORE_CTX_set_cert(ctx->ctx, x509->x509); - X509_STORE_CTX_set_chain(ctx->ctx, stack); - - ok = X509_verify_cert(ctx->ctx); - - X509_STORE_CTX_set_chain(ctx->ctx, NULL); - X509_STORE_CTX_set_cert(ctx->ctx, NULL); - Py_XDECREF(chain); - Py_XDECREF(x509); - - sk_X509_free(stack); - - if (PyErr_Occurred()) - goto error; - - if (ok < 0) - lose_openssl_error("X509_verify_cert() raised an exception"); - - return (PyObject *) ctx; - - error: /* fall through */ - Py_XDECREF(ctx); - return NULL; -} - -static struct PyMethodDef x509_store_object_methods[] = { - Define_Method(addTrust, x509_store_object_add_trust, METH_VARARGS), - Define_Method(addCrl, x509_store_object_add_crl, METH_VARARGS), - Define_Method(setContextClass,x509_store_object_set_context_class, METH_VARARGS), - Define_Method(setFlags, x509_store_object_set_flags, METH_VARARGS), - Define_Method(clearFlags, x509_store_object_clear_flags, METH_VARARGS), - Define_Method(verify, x509_store_object_verify, METH_VARARGS), - {NULL} -}; - -static char POW_X509Store_Type__doc__[] = - "This class holds the OpenSSL certificate store objects used in CMS\n" - "and certificate verification.\n" - "\n" - LAME_DISCLAIMER_IN_ALL_CLASS_DOCUMENTATION - ; - -static PyTypeObject POW_X509Store_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.X509Store", /* tp_name */ - sizeof(x509_store_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)x509_store_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_X509Store_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - x509_store_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - x509_store_object_new, /* tp_new */ -}; - - - -/* - * X509StoreCTX object. - */ - -static int -x509_store_ctx_object_verify_cb(int ok, X509_STORE_CTX *ctx) -{ - static char method_name[] = "verify_callback"; - PyObject *self = X509_STORE_CTX_get_ex_data(ctx, x509_store_ctx_ex_data_idx); - PyObject *result = NULL; - - if (self == NULL || !PyObject_HasAttrString(self, method_name)) - return ok; - - if ((result = PyObject_CallMethod(self, method_name, "i", ok)) == NULL) - return -1; - - ok = PyObject_IsTrue(result); - Py_XDECREF(result); - return ok; -} - -static PyObject * -x509_store_ctx_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - x509_store_ctx_object *self = NULL; - - ENTERING(x509_store_ctx_object_new); - - if ((self = (x509_store_ctx_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - self->ctx = NULL; - self->store = NULL; - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static int -x509_store_ctx_object_init(x509_store_ctx_object *self, PyObject *args, GCC_UNUSED PyObject *kwds) -{ - x509_store_object *store = NULL; - - if (!PyArg_ParseTuple(args, "|O!", &POW_X509Store_Type, &store)) - goto error; - - if ((self->ctx = X509_STORE_CTX_new()) == NULL) - lose_no_memory(); - - if (!X509_STORE_CTX_init(self->ctx, store ? store->store : NULL, NULL, NULL)) - lose_openssl_error("Couldn't initialize X509_STORE_CTX"); - - if (!X509_STORE_CTX_set_ex_data(self->ctx, x509_store_ctx_ex_data_idx, self)) - lose_openssl_error("Couldn't set X509_STORE_CTX ex_data"); - - Py_XDECREF(self->store); - self->store = store; - Py_XINCREF(self->store); - - X509_VERIFY_PARAM_set_flags(self->ctx->param, X509_V_FLAG_X509_STRICT); - X509_STORE_CTX_set_verify_cb(self->ctx, x509_store_ctx_object_verify_cb); - return 0; - - error: - return -1; -} - -static void -x509_store_ctx_object_dealloc(x509_store_ctx_object *self) -{ - ENTERING(x509_store_ctx_object_dealloc); - X509_STORE_CTX_free(self->ctx); - Py_XDECREF(self->store); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -x509_store_ctx_object_get_store (x509_store_ctx_object *self, GCC_UNUSED void *closure) -{ - return Py_BuildValue("O", self->store == NULL ? Py_None : (PyObject *) self->store); -} - -static char x509_store_ctx_object_get_error__doc__[] = - "Extract verification error code from this X509StoreCTX.\n" - ; - -static PyObject* -x509_store_ctx_object_get_error (x509_store_ctx_object *self) -{ - return Py_BuildValue("i", X509_STORE_CTX_get_error(self->ctx)); -} - -static char x509_store_ctx_object_get_error_string__doc__[] = - "Extract verification error code from this X509StoreCTX.\n" - ; - -static PyObject* -x509_store_ctx_object_get_error_string (x509_store_ctx_object *self) -{ - return Py_BuildValue("s", X509_verify_cert_error_string(X509_STORE_CTX_get_error(self->ctx))); -} - -static char x509_store_ctx_object_get_error_depth__doc__[] = - "Extract verification error depth from this X509StoreCTX.\n" - ; - -static PyObject* -x509_store_ctx_object_get_error_depth (x509_store_ctx_object *self) -{ - return Py_BuildValue("i", X509_STORE_CTX_get_error_depth(self->ctx)); -} - -static char x509_store_ctx_object_get_current_certificate__doc__[] = - "Extract the certificate which caused the current validation error,\n" - "or None if no certificate is relevant.\n" - ; - -static PyObject * -x509_store_ctx_object_get_current_certificate (x509_store_ctx_object *self) -{ - X509 *x = X509_STORE_CTX_get_current_cert(self->ctx); - x509_object *obj = NULL; - - if (x == NULL) - Py_RETURN_NONE; - - if ((x = X509_dup(x)) == NULL) - lose_no_memory(); - - if ((obj = x509_object_new_helper(NULL, x)) == NULL) - goto error; - - return (PyObject *) obj; - - error: - Py_XDECREF(obj); - X509_free(x); - return NULL; -} - -static char x509_store_ctx_object_get_chain__doc__[] = - "Extract certificate chain from X509StoreCTX. If validation\n" - "completed succesfully, this is the complete validation chain;\n" - "otherwise, the returned chain may be invalid or incomplete.\n" - ; - -static PyObject * -x509_store_ctx_object_get_chain (x509_store_ctx_object *self) -{ - STACK_OF(X509) *chain = NULL; - PyObject *result = NULL; - - if ((chain = X509_STORE_CTX_get1_chain(self->ctx)) == NULL) - lose_openssl_error("X509_STORE_CTX_get1_chain() failed"); - - result = stack_to_tuple_helper(CHECKED_PTR_OF(STACK_OF(X509), chain), - stack_to_tuple_helper_get_x509); - - error: /* fall through */ - sk_X509_pop_free(chain, X509_free); - return result; -} - -/* - * For some reason, there are no methods for the policy mechanism for - * X509_STORE, only for X509_STORE_CTX. Presumably we can whack these - * anyway using the X509_VERIFY_PARAM_*() calls, the question is - * whether there's a good reason for this omission. - * - * For the moment, I'm just going to leave the policy stuff - * unimplemented, until we figure out whether it belongs in X509Store - * or X509StoreCTX. - */ - -#define IMPLEMENT_X509StoreCTX_POLICY 0 - -#if IMPLEMENT_X509StoreCTX_POLICY - -static char x509_store_ctx_object_set_policy__doc__[] = - "Set this X509StoreCTX to require a specified certificate policy.\n" - ; - -static PyObject* -x509_store_ctx_object_set_policy (x509_store_ctx_object *self, PyObject *args) -{ - ASN1_OBJECT *policy = NULL; - char *oid = NULL; - - if (!PyArg_ParseTuple(args, "s", &oid)) - goto error; - - if ((policy = OBJ_txt2obj(oid, 1)) == NULL) - lose_openssl_error("Couldn't parse OID"); - - if (!X509_VERIFY_PARAM_set_flags(self->ctx->param, X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY)) - lose_openssl_error("Couldn't set policy flags"); - - if (!X509_VERIFY_PARAM_add0_policy(self->ctx->param, policy)) - lose_openssl_error("Couldn't set policy"); - - Py_RETURN_NONE; - - error: - ASN1_OBJECT_free(policy); - return NULL; -} - -#endif /* IMPLEMENT_X509StoreCTX_POLICY */ - -/* - * See (omnibus) man page for X509_STORE_CTX_get_error() for other - * query methods we might want to expose. Someday we might want to - * support X509_V_FLAG_USE_CHECK_TIME too. - */ - -static struct PyMethodDef x509_store_ctx_object_methods[] = { - Define_Method(getError, x509_store_ctx_object_get_error, METH_NOARGS), - Define_Method(getErrorString, x509_store_ctx_object_get_error_string, METH_NOARGS), - Define_Method(getErrorDepth, x509_store_ctx_object_get_error_depth, METH_NOARGS), - Define_Method(getCurrentCertificate, x509_store_ctx_object_get_current_certificate, METH_NOARGS), - Define_Method(getChain, x509_store_ctx_object_get_chain, METH_NOARGS), - -#if IMPLEMENT_X509StoreCTX_POLICY - Define_Method(setPolicy, x509_store_ctx_object_set_policy, METH_VARARGS), -#endif - {NULL} -}; - -static PyGetSetDef x509_store_ctx_object_getsetters[] = { - {"store", (getter) x509_store_ctx_object_get_store}, - {NULL} -}; - -static char POW_X509StoreCTX_Type__doc__[] = - "This class holds the state of an OpenSSL certificate verification\n" - "operation. Ordinarily, the user will never have cause to instantiate\n" - "this class directly, instead, an object of this class will be returned\n" - "by X509Store.verify().\n" - "\n" - "If you need to see OpenSSL's verification callbacks, you can do so\n" - "by subclassing X509StoreCTX and attaching your subclass to an X509Store\n" - "object using X509Store.setContextClass(). Your subclass should provide\n" - "a .verify_callback() method, wich should expect to receive one argument:\n" - "the integer \"ok\" value passed by OpenSSL's verification callbacks.\n" - "\n" - "The return value from your .verify_callback() method will be is interpreted\n" - "as a boolean value: anything which evaluates to True will be result in a\n" - "return value of 1 to OpenSSL, while anything which evaluates to False will\n" - "result in a return value of 0 to OpenSSL.\n" - ; - -static PyTypeObject POW_X509StoreCTX_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.X509StoreCTX", /* tp_name */ - sizeof(x509_store_ctx_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)x509_store_ctx_object_dealloc,/* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_X509StoreCTX_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - x509_store_ctx_object_methods, /* tp_methods */ - 0, /* tp_members */ - x509_store_ctx_object_getsetters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc) x509_store_ctx_object_init, /* tp_init */ - 0, /* tp_alloc */ - x509_store_ctx_object_new, /* tp_new */ -}; - - - -/* - * CRL object. - */ - -static crl_object * -crl_object_new_helper(PyTypeObject *type, X509_CRL *crl) -{ - crl_object *self = NULL; - - if (type == NULL) - type = &POW_CRL_Type; - - if ((self = (crl_object *) type->tp_alloc(type, 0)) == NULL) - return NULL; - - self->crl = crl; - return self; -} - -static PyObject * -crl_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - crl_object *self = NULL; - X509_CRL *crl = NULL; - - ENTERING(crl_object_new); - - if ((crl = X509_CRL_new()) == NULL) - lose_no_memory(); - - if ((self = crl_object_new_helper(type, crl)) == NULL) - goto error; - - return (PyObject *) self; - - error: - X509_CRL_free(crl); - return NULL; -} - -static void -crl_object_dealloc(crl_object *self) -{ - ENTERING(crl_object_dealloc); - X509_CRL_free(self->crl); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -crl_object_pem_read_helper(PyTypeObject *type, BIO *bio) -{ - crl_object *self; - - ENTERING(crl_object_pem_read_helper); - - if ((self = (crl_object *) crl_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!PEM_read_bio_X509_CRL(bio, &self->crl, NULL, NULL)) - lose_openssl_error("Couldn't PEM encoded load CRL"); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static PyObject * -crl_object_der_read_helper(PyTypeObject *type, BIO *bio) -{ - crl_object *self; - - ENTERING(crl_object_der_read_helper); - - if ((self = (crl_object *) crl_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!d2i_X509_CRL_bio(bio, &self->crl)) - lose_openssl_error("Couldn't load DER encoded CRL"); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static char crl_object_pem_read__doc__[] = - "Read a PEM-encoded CRL object from a string.\n" - ; - -static PyObject * -crl_object_pem_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(crl_object_pem_read); - return read_from_string_helper(crl_object_pem_read_helper, type, args); -} - -static char crl_object_pem_read_file__doc__[] = - "Read a PEM-encoded CRL object from a file.\n" - ; - -static PyObject * -crl_object_pem_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(crl_object_pem_read_file); - return read_from_file_helper(crl_object_pem_read_helper, type, args); -} - -static char crl_object_der_read__doc__[] = - "Read a DER-encoded CRL object from a string.\n" - ; - -static PyObject * -crl_object_der_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(crl_object_der_read); - return read_from_string_helper(crl_object_der_read_helper, type, args); -} - -static char crl_object_der_read_file__doc__[] = - "Read a DER-encoded CRL object from a file.\n" - ; - -static PyObject * -crl_object_der_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(crl_object_der_read_file); - return read_from_file_helper(crl_object_der_read_helper, type, args); -} - -static X509_EXTENSIONS ** -crl_object_extension_helper(crl_object *self) -{ - if (self && self->crl && self->crl->crl) - return &self->crl->crl->extensions; - PyErr_SetString(PyExc_ValueError, "Can't find X509_EXTENSIONS in CRL object"); - return NULL; -} - -static char crl_object_get_version__doc__[] = - "return the version number of this CRL.\n" - ; - -static PyObject * -crl_object_get_version(crl_object *self) -{ - ENTERING(crl_object_get_version); - return Py_BuildValue("l", X509_CRL_get_version(self->crl)); -} - -static char crl_object_set_version__doc__[] = - "Set the version number of this CRL.\n" - "\n" - "The \"version\" parameter should be a positive integer.\n" - ; - -static PyObject * -crl_object_set_version(crl_object *self, PyObject *args) -{ - long version = 0; - - ENTERING(crl_object_set_version); - - if (!PyArg_ParseTuple(args, "i", &version)) - goto error; - - if (!X509_CRL_set_version(self->crl, version)) - lose_no_memory(); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char crl_object_get_issuer__doc__[] = - "Return issuer name of this CRL.\n" - "\n" - "See the \"getIssuer()\" method of the X509 class for more details.\n" - ; - -static PyObject * -crl_object_get_issuer(crl_object *self, PyObject *args) -{ - PyObject *result = NULL; - int format = OIDNAME_FORMAT; - - ENTERING(crl_object_get_issuer); - - if (!PyArg_ParseTuple(args, "|i", &format)) - goto error; - - result = x509_object_helper_get_name(X509_CRL_get_issuer(self->crl), format); - - error: /* Fall through */ - return result; -} - -static char crl_object_set_issuer__doc__[] = - "Set this CRL's issuer name.\n" - "\n" - "See the \"setIssuer()\" method of the X509 class for details.\n" - ; - -static PyObject * -crl_object_set_issuer(crl_object *self, PyObject *args) -{ - PyObject *name_sequence = NULL; - X509_NAME *name = NULL; - - ENTERING(crl_object_set_issuer); - - if (!PyArg_ParseTuple(args, "O", &name_sequence)) - goto error; - - if (!PySequence_Check(name_sequence)) - lose_type_error("Inapropriate type"); - - if ((name = x509_object_helper_set_name(name_sequence)) == NULL) - goto error; - - if (!X509_CRL_set_issuer_name(self->crl, name)) - lose_openssl_error("Unable to set issuer name"); - - X509_NAME_free(name); - - Py_RETURN_NONE; - - error: - X509_NAME_free(name); - return NULL; -} - -/* - * NB: OpenSSL is confused about the name of this field, probably for - * backwards compatability with some ancient mistake. What RFC 5280 - * calls "thisUpdate", OpenSSL calls "lastUpdate". - */ - -static char crl_object_set_this_update__doc__[] = - "Set this CRL's \"thisUpdate\" value.\n" - "\n" - "The \"time\" parameter should be a datetime object.\n" - ; - -static PyObject * -crl_object_set_this_update (crl_object *self, PyObject *args) -{ - PyObject *o = NULL; - ASN1_TIME *t = NULL; - - ENTERING(crl_object_set_this_update); - - if (!PyArg_ParseTuple(args, "O", &o)) - goto error; - - if ((t = Python_to_ASN1_TIME(o, 1)) == NULL) - lose("Couldn't convert thisUpdate string"); - - if (!X509_CRL_set_lastUpdate(self->crl, t)) /* sic */ - lose("Couldn't set thisUpdate"); - - ASN1_TIME_free(t); - Py_RETURN_NONE; - - error: - ASN1_TIME_free(t); - return NULL; -} - -static char crl_object_get_this_update__doc__[] = - "Return this CRL's \"thisUpdate\" value as a datetime.\n" - ; - -static PyObject * -crl_object_get_this_update (crl_object *self) -{ - ENTERING(crl_object_get_this_update); - return ASN1_TIME_to_Python(X509_CRL_get_lastUpdate(self->crl)); /* sic */ -} - -static char crl_object_set_next_update__doc__[] = - "Set this CRL's \"nextUpdate\" value.\n" - "\n" - "The \"time\" parameter should be a datetime object.\n" - ; - -static PyObject * -crl_object_set_next_update (crl_object *self, PyObject *args) -{ - PyObject *o = NULL; - ASN1_TIME *t = NULL; - - ENTERING(crl_object_set_next_update); - - if (!PyArg_ParseTuple(args, "O", &o)) - goto error; - - if ((t = Python_to_ASN1_TIME(o, 1)) == NULL) - lose("Couldn't parse nextUpdate string"); - - if (!X509_CRL_set_nextUpdate(self->crl, t)) - lose("Couldn't set nextUpdate"); - - ASN1_TIME_free(t); - Py_RETURN_NONE; - - error: - ASN1_TIME_free(t); - return NULL; -} - -static char crl_object_get_next_update__doc__[] = - "Returns this CRL's \"nextUpdate\" value as a datetime.\n" - ; - -static PyObject * -crl_object_get_next_update (crl_object *self) -{ - ENTERING(crl_object_get_next_update); - return ASN1_TIME_to_Python(X509_CRL_get_nextUpdate(self->crl)); -} - -static char crl_object_add_revocations__doc__[] = - "This method adds a collection of revocations to this CRL.\n" - "\n" - "The \"iterable\" parameter should be an iterable object which returns\n" - "two-element sequences. The first element of each pair should be the\n" - "revoked serial number (an integer), the second element should be the\n" - "revocation date (a datetime object).\n" - ; - -static PyObject * -crl_object_add_revocations(crl_object *self, PyObject *args) -{ - PyObject *iterable = NULL; - PyObject *iterator = NULL; - PyObject *item = NULL; - PyObject *fast = NULL; - X509_REVOKED *revoked = NULL; - ASN1_INTEGER *serial = NULL; - ASN1_TIME *date = NULL; - int ok = 0; - - ENTERING(crl_object_add_revocations); - - if (!PyArg_ParseTuple(args, "O", &iterable) || - (iterator = PyObject_GetIter(iterable)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if ((fast = PySequence_Fast(item, "Revocation entry must be a sequence")) == NULL) - goto error; - - if (PySequence_Fast_GET_SIZE(fast) != 2) - lose_type_error("Revocation entry must be two-element sequence"); - - if ((serial = PyLong_to_ASN1_INTEGER(PySequence_Fast_GET_ITEM(fast, 0))) == NULL || - (date = Python_to_ASN1_TIME(PySequence_Fast_GET_ITEM(fast, 1), 1)) == NULL) - goto error; - - if ((revoked = X509_REVOKED_new()) == NULL || - !X509_REVOKED_set_serialNumber(revoked, serial) || - !X509_REVOKED_set_revocationDate(revoked, date)) - lose_no_memory(); - - ASN1_INTEGER_free(serial); - serial = NULL; - - ASN1_TIME_free(date); - date = NULL; - - if (!X509_CRL_add0_revoked(self->crl, revoked)) - lose_no_memory(); - - revoked = NULL; - Py_XDECREF(item); - Py_XDECREF(fast); - item = fast = NULL; - } - - if (!X509_CRL_sort(self->crl)) - lose_openssl_error("Couldn't sort CRL"); - - ok = 1; - - error: - Py_XDECREF(iterator); - Py_XDECREF(item); - Py_XDECREF(fast); - X509_REVOKED_free(revoked); - ASN1_INTEGER_free(serial); - ASN1_TIME_free(date); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char crl_object_get_revoked__doc__[] = - "Return a sequence of two-element tuples representing the sequence of\n" - "revoked certificates listed in this CRL.\n" - "\n" - "The first element of each pair is the serialNumber of the revoked\n" - "certificate, the second element is the revocationDate.\n" - ; - -static PyObject * -crl_object_get_revoked(crl_object *self) -{ - STACK_OF(X509_REVOKED) *revoked = NULL; - X509_REVOKED *r = NULL; - PyObject *result = NULL; - PyObject *item = NULL; - PyObject *serial = NULL; - PyObject *date = NULL; - int i; - - ENTERING(crl_object_get_revoked); - - if ((revoked = X509_CRL_get_REVOKED(self->crl)) == NULL) - lose("Inexplicable NULL revocation list pointer"); - - if ((result = PyTuple_New(sk_X509_REVOKED_num(revoked))) == NULL) - goto error; - - for (i = 0; i < sk_X509_REVOKED_num(revoked); i++) { - r = sk_X509_REVOKED_value(revoked, i); - - if ((serial = ASN1_INTEGER_to_PyLong(r->serialNumber)) == NULL || - (date = ASN1_TIME_to_Python(r->revocationDate)) == NULL || - (item = Py_BuildValue("(NN)", serial, date)) == NULL) - goto error; - - PyTuple_SET_ITEM(result, i, item); - item = serial = date = NULL; - } - - return result; - - error: - Py_XDECREF(result); - Py_XDECREF(item); - Py_XDECREF(serial); - Py_XDECREF(date); - return NULL; -} - -static char crl_object_clear_extensions__doc__[] = - "Clear all extensions attached to this CRL.\n" - ; - -static PyObject * -crl_object_clear_extensions(crl_object *self) -{ - X509_EXTENSION *ext; - - ENTERING(crl_object_clear_extensions); - - while ((ext = X509_CRL_delete_ext(self->crl, 0)) != NULL) - X509_EXTENSION_free(ext); - - Py_RETURN_NONE; -} - -static char crl_object_sign__doc__[] = - "Sign this CRL with a private key.\n" - "\n" - "The \"key\" parameter should be an instance of the Asymmetric class,\n" - "containing a private key.\n" - "\n" - "The optional \"digest\" parameter indicates which digest to compute and\n" - "sign, and should be one of the following:\n" - "\n" - "* MD5_DIGEST\n" - "* SHA_DIGEST\n" - "* SHA1_DIGEST\n" - "* SHA256_DIGEST\n" - "* SHA384_DIGEST\n" - "* SHA512_DIGEST\n" - "\n" - "The default digest algorithm is SHA-256.\n" - ; - -static PyObject * -crl_object_sign(crl_object *self, PyObject *args) -{ - asymmetric_object *asym; - int digest_type = SHA256_DIGEST; - const EVP_MD *digest_method = NULL; - - ENTERING(crl_object_sign); - - if (!PyArg_ParseTuple(args, "O!|i", &POW_Asymmetric_Type, &asym, &digest_type)) - goto error; - - if ((digest_method = evp_digest_factory(digest_type)) == NULL) - lose("Unsupported digest algorithm"); - - if (!X509_CRL_sign(self->crl, asym->pkey, digest_method)) - lose_openssl_error("Couldn't sign CRL"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char crl_object_verify__doc__[] = - "Verify this CRL's signature.\n" - "\n" - "The check is performed using OpenSSL's X509_CRL_verify() function.\n" - "\n" - "The \"key\" parameter should be an instance of the Asymmetric class\n" - "containing the public key of the purported signer.\n" - ; - -static PyObject * -crl_object_verify(crl_object *self, PyObject *args) -{ - asymmetric_object *asym; - - ENTERING(crl_object_verify); - - if (!PyArg_ParseTuple(args, "O!", &POW_Asymmetric_Type, &asym)) - goto error; - - return PyBool_FromLong(X509_CRL_verify(self->crl, asym->pkey)); - - error: - return NULL; -} - -static char crl_object_pem_write__doc__[] = - "Return the PEM encoding of this CRL, as a string.\n" - ; - -static PyObject * -crl_object_pem_write(crl_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(crl_object_pem_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!PEM_write_bio_X509_CRL(bio, self->crl)) - lose_openssl_error("Unable to write CRL"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char crl_object_der_write__doc__[] = - "Return the DER encoding of this CRL, as a string.\n" - ; - -static PyObject * -crl_object_der_write(crl_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(crl_object_der_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!i2d_X509_CRL_bio(bio, self->crl)) - lose_openssl_error("Unable to write CRL"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char crl_object_get_aki__doc__[] = - "Return the Authority Key Identifier (AKI) keyid value for\n" - "this CRL, or None if the CRL has no AKI extension\n" - "or has an AKI extension with no keyIdentifier value.\n" - ; - -static PyObject * -crl_object_get_aki(crl_object *self) -{ - return extension_get_aki(crl_object_extension_helper(self)); -} - -static char crl_object_set_aki__doc__[] = - "Set the Authority Key Identifier (AKI) value for this\n" - "CRL. We only support the keyIdentifier method, as that's\n" - "the only form which is legal for RPKI certificates.\n" - ; - -static PyObject * -crl_object_set_aki(crl_object *self, PyObject *args) -{ - return extension_set_aki(crl_object_extension_helper(self), args); -} - -static char crl_object_get_crl_number__doc__[] = - "Return the CRL Number extension value from this CRL, an integer.\n" - ; - -static PyObject * -crl_object_get_crl_number(crl_object *self) -{ - ASN1_INTEGER *ext = X509_CRL_get_ext_d2i(self->crl, NID_crl_number, NULL, NULL); - PyObject *result = NULL; - - ENTERING(crl_object_get_crl_number); - - if (ext == NULL) - Py_RETURN_NONE; - - result = Py_BuildValue("N", ASN1_INTEGER_to_PyLong(ext)); - ASN1_INTEGER_free(ext); - return result; -} - -static char crl_object_set_crl_number__doc__[] = - "Set the CRL Number extension value in this CRL.\n" - "\n" - "The \"number\" parameter should be an integer.\n" - ; - -static PyObject * -crl_object_set_crl_number(crl_object *self, PyObject *args) -{ - ASN1_INTEGER *ext = NULL; - PyObject *crl_number = NULL; - - ENTERING(crl_object_set_crl_number); - - if (!PyArg_ParseTuple(args, "O", &crl_number) || - (ext = PyLong_to_ASN1_INTEGER(crl_number)) == NULL) - goto error; - - if (!X509_CRL_add1_ext_i2d(self->crl, NID_crl_number, ext, 0, X509V3_ADD_REPLACE)) - lose_openssl_error("Couldn't add CRL Number extension to CRL"); - - ASN1_INTEGER_free(ext); - Py_RETURN_NONE; - - error: - ASN1_INTEGER_free(ext); - return NULL; -} - -static char crl_object_pprint__doc__[] = - "Return a pretty-printed rendition of this CRL.\n" - ; - -static PyObject * -crl_object_pprint(crl_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(crl_object_pprint); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!X509_CRL_print(bio, self->crl)) - lose_openssl_error("Unable to pretty-print CRL"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static struct PyMethodDef crl_object_methods[] = { - Define_Method(sign, crl_object_sign, METH_VARARGS), - Define_Method(verify, crl_object_verify, METH_VARARGS), - Define_Method(getVersion, crl_object_get_version, METH_NOARGS), - Define_Method(setVersion, crl_object_set_version, METH_VARARGS), - Define_Method(getIssuer, crl_object_get_issuer, METH_VARARGS), - Define_Method(setIssuer, crl_object_set_issuer, METH_VARARGS), - Define_Method(getThisUpdate, crl_object_get_this_update, METH_NOARGS), - Define_Method(setThisUpdate, crl_object_set_this_update, METH_VARARGS), - Define_Method(getNextUpdate, crl_object_get_next_update, METH_NOARGS), - Define_Method(setNextUpdate, crl_object_set_next_update, METH_VARARGS), - Define_Method(getRevoked, crl_object_get_revoked, METH_NOARGS), - Define_Method(addRevocations, crl_object_add_revocations, METH_VARARGS), - Define_Method(clearExtensions, crl_object_clear_extensions, METH_NOARGS), - Define_Method(pemWrite, crl_object_pem_write, METH_NOARGS), - Define_Method(derWrite, crl_object_der_write, METH_NOARGS), - Define_Method(pprint, crl_object_pprint, METH_NOARGS), - Define_Method(getAKI, crl_object_get_aki, METH_NOARGS), - Define_Method(setAKI, crl_object_set_aki, METH_VARARGS), - Define_Method(getCRLNumber, crl_object_get_crl_number, METH_NOARGS), - Define_Method(setCRLNumber, crl_object_set_crl_number, METH_VARARGS), - Define_Class_Method(pemRead, crl_object_pem_read, METH_VARARGS), - Define_Class_Method(pemReadFile, crl_object_pem_read_file, METH_VARARGS), - Define_Class_Method(derRead, crl_object_der_read, METH_VARARGS), - Define_Class_Method(derReadFile, crl_object_der_read_file, METH_VARARGS), - {NULL} -}; - -static char POW_CRL_Type__doc__[] = - "Container for OpenSSL's X509 CRL management facilities.\n" - ; - -static PyTypeObject POW_CRL_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.CRL", /* tp_name */ - sizeof(crl_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)crl_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_CRL_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - crl_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - crl_object_new, /* tp_new */ -}; - - - -/* - * Asymmetric object. - */ - -static PyObject * -asymmetric_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - asymmetric_object *self = NULL; - - ENTERING(asymmetric_object_new); - - if ((self = (asymmetric_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - self->pkey = NULL; - - return (PyObject *) self; - - error: - - Py_XDECREF(self); - return NULL; -} - -static int -asymmetric_object_init(asymmetric_object *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {NULL}; - - ENTERING(asymmetric_object_init); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) - goto error; - - /* - * We used to take arguments to generate an RSA key, but that's - * now in the .generateRSA() class method. - */ - - return 0; - - error: - return -1; -} - -static void -asymmetric_object_dealloc(asymmetric_object *self) -{ - ENTERING(asymmetric_object_dealloc); - EVP_PKEY_free(self->pkey); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -asymmetric_object_pem_read_private_helper(PyTypeObject *type, BIO *bio, char *pass) -{ - asymmetric_object *self = NULL; - - ENTERING(asymmetric_object_pem_read_private_helper); - - if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!PEM_read_bio_PrivateKey(bio, &self->pkey, NULL, pass)) - lose_openssl_error("Couldn't load private key"); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -/* - * We can't use the generic read_from_*_helper() functions here - * because of optional the PEM password, so we just code the two PEM - * read cases for private keys directly. Other than the passphrase, - * code is pretty much the same as the generic functions. - * - * It turns out that OpenSSL is moving away from its old raw PKCS #1.5 - * private key format in favor of PKCS #8. This makes sense, but it - * leaves us with a minor mess to track. Many OpenSSL functions that - * originally expected PKCS #1.5 now also accept PKCS #8, so there's - * no tearing hurry about this, but at some point we might want to - * switch to writing PKCS #8. It looks like this would be relatively - * straightforward: see functions i2d_PKCS8PrivateKey_bio() and - * PEM_write_bio_PKCS8PrivateKey(), and note that PKCS #8 supports - * encrypted private keys in DER format, so the DER methods should - * take a passphrase argument as the PEM methods do. - */ - -static char asymmetric_object_pem_read_private__doc__[] = - "Read a PEM-encoded private key from a string.\n" - "\n" - "Optional second argument is a passphrase for the key.\n" - ; - -static PyObject * -asymmetric_object_pem_read_private(PyTypeObject *type, PyObject *args) -{ - PyObject *result = NULL; - char *pass = NULL; - char *src = NULL; - BIO *bio = NULL; - Py_ssize_t len = 0; - - ENTERING(asymmetric_object_pem_read_private); - - if (!PyArg_ParseTuple(args, "s#|s", &src, &len, &pass)) - goto error; - - if ((bio = BIO_new_mem_buf(src, len)) == NULL) - lose_no_memory(); - - result = asymmetric_object_pem_read_private_helper(type, bio, pass); - - error: - BIO_free(bio); - return result; -} - -static char asymmetric_object_pem_read_private_file__doc__[] = - "Read a PEM-encoded private key from a file.\n" - "\n" - "Optional second argument is a passphrase for the key.\n" - ; - -static PyObject * -asymmetric_object_pem_read_private_file(PyTypeObject *type, PyObject *args) -{ - const char *filename = NULL; - PyObject *result = NULL; - char *pass = NULL; - BIO *bio = NULL; - - ENTERING(asymmetric_object_pem_read_private_file); - - if (!PyArg_ParseTuple(args, "s|s", &filename, &pass)) - goto error; - - if ((bio = BIO_new_file(filename, "rb")) == NULL) - lose_openssl_error("Could not open file"); - - result = asymmetric_object_pem_read_private_helper(type, bio, pass); - - error: - BIO_free(bio); - return result; -} - -static PyObject * -asymmetric_object_der_read_private_helper(PyTypeObject *type, BIO *bio) -{ - asymmetric_object *self = NULL; - - ENTERING(asymmetric_object_der_read_private_helper); - - if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!d2i_PrivateKey_bio(bio, &self->pkey)) - lose_openssl_error("Couldn't load private key"); - - return (PyObject *) self; - - error: - - Py_XDECREF(self); - return NULL; -} - -static char asymmetric_object_der_read_private__doc__[] = - "Read a DER-encoded private key from a string.\n" - ; - -static PyObject * -asymmetric_object_der_read_private(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_object_der_read_private); - return read_from_string_helper(asymmetric_object_der_read_private_helper, type, args); -} - -static char asymmetric_object_der_read_private_file__doc__[] = - "Read a DER-encoded private key from a file.\n" - ; - -static PyObject * -asymmetric_object_der_read_private_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_object_der_read_private_file); - return read_from_file_helper(asymmetric_object_der_read_private_helper, type, args); -} - -static PyObject * -asymmetric_object_pem_read_public_helper(PyTypeObject *type, BIO *bio) -{ - asymmetric_object *self = NULL; - - ENTERING(asymmetric_object_pem_read_public_helper); - - if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!PEM_read_bio_PUBKEY(bio, &self->pkey, NULL, NULL)) - lose_openssl_error("Couldn't load public key"); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static PyObject * -asymmetric_object_der_read_public_helper(PyTypeObject *type, BIO *bio) -{ - asymmetric_object *self = NULL; - - ENTERING(asymmetric_object_der_read_public_helper); - - if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!d2i_PUBKEY_bio(bio, &self->pkey)) - lose_openssl_error("Couldn't load public key"); - - return (PyObject *) self; - - error: - - Py_XDECREF(self); - return NULL; -} - -static char asymmetric_object_pem_read_public__doc__[] = - "Read a PEM-encoded public key from a string.\n" - ; - -static PyObject * -asymmetric_object_pem_read_public(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_object_pem_read_public); - return read_from_string_helper(asymmetric_object_pem_read_public_helper, type, args); -} - -static char asymmetric_object_pem_read_public_file__doc__[] = - "Read a PEM-encoded public key from a file.\n" - ; - -static PyObject * -asymmetric_object_pem_read_public_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_object_pem_read_public_file); - return read_from_file_helper(asymmetric_object_pem_read_public_helper, type, args); -} - -static char asymmetric_object_der_read_public__doc__[] = - "Read a DER-encoded public key from a string.\n" - ; - -static PyObject * -asymmetric_object_der_read_public(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_object_der_read_public); - return read_from_string_helper(asymmetric_object_der_read_public_helper, type, args); -} - -static char asymmetric_object_der_read_public_file__doc__[] = - "Read a DER-encoded public key from a file.\n" - ; - -static PyObject * -asymmetric_object_der_read_public_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_object_der_read_public_file); - return read_from_file_helper(asymmetric_object_der_read_public_helper, type, args); -} - -static char asymmetric_object_pem_write_private__doc__[] = - "Return the PEM encoding of an \"Asymmetric\" private key.\n" - "\n" - "This method takes an optional parameter \"passphrase\" which, if\n" - "specified, will be used to encrypt the private key with AES-256-CBC.\n" - "\n" - "If you don't specify a passphrase, the key will not be encrypted.\n" - ; - -static PyObject * -asymmetric_object_pem_write_private(asymmetric_object *self, PyObject *args) -{ - PyObject *result = NULL; - char *passphrase = NULL; - const EVP_CIPHER *evp_method = NULL; - BIO *bio = NULL; - - ENTERING(asymmetric_object_pem_write_private); - - if (!PyArg_ParseTuple(args, "|s", &passphrase)) - goto error; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (passphrase) - evp_method = EVP_aes_256_cbc(); - - if (!PEM_write_bio_PrivateKey(bio, self->pkey, evp_method, NULL, 0, NULL, passphrase)) - lose_openssl_error("Unable to write key"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char asymmetric_object_pem_write_public__doc__[] = - "Return the PEM encoding of an \"Asymmetric\" public key.\n" - ; - -static PyObject * -asymmetric_object_pem_write_public(asymmetric_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(asymmetric_object_pem_write_public); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!PEM_write_bio_PUBKEY(bio, self->pkey)) - lose_openssl_error("Unable to write key"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char asymmetric_object_der_write_private__doc__[] = - "Return the DER encoding of an \"Asymmetric\" private key.\n" - ; - -static PyObject * -asymmetric_object_der_write_private(asymmetric_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(asymmetric_object_der_write_private); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!i2d_PrivateKey_bio(bio, self->pkey)) - lose_openssl_error("Unable to write private key"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char asymmetric_object_der_write_public__doc__[] = - "Return the DER encoding of an \"Asymmetric\" public key.\n" - ; - -static PyObject * -asymmetric_object_der_write_public(asymmetric_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(asymmetric_object_der_write_public); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!i2d_PUBKEY_bio(bio, self->pkey)) - lose_openssl_error("Unable to write public key"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char asymmetric_object_generate_rsa__doc__[] = - "Generate a new RSA keypair.\n" - "\n" - "Optional argument key_size is the desired key size, in bits;\n" - "if not specified, the default is 2048." - ; - -static PyObject * -asymmetric_object_generate_rsa(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"key_size", NULL}; - asymmetric_object *self = NULL; - EVP_PKEY_CTX *ctx = NULL; - int key_size = 2048; - int ok = 0; - - ENTERING(asymmetric_object_generate_rsa); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &key_size)) - goto error; - - if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL) - goto error; - - /* - * Explictly setting RSA_F4 would be tedious, as it requires messing - * about with bignums, and F4 is the default, so we leave it alone. - * In case this ever changes, the required sequence would be: - * BN_new(), BN_set_word(), EVP_PKEY_CTX_set_rsa_keygen_pubexp(), - * BN_free(). - */ - - if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL || - EVP_PKEY_keygen_init(ctx) <= 0 || - EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, key_size) <= 0 || - EVP_PKEY_keygen(ctx, &self->pkey) <= 0) - lose_openssl_error("Couldn't generate new RSA key"); - - ok = 1; - - error: - EVP_PKEY_CTX_free(ctx); - - if (ok) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static char asymmetric_object_generate_from_params__doc__[] = - "Generate a new keypair using an AsymmetricParams object.\n" - ; - -static PyObject * -asymmetric_object_generate_from_params(PyTypeObject *type, PyObject *args) -{ - asymmetric_params_object *params = NULL; - asymmetric_object *self = NULL; - EVP_PKEY_CTX *ctx = NULL; - int ok = 0; - - ENTERING(asymmetric_object_generate_from_params); - - if (!PyArg_ParseTuple(args, "O!", &POW_AsymmetricParams_Type, ¶ms)) - goto error; - - if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL) - goto error; - - if ((ctx = EVP_PKEY_CTX_new(params->pkey, NULL)) == NULL || - EVP_PKEY_keygen_init(ctx) <= 0 || - EVP_PKEY_keygen(ctx, &self->pkey) <= 0) - lose_openssl_error("Couldn't generate new key"); - - ok = 1; - - error: - EVP_PKEY_CTX_free(ctx); - - if (ok) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static char asymmetric_object_calculate_ski__doc__[] = - "Calculate SKI value for this key.\n" - "\n" - "The SKI is the SHA-1 hash of key's SubjectPublicKey value.\n" - ; - -static PyObject * -asymmetric_object_calculate_ski(asymmetric_object *self) -{ - PyObject *result = NULL; - X509_PUBKEY *pubkey = NULL; - unsigned char digest[EVP_MAX_MD_SIZE]; - unsigned digest_length; - - ENTERING(asymmetric_object_calculate_ski); - - if (!X509_PUBKEY_set(&pubkey, self->pkey)) - lose_openssl_error("Couldn't extract public key"); - - if (!EVP_Digest(pubkey->public_key->data, pubkey->public_key->length, - digest, &digest_length, EVP_sha1(), NULL)) - lose_openssl_error("Couldn't calculate SHA-1 digest of public key"); - - result = PyString_FromStringAndSize((char *) digest, digest_length); - - error: - X509_PUBKEY_free(pubkey); - return result; -} - -static struct PyMethodDef asymmetric_object_methods[] = { - Define_Method(pemWritePrivate, asymmetric_object_pem_write_private, METH_VARARGS), - Define_Method(pemWritePublic, asymmetric_object_pem_write_public, METH_NOARGS), - Define_Method(derWritePrivate, asymmetric_object_der_write_private, METH_NOARGS), - Define_Method(derWritePublic, asymmetric_object_der_write_public, METH_NOARGS), - Define_Method(calculateSKI, asymmetric_object_calculate_ski, METH_NOARGS), - Define_Class_Method(pemReadPublic, asymmetric_object_pem_read_public, METH_VARARGS), - Define_Class_Method(pemReadPublicFile, asymmetric_object_pem_read_public_file, METH_VARARGS), - Define_Class_Method(derReadPublic, asymmetric_object_der_read_public, METH_VARARGS), - Define_Class_Method(derReadPublicFile, asymmetric_object_der_read_public_file, METH_VARARGS), - Define_Class_Method(pemReadPrivate, asymmetric_object_pem_read_private, METH_VARARGS), - Define_Class_Method(pemReadPrivateFile, asymmetric_object_pem_read_private_file, METH_VARARGS), - Define_Class_Method(derReadPrivate, asymmetric_object_der_read_private, METH_VARARGS), - Define_Class_Method(derReadPrivateFile, asymmetric_object_der_read_private_file, METH_VARARGS), - Define_Class_Method(generateRSA, asymmetric_object_generate_rsa, METH_KEYWORDS), - Define_Class_Method(generateFromParams, asymmetric_object_generate_from_params, METH_VARARGS), - {NULL} -}; - -static char POW_Asymmetric_Type__doc__[] = - "Container for OpenSSL's EVP_PKEY asymmetric key classes.\n" - "\n" - LAME_DISCLAIMER_IN_ALL_CLASS_DOCUMENTATION - ; - -static PyTypeObject POW_Asymmetric_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.Asymmetric", /* tp_name */ - sizeof(asymmetric_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)asymmetric_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_Asymmetric_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - asymmetric_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc) asymmetric_object_init, /* tp_init */ - 0, /* tp_alloc */ - asymmetric_object_new, /* tp_new */ -}; - - - -/* - * AsymmetricParams object. - */ - -static PyObject * -asymmetric_params_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - asymmetric_params_object *self = NULL; - - ENTERING(asymmetric_params_object_new); - - if ((self = (asymmetric_params_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - self->pkey = NULL; - - return (PyObject *) self; - - error: - - Py_XDECREF(self); - return NULL; -} - -static int -asymmetric_params_object_init(asymmetric_params_object *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {NULL}; - - ENTERING(asymmetric_params_object_init); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) - goto error; - - return 0; - - error: - return -1; -} - -static void -asymmetric_params_object_dealloc(asymmetric_params_object *self) -{ - ENTERING(asymmetric_params_object_dealloc); - EVP_PKEY_free(self->pkey); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -asymmetric_params_object_pem_read_helper(PyTypeObject *type, BIO *bio) -{ - asymmetric_params_object *self = NULL; - - ENTERING(asymmetric_params_object_pem_read_helper); - - if ((self = (asymmetric_params_object *) asymmetric_params_object_new(type, NULL, NULL)) == NULL) - goto error; - - if (!PEM_read_bio_Parameters(bio, &self->pkey)) - lose_openssl_error("Couldn't load PEM encoded key parameters"); - - return (PyObject *) self; - - error: - - Py_XDECREF(self); - return NULL; -} - -static char asymmetric_params_object_pem_read__doc__[] = - "Read PEM-encoded key parameters from a string.\n" - ; - -static PyObject * -asymmetric_params_object_pem_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_params_object_pem_read); - return read_from_string_helper(asymmetric_params_object_pem_read_helper, type, args); -} - -static char asymmetric_params_object_pem_read_file__doc__[] = - "Read PEM-encoded key parameters from a file.\n" - ; - -static PyObject * -asymmetric_params_object_pem_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(asymmetric_params_object_pem_read_file); - return read_from_file_helper(asymmetric_params_object_pem_read_helper, type, args); -} - -static char asymmetric_params_object_pem_write__doc__[] = - "Return the PEM encoding of this set of key parameters, as a string.\n" - ; - -static PyObject * -asymmetric_params_object_pem_write(asymmetric_params_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(asymmetric_params_object_pem_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (PEM_write_bio_Parameters(bio, self->pkey) <= 0) - lose_openssl_error("Unable to write key parameters"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char asymmetric_params_object_generate_ec__doc__[] = - "Generate a new set of EC parameters.\n" - "\n" - "Optional argument curve is a numeric code representing the curve to use;\n" - "if not specified, the default is P-256." - ; - -static PyObject * -asymmetric_params_object_generate_ec(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"curve", NULL}; - asymmetric_params_object *self = NULL; - EVP_PKEY_CTX *ctx = NULL; - int curve = NID_X9_62_prime256v1; - int ok = 0; - - ENTERING(asymmetric_params_object_generate_ec); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &curve)) - goto error; - - if ((self = (asymmetric_params_object *) asymmetric_params_object_new(type, NULL, NULL)) == NULL) - goto error; - - if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || - EVP_PKEY_paramgen_init(ctx) <= 0 || - EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve) <= 0 || - EVP_PKEY_paramgen(ctx, &self->pkey) <= 0) - lose_openssl_error("Couldn't generate key parameters"); - - ok = 1; - - error: - EVP_PKEY_CTX_free(ctx); - - if (ok) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static char asymmetric_params_object_generate_dh__doc__[] = - "Generate a new set of DH parameters.\n" - "\n" - "Optional argument prime_length is length of the DH prime parameter\n" - "to use, in bits; if not specified, the default is 2048 bits.\n" - "\n" - "Be warned that generating DH parameters with a 2048-bit prime may\n" - "take a ridiculously long time.\n" - ; - -static PyObject * -asymmetric_params_object_generate_dh(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"prime_length", NULL}; - asymmetric_params_object *self = NULL; - EVP_PKEY_CTX *ctx = NULL; - int prime_length = 2048; - int ok = 0; - - ENTERING(asymmetric_params_object_generate_dh); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &prime_length)) - goto error; - - if ((self = (asymmetric_params_object *) asymmetric_params_object_new(type, NULL, NULL)) == NULL) - goto error; - - if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL)) == NULL || - EVP_PKEY_paramgen_init(ctx) <= 0 || - EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, prime_length) <= 0 || - EVP_PKEY_paramgen(ctx, &self->pkey) <= 0) - lose_openssl_error("Couldn't generate key parameters"); - - ok = 1; - - error: - EVP_PKEY_CTX_free(ctx); - - if (ok) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static char asymmetric_params_object_generate_dsa__doc__[] = - "Generate a new set of DSA parameters.\n" - "\n" - "Optional argument key_length is the length of the key to generate, in bits;\n" - "if not specified, the default is 2048 bits." - ; - -static PyObject * -asymmetric_params_object_generate_dsa(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"key_length", NULL}; - asymmetric_params_object *self = NULL; - EVP_PKEY_CTX *ctx = NULL; - int key_length = 2048; - int ok = 0; - - ENTERING(asymmetric_params_object_generate_dsa); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &key_length)) - goto error; - - if ((self = (asymmetric_params_object *) asymmetric_params_object_new(type, NULL, NULL)) == NULL) - goto error; - - if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL)) == NULL || - EVP_PKEY_paramgen_init(ctx) <= 0 || - EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, key_length) <= 0 || - EVP_PKEY_paramgen(ctx, &self->pkey) <= 0) - lose_openssl_error("Couldn't generate key parameters"); - - ok = 1; - - error: - EVP_PKEY_CTX_free(ctx); - - if (ok) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static struct PyMethodDef asymmetric_params_object_methods[] = { - Define_Method(pemWrite, asymmetric_params_object_pem_write, METH_NOARGS), - Define_Class_Method(pemRead, asymmetric_params_object_pem_read, METH_VARARGS), - Define_Class_Method(pemReadFile, asymmetric_params_object_pem_read_file, METH_VARARGS), - Define_Class_Method(generateEC, asymmetric_params_object_generate_ec, METH_KEYWORDS), - Define_Class_Method(generateDH, asymmetric_params_object_generate_dh, METH_KEYWORDS), - Define_Class_Method(generateDSA, asymmetric_params_object_generate_dsa, METH_KEYWORDS), - {NULL} -}; - -static char POW_AsymmetricParams_Type__doc__[] = - "Container for OpenSSL's EVP_PKEY asymmetric key parameter classes.\n" - "\n" - LAME_DISCLAIMER_IN_ALL_CLASS_DOCUMENTATION - ; - -static PyTypeObject POW_AsymmetricParams_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.AsymmetricParams", /* tp_name */ - sizeof(asymmetric_params_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)asymmetric_params_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_AsymmetricParams_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - asymmetric_params_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc) asymmetric_params_object_init, /* tp_init */ - 0, /* tp_alloc */ - asymmetric_params_object_new, /* tp_new */ -}; - - - -/* - * Digest object. - */ - -static PyObject * -digest_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - digest_object *self = NULL; - - ENTERING(digest_object_new); - - if ((self = (digest_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - self->digest_type = 0; - - return (PyObject *) self; - - error: - return NULL; -} - -static int -digest_object_init(digest_object *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"digest_type", NULL}; - const EVP_MD *digest_method = NULL; - int digest_type = 0; - - ENTERING(digest_object_init); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &digest_type)) - goto error; - - if ((digest_method = evp_digest_factory(digest_type)) == NULL) - lose("Unsupported digest algorithm"); - - self->digest_type = digest_type; - if (!EVP_DigestInit(&self->digest_ctx, digest_method)) - lose_openssl_error("Couldn't initialize digest"); - - return 0; - - error: - return -1; -} - -static void -digest_object_dealloc(digest_object *self) -{ - ENTERING(digest_object_dealloc); - EVP_MD_CTX_cleanup(&self->digest_ctx); - self->ob_type->tp_free((PyObject*) self); -} - -static char digest_object_update__doc__[] = - "Add data to this digest.\n" - "\n" - "the \"data\" parameter should be a string containing the data to be added.\n" - ; - -static PyObject * -digest_object_update(digest_object *self, PyObject *args) -{ - char *data = NULL; - Py_ssize_t len = 0; - - ENTERING(digest_object_update); - - if (!PyArg_ParseTuple(args, "s#", &data, &len)) - goto error; - - if (!EVP_DigestUpdate(&self->digest_ctx, data, len)) - lose_openssl_error("EVP_DigestUpdate() failed"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char digest_object_copy__doc__[] = - "Return a copy of this Digest object.\n" - ; - -static PyObject * -digest_object_copy(digest_object *self) -{ - digest_object *new = NULL; - - ENTERING(digest_object_copy); - - if ((new = (digest_object *) digest_object_new(&POW_Digest_Type, NULL, NULL)) == NULL) - goto error; - - new->digest_type = self->digest_type; - if (!EVP_MD_CTX_copy(&new->digest_ctx, &self->digest_ctx)) - lose_openssl_error("Couldn't copy digest"); - - return (PyObject*) new; - - error: - - Py_XDECREF(new); - return NULL; -} - -static char digest_object_digest__doc__[] = - "Return the digest of all the data which this Digest object has processed.\n" - "\n" - "This method can be called at any time and will not effect the internal\n" - "state of the Digest object.\n" - ; - -/* - * Do we really need to do this copy? Nice general operation, but does - * anything we're doing for RPKI care? - */ - -static PyObject * -digest_object_digest(digest_object *self) -{ - unsigned char digest_text[EVP_MAX_MD_SIZE]; - EVP_MD_CTX ctx; - unsigned digest_len = 0; - - ENTERING(digest_object_digest); - - if (!EVP_MD_CTX_copy(&ctx, &self->digest_ctx)) - lose_openssl_error("Couldn't copy digest"); - - EVP_DigestFinal(&ctx, digest_text, &digest_len); - - EVP_MD_CTX_cleanup(&ctx); - - return Py_BuildValue("s#", digest_text, (Py_ssize_t) digest_len); - - error: - return NULL; -} - -static struct PyMethodDef digest_object_methods[] = { - Define_Method(update, digest_object_update, METH_VARARGS), - Define_Method(digest, digest_object_digest, METH_NOARGS), - Define_Method(copy, digest_object_copy, METH_NOARGS), - {NULL} -}; - -static char POW_Digest_Type__doc__[] = - "This class provides access to the digest functionality of OpenSSL.\n" - "It emulates the digest modules in the Python Standard Library, but\n" - "does not currently support the \"hexdigest\" method.\n" - "\n" - "The constructor takes one parameter, the kind of Digest object to create.\n" - "This should be one of the following:\n" - "\n" - " * MD5_DIGEST\n" - " * SHA_DIGEST\n" - " * SHA1_DIGEST\n" - " * SHA256_DIGEST\n" - " * SHA384_DIGEST\n" - " * SHA512_DIGEST\n" - ; - -static PyTypeObject POW_Digest_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.Digest", /* tp_name */ - sizeof(digest_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)digest_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_Digest_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - digest_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc) digest_object_init, /* tp_init */ - 0, /* tp_alloc */ - digest_object_new, /* tp_new */ -}; - - - -/* - * CMS object. - */ - -static PyObject * -cms_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - cms_object *self; - - ENTERING(cms_object_new); - - if ((self = (cms_object *) type->tp_alloc(type, 0)) != NULL) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static void -cms_object_dealloc(cms_object *self) -{ - ENTERING(cms_object_dealloc); - CMS_ContentInfo_free(self->cms); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -cms_object_pem_read_helper(PyTypeObject *type, BIO *bio) -{ - cms_object *self; - - ENTERING(cms_object_pem_read_helper); - - if ((self = (cms_object *) type->tp_new(type, NULL, NULL)) == NULL) - goto error; - - if (!PEM_read_bio_CMS(bio, &self->cms, NULL, NULL)) - lose_openssl_error("Couldn't load PEM encoded CMS message"); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static PyObject * -cms_object_der_read_helper(PyTypeObject *type, BIO *bio) -{ - cms_object *self; - - ENTERING(cms_object_der_read_helper); - - if ((self = (cms_object *) type->tp_new(type, NULL, NULL)) == NULL) - goto error; - - if (!d2i_CMS_bio(bio, &self->cms)) - lose_openssl_error("Couldn't load DER encoded CMS message"); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static char cms_object_pem_read__doc__[] = - "Read a PEM-encoded CMS object from a string.\n" - ; - -static PyObject * -cms_object_pem_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(cms_object_pem_read); - return read_from_string_helper(cms_object_pem_read_helper, type, args); -} - -static char cms_object_pem_read_file__doc__[] = - "Read a PEM-encoded CMS object from a file.\n" - ; - -static PyObject * -cms_object_pem_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(cms_object_pem_read_file); - return read_from_file_helper(cms_object_pem_read_helper, type, args); -} - -static char cms_object_der_read__doc__[] = - "Read a DER-encoded CMS object from a string.\n" - ; - -static PyObject * -cms_object_der_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(cms_object_der_read); - return read_from_string_helper(cms_object_der_read_helper, type, args); -} - -static char cms_object_der_read_file__doc__[] = - "Read a DER-encoded CMS object from a file.\n" - ; - -static PyObject * -cms_object_der_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(cms_object_der_read_file); - return read_from_file_helper(cms_object_der_read_helper, type, args); -} - -static char cms_object_pem_write__doc__[] = - "Return the DER encoding of this CMS message.\n" - ; - -static PyObject * -cms_object_pem_write(cms_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(cms_object_pem_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!PEM_write_bio_CMS(bio, self->cms)) - lose_openssl_error("Unable to write CMS object"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char cms_object_der_write__doc__[] = - "Return the DER encoding of this CMS message.\n" - ; - -static PyObject * -cms_object_der_write(cms_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(cms_object_der_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!i2d_CMS_bio(bio, self->cms)) - lose_openssl_error("Unable to write CMS object"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static int -cms_object_sign_helper(cms_object *self, - BIO *bio, - x509_object *signcert, - asymmetric_object *signkey, - PyObject *x509_iterable, - PyObject *crl_iterable, - char *oid, - unsigned flags) -{ - STACK_OF(X509) *x509_stack = NULL; - ASN1_OBJECT *econtent_type = NULL; - CMS_ContentInfo *cms = NULL; - PyObject *iterator = NULL; - PyObject *item = NULL; - int ok = 0; - - ENTERING(cms_object_sign_helper); - - assert_no_unhandled_openssl_errors(); - - flags &= CMS_NOCERTS | CMS_NOATTR; - flags |= CMS_BINARY | CMS_NOSMIMECAP | CMS_PARTIAL | CMS_USE_KEYID; - - if ((x509_stack = x509_helper_iterable_to_stack(x509_iterable)) == NULL) - goto error; - - assert_no_unhandled_openssl_errors(); - - if (oid && (econtent_type = OBJ_txt2obj(oid, 1)) == NULL) - lose_openssl_error("Couldn't parse OID"); - - assert_no_unhandled_openssl_errors(); - - if ((cms = CMS_sign(NULL, NULL, x509_stack, bio, flags)) == NULL) - lose_openssl_error("Couldn't create CMS message"); - - assert_no_unhandled_openssl_errors(); - - if (econtent_type) - CMS_set1_eContentType(cms, econtent_type); - - assert_no_unhandled_openssl_errors(); - - if (!CMS_add1_signer(cms, signcert->x509, signkey->pkey, EVP_sha256(), flags)) - lose_openssl_error("Couldn't sign CMS message"); - - assert_no_unhandled_openssl_errors(); - - if (crl_iterable != Py_None) { - - if ((iterator = PyObject_GetIter(crl_iterable)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if (!POW_CRL_Check(item)) - lose_type_error("Inappropriate type"); - - if (!CMS_add1_crl(cms, ((crl_object *) item)->crl)) - lose_openssl_error("Couldn't add CRL to CMS"); - - assert_no_unhandled_openssl_errors(); - - Py_XDECREF(item); - item = NULL; - } - } - - if (!CMS_final(cms, bio, NULL, flags)) - lose_openssl_error("Couldn't finalize CMS signatures"); - - assert_no_unhandled_openssl_errors(); - - CMS_ContentInfo_free(self->cms); - self->cms = cms; - cms = NULL; - - ok = 1; - - error: /* fall through */ - CMS_ContentInfo_free(cms); - sk_X509_free(x509_stack); - ASN1_OBJECT_free(econtent_type); - Py_XDECREF(iterator); - Py_XDECREF(item); - - return ok; -} - -static char cms_object_sign__doc__[] = - "Sign this CMS message message with a private key.\n" - "\n" - "The \"signcert\" parameter should be the certificate against which the\n" - "message will eventually be verified, an X509 object.\n" - "\n" - "The \"key\" parameter should be the private key with which to sign the\n" - "message, an Asymmetric object.\n" - "\n" - "The \"data\" parameter should be the message to be signed, a string.\n" - "\n" - "The optional \"certs\" parameter should be an iterable supplying X509 objects\n" - "to be included in the signed message.\n" - "\n" - "The optional \"crls\" parameter should be an iterable supplying CRL objects\n" - "to be included in the signed message.\n" - "\n" - "The optional \"eContentType\" parameter should be an Object Identifier\n" - "to use as the eContentType value in the signed message.\n" - "\n" - "The optional \"flags\" parameters should be an integer holding a bitmask,\n" - "and can include the following flags:\n" - "\n" - " * CMS_NOCERTS\n" - " * CMS_NOATTR\n" - ; - -static PyObject * -cms_object_sign(cms_object *self, PyObject *args) -{ - asymmetric_object *signkey = NULL; - x509_object *signcert = NULL; - PyObject *x509_iterable = Py_None; - PyObject *crl_iterable = Py_None; - char *buf = NULL, *oid = NULL; - Py_ssize_t len; - unsigned flags = 0; - BIO *bio = NULL; - int ok = 0; - - ENTERING(cms_object_sign); - - if (!PyArg_ParseTuple(args, "O!O!s#|OOsI", - &POW_X509_Type, &signcert, - &POW_Asymmetric_Type, &signkey, - &buf, &len, - &x509_iterable, - &crl_iterable, - &oid, - &flags)) - goto error; - - assert_no_unhandled_openssl_errors(); - - if ((bio = BIO_new_mem_buf(buf, len)) == NULL) - lose_no_memory(); - - assert_no_unhandled_openssl_errors(); - - if (!cms_object_sign_helper(self, bio, signcert, signkey, - x509_iterable, crl_iterable, oid, flags)) - lose_openssl_error("Couldn't sign CMS object"); - - assert_no_unhandled_openssl_errors(); - - ok = 1; - - error: - BIO_free(bio); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static BIO * -cms_object_verify_helper(cms_object *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"store", "certs", "flags", NULL}; - x509_store_object *store = NULL; - PyObject *certs_iterable = Py_None; - STACK_OF(X509) *certs_stack = NULL; - unsigned flags = 0, ok = 0; - BIO *bio = NULL; - - ENTERING(cms_object_verify_helper); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|OI", kwlist, - &POW_X509Store_Type, &store, &certs_iterable, &flags)) - goto error; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - assert_no_unhandled_openssl_errors(); - - flags &= (CMS_NOINTERN | CMS_NOCRL | CMS_NO_SIGNER_CERT_VERIFY | - CMS_NO_ATTR_VERIFY | CMS_NO_CONTENT_VERIFY); - - if (certs_iterable != Py_None && - (certs_stack = x509_helper_iterable_to_stack(certs_iterable)) == NULL) - goto error; - - assert_no_unhandled_openssl_errors(); - - if (CMS_verify(self->cms, certs_stack, store->store, NULL, bio, flags) <= 0) - lose_openssl_error("Couldn't verify CMS message"); - - assert_no_unhandled_openssl_errors(); - - ok = 1; - - error: /* fall through */ - sk_X509_free(certs_stack); - - if (ok) - return bio; - - BIO_free(bio); - return NULL; -} - -static char cms_object_verify__doc__[] = - "Verify this CMS message against a trusted certificate store.\n" - "\n" - "The \"store\" parameter is an X509Store object, the trusted certificate\n" - "store to use in verification.\n" - "\n" - "The optional \"certs\" parameter is a set of certificates to search\n" - "for the signer's certificate.\n" - "\n" - "The optional \"flags\" parameter is an integer of bit flags,\n" - "containing zero or more of the following:\n" - "\n" - " * CMS_NOINTERN\n" - " * CMS_NOCRL\n" - " * CMS_NO_SIGNER_CERT_VERIFY\n" - " * CMS_NO_ATTR_VERIFY\n" - " * CMS_NO_CONTENT_VERIFY\n" - ; - -static PyObject * -cms_object_verify(cms_object *self, PyObject *args, PyObject *kwds) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(cms_object_verify); - - if ((bio = cms_object_verify_helper(self, args, kwds)) != NULL) - result = BIO_to_PyString_helper(bio); - - BIO_free(bio); - return result; -} - -static char cms_object_eContentType__doc__[] = - "Return the eContentType OID of this CMS message.\n" - ; - -static PyObject * -cms_object_eContentType(cms_object *self) -{ - const ASN1_OBJECT *oid = NULL; - PyObject *result = NULL; - - ENTERING(cms_object_eContentType); - - if ((oid = CMS_get0_eContentType(self->cms)) == NULL) - lose_openssl_error("Couldn't extract eContentType from CMS message"); - - assert_no_unhandled_openssl_errors(); - - result = ASN1_OBJECT_to_PyString(oid); - - error: - return result; -} - -static char cms_object_signingTime__doc__[] = - "Return the signingTime of this CMS message.\n" - ; - -static PyObject * -cms_object_signingTime(cms_object *self) -{ - PyObject *result = NULL; - STACK_OF(CMS_SignerInfo) *sis = NULL; - CMS_SignerInfo *si = NULL; - X509_ATTRIBUTE *xa = NULL; - ASN1_TYPE *so = NULL; - int i; - - ENTERING(cms_object_signingTime); - - if ((sis = CMS_get0_SignerInfos(self->cms)) == NULL) - lose_openssl_error("Couldn't extract signerInfos from CMS message[1]"); - - if (sk_CMS_SignerInfo_num(sis) != 1) - lose_openssl_error("Couldn't extract signerInfos from CMS message[2]"); - - si = sk_CMS_SignerInfo_value(sis, 0); - - if ((i = CMS_signed_get_attr_by_NID(si, NID_pkcs9_signingTime, -1)) < 0) - lose_openssl_error("Couldn't extract signerInfos from CMS message[3]"); - - if ((xa = CMS_signed_get_attr(si, i)) == NULL) - lose_openssl_error("Couldn't extract signerInfos from CMS message[4]"); - - if (xa->single) - lose("Couldn't extract signerInfos from CMS message[5]"); - - if (sk_ASN1_TYPE_num(xa->value.set) != 1) - lose("Couldn't extract signerInfos from CMS message[6]"); - - if ((so = sk_ASN1_TYPE_value(xa->value.set, 0)) == NULL) - lose("Couldn't extract signerInfos from CMS message[7]"); - - switch (so->type) { - case V_ASN1_UTCTIME: - result = ASN1_TIME_to_Python(so->value.utctime); - break; - case V_ASN1_GENERALIZEDTIME: - result = ASN1_TIME_to_Python(so->value.generalizedtime); - break; - default: - lose("Couldn't extract signerInfos from CMS message[8]"); - } - - error: - return result; -} - -static char cms_object_pprint__doc__[] = - "Return a pretty-printed representation of this CMS message.\n" - ; - -static PyObject * -cms_object_pprint(cms_object *self) -{ - BIO *bio = NULL; - PyObject *result = NULL; - - ENTERING(cms_object_pprint); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!CMS_ContentInfo_print_ctx(bio, self->cms, 0, NULL)) - lose_openssl_error("Unable to pretty-print CMS object"); - - result = BIO_to_PyString_helper(bio); - - error: - BIO_free(bio); - return result; -} - -static char cms_object_certs__doc__[] = - "Return any certificates embedded in this CMS message, as a\n" - "tuple of X509 objects. This tuple will be empty if the message\n" - "wrapper contains no certificates.\n" - ; - -static PyObject * -cms_object_certs(cms_object *self) -{ - STACK_OF(X509) *certs = NULL; - PyObject *result = NULL; - - ENTERING(cms_object_certs); - - if ((certs = CMS_get1_certs(self->cms)) != NULL) - result = stack_to_tuple_helper(CHECKED_PTR_OF(STACK_OF(X509), certs), - stack_to_tuple_helper_get_x509); - else if (!ERR_peek_error()) - result = Py_BuildValue("()"); - else - lose_openssl_error("Couldn't extract certs from CMS message"); - - error: /* fall through */ - sk_X509_pop_free(certs, X509_free); - return result; -} - -static char cms_object_crls__doc__[] = - "Return any CRLs embedded in this CMS message, as a tuple of\n" - "CRL objects. This tuple will be empty if the message contains no CRLs.\n" - ; - -static PyObject * -cms_object_crls(cms_object *self) -{ - STACK_OF(X509_CRL) *crls = NULL; - PyObject *result = NULL; - - ENTERING(cms_object_crls); - - if ((crls = CMS_get1_crls(self->cms)) != NULL) - result = stack_to_tuple_helper(CHECKED_PTR_OF(STACK_OF(X509_CRL), crls), - stack_to_tuple_helper_get_crl); - else if (!ERR_peek_error()) - result = Py_BuildValue("()"); - else - lose_openssl_error("Couldn't extract CRLs from CMS message"); - - error: /* fall through */ - sk_X509_CRL_pop_free(crls, X509_CRL_free); - return result; -} - -static struct PyMethodDef cms_object_methods[] = { - Define_Method(pemWrite, cms_object_pem_write, METH_NOARGS), - Define_Method(derWrite, cms_object_der_write, METH_NOARGS), - Define_Method(sign, cms_object_sign, METH_VARARGS), - Define_Method(verify, cms_object_verify, METH_KEYWORDS), - Define_Method(eContentType, cms_object_eContentType, METH_NOARGS), - Define_Method(signingTime, cms_object_signingTime, METH_NOARGS), - Define_Method(pprint, cms_object_pprint, METH_NOARGS), - Define_Method(certs, cms_object_certs, METH_NOARGS), - Define_Method(crls, cms_object_crls, METH_NOARGS), - Define_Class_Method(pemRead, cms_object_pem_read, METH_VARARGS), - Define_Class_Method(pemReadFile, cms_object_pem_read_file, METH_VARARGS), - Define_Class_Method(derRead, cms_object_der_read, METH_VARARGS), - Define_Class_Method(derReadFile, cms_object_der_read_file, METH_VARARGS), - {NULL} -}; - -static char POW_CMS_Type__doc__[] = - "Wrapper for OpenSSL's CMS class. At present this only handes signed\n" - "objects, as those are the only kind of CMS objects used in RPKI.\n" - ; - -static PyTypeObject POW_CMS_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.CMS", /* tp_name */ - sizeof(cms_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)cms_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_CMS_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - cms_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - cms_object_new, /* tp_new */ -}; - - - -/* - * Manifest object. - */ - -static PyObject * -manifest_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - manifest_object *self = NULL; - - ENTERING(manifest_object_new); - - if ((self = (manifest_object *) cms_object_new(type, args, kwds)) != NULL && - (self->manifest = Manifest_new()) != NULL) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static void -manifest_object_dealloc(manifest_object *self) -{ - ENTERING(manifest_object_dealloc); - Manifest_free(self->manifest); - cms_object_dealloc(&self->cms); -} - -static char manifest_object_verify__doc__[] = - "Verify this manifest. See the CMS class's .verify() method for details.\n" - ; - -static PyObject * -manifest_object_verify(manifest_object *self, PyObject *args, PyObject *kwds) -{ - BIO *bio = NULL; - int ok = 0; - - ENTERING(manifest_object_verify); - - if ((bio = cms_object_verify_helper(&self->cms, args, kwds)) == NULL) - goto error; - - if (!ASN1_item_d2i_bio(ASN1_ITEM_rptr(Manifest), bio, &self->manifest)) - lose_openssl_error("Couldn't decode manifest"); - - ok = 1; - - error: - BIO_free(bio); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static PyObject * -manifest_object_der_read_helper(PyTypeObject *type, BIO *bio) -{ - manifest_object *self; - - ENTERING(manifest_object_der_read_helper); - - if ((self = (manifest_object *) cms_object_der_read_helper(type, bio)) != NULL) - self->manifest = NULL; - - return (PyObject *) self; -} - -static char manifest_object_der_read__doc__[] = - "Read a DER-encoded manifest object from a string.\n" - ; - -static PyObject * -manifest_object_der_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(manifest_object_der_read); - return read_from_string_helper(manifest_object_der_read_helper, type, args); -} - -static char manifest_object_der_read_file__doc__[] = - "Read a DER-encoded manifest object from a file.\n" - ; - -static PyObject * -manifest_object_der_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(manifest_object_der_read_file); - return read_from_file_helper(manifest_object_der_read_helper, type, args); -} - -static PyObject * -manifest_object_pem_read_helper(PyTypeObject *type, BIO *bio) -{ - manifest_object *self; - - ENTERING(manifest_object_pem_read_helper); - - if ((self = (manifest_object *) cms_object_pem_read_helper(type, bio)) != NULL) - self->manifest = NULL; - - return (PyObject *) self; -} - -static char manifest_object_pem_read__doc__[] = - "Read a PEM-encoded manifest object from a string.\n" - ; - -static PyObject * -manifest_object_pem_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(manifest_object_pem_read); - return read_from_string_helper(manifest_object_pem_read_helper, type, args); -} - -static char manifest_object_pem_read_file__doc__[] = - "Read a PEM-encoded manifest object from a file.\n" - ; - -static PyObject * -manifest_object_pem_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(manifest_object_pem_read_file); - return read_from_file_helper(manifest_object_pem_read_helper, type, args); -} - -static char manifest_object_get_version__doc__[] = - "Return the version number of this manifest.\n" - ; - -static PyObject * -manifest_object_get_version(manifest_object *self) -{ - ENTERING(manifest_object_get_version); - - if (self->manifest == NULL) - lose_not_verified("Can't report version of unverified manifest"); - - if (self->manifest->version) - return Py_BuildValue("N", ASN1_INTEGER_to_PyLong(self->manifest->version)); - else - return PyInt_FromLong(0); - - error: - return NULL; -} - -static char manifest_object_set_version__doc__[] = - "Set the version number of this manifest.\n" - "\n" - "The \"version\" parameter should be a non-negative integer.\n" - "\n" - "As of this writing, zero is both the default and the only defined version.\n" - "Attempting to set any version number other than zero will fail, as we\n" - "don't understand how to write other versions, by definition.\n" - ; - -static PyObject * -manifest_object_set_version(manifest_object *self, PyObject *args) -{ - int version = 0; - - ENTERING(manifest_object_set_version); - - if (!PyArg_ParseTuple(args, "|i", &version)) - goto error; - - if (version != 0) - lose("RFC 6486 only defines RPKI manifest version zero"); - - if (self->manifest == NULL) - lose_not_verified("Can't set version of unverified manifest"); - - ASN1_INTEGER_free(self->manifest->version); - self->manifest->version = NULL; - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char manifest_object_get_manifest_number__doc__[] = - "Return the manifestNumber of this manifest.\n" - ; - -static PyObject * -manifest_object_get_manifest_number(manifest_object *self) -{ - ENTERING(manifest_object_get_manifest_number); - - if (self->manifest == NULL) - lose_not_verified("Can't get manifestNumber of unverified manifest"); - - return Py_BuildValue("N", ASN1_INTEGER_to_PyLong(self->manifest->manifestNumber)); - - error: - return NULL; -} - -static char manifest_object_set_manifest_number__doc__[] = - "Set the manifestNumber of this manifest.\n" - "\n" - "The \"manifestNumber\" parameter should be a non-negative integer.\n" - ; - -static PyObject * -manifest_object_set_manifest_number(manifest_object *self, PyObject *args) -{ - PyObject *manifestNumber = NULL; - PyObject *zero = NULL; - int ok = 0; - - ENTERING(manifest_object_set_manifest_number); - - if (!PyArg_ParseTuple(args, "O", &manifestNumber)) - goto error; - - if ((zero = PyInt_FromLong(0)) == NULL) - goto error; - - switch (PyObject_RichCompareBool(manifestNumber, zero, Py_GE)) { - case -1: - goto error; - case 0: - lose("Negative manifest number is not allowed"); - } - - if (self->manifest == NULL) - lose_not_verified("Can't set manifestNumber of unverified manifest"); - - ASN1_INTEGER_free(self->manifest->manifestNumber); - - if ((self->manifest->manifestNumber = PyLong_to_ASN1_INTEGER(manifestNumber)) == NULL) - goto error; - - ok = 1; - - error: - Py_XDECREF(zero); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char manifest_object_set_this_update__doc__[] = - "Set this manifest's \"thisUpdate\" value.\n" - "\n" - "The \"time\" parameter should be a datetime object.\n" - ; - -static PyObject * -manifest_object_set_this_update (manifest_object *self, PyObject *args) -{ - ASN1_TIME *t = NULL; - PyObject *o = NULL; - - ENTERING(manifest_object_set_this_update); - - if (!PyArg_ParseTuple(args, "O", &o)) - goto error; - - if (self->manifest == NULL) - lose_not_verified("Can't set thisUpdate value of unverified manifest"); - - if ((t = Python_to_ASN1_TIME(o, 0)) == NULL) - lose("Couldn't convert thisUpdate string"); - - ASN1_TIME_free(self->manifest->thisUpdate); - self->manifest->thisUpdate = t; - Py_RETURN_NONE; - - error: - ASN1_TIME_free(t); - return NULL; -} - -static char manifest_object_get_this_update__doc__[] = - "Return this manifest's \"thisUpdate\" value as a datetime.\n" - ; - -static PyObject * -manifest_object_get_this_update (manifest_object *self) -{ - ENTERING(manifest_object_get_this_update); - - if (self->manifest == NULL) - lose_not_verified("Can't get thisUpdate value of unverified manifest"); - - return ASN1_TIME_to_Python(self->manifest->thisUpdate); - - error: - return NULL; -} - -static char manifest_object_set_next_update__doc__[] = - "Set this manifest's \"nextUpdate\" value.\n" - "\n" - "The \"time\" parameter should be a datetime object.\n" - ; - -static PyObject * -manifest_object_set_next_update (manifest_object *self, PyObject *args) -{ - ASN1_TIME *t = NULL; - PyObject *o = NULL; - - ENTERING(manifest_object_set_next_update); - - if (!PyArg_ParseTuple(args, "O", &o)) - goto error; - - if (self->manifest == NULL) - lose_not_verified("Can't set nextUpdate value of unverified manifest"); - - if ((t = Python_to_ASN1_TIME(o, 0)) == NULL) - lose("Couldn't parse nextUpdate string"); - - ASN1_TIME_free(self->manifest->nextUpdate); - self->manifest->nextUpdate = t; - Py_RETURN_NONE; - - error: - ASN1_TIME_free(t); - return NULL; -} - -static char manifest_object_get_next_update__doc__[] = - "Return this manifest's \"nextUpdate\" value as a datetime.\n" - ; - -static PyObject * -manifest_object_get_next_update (manifest_object *self) -{ - ENTERING(manifest_object_get_next_update); - - if (self->manifest == NULL) - lose_not_verified("Can't extract nextUpdate value of unverified manifest"); - - return ASN1_TIME_to_Python(self->manifest->nextUpdate); - - error: - return NULL; -} - -static char manifest_object_get_algorithm__doc__[] = - "Return this manifest's fileHashAlg OID.\n" - ; - -static PyObject * -manifest_object_get_algorithm(manifest_object *self) -{ - PyObject *result = NULL; - - ENTERING(manifest_object_get_algorithm); - - if (self->manifest == NULL) - lose_not_verified("Can't extract algorithm OID of unverified manifest"); - - result = ASN1_OBJECT_to_PyString(self->manifest->fileHashAlg); - - error: - return result; -} - -static char manifest_object_set_algorithm__doc__[] = - "Set this manifest's fileHashAlg OID.\n" - ; - -static PyObject * -manifest_object_set_algorithm(manifest_object *self, PyObject *args) -{ - ASN1_OBJECT *oid = NULL; - const char *s = NULL; - - ENTERING(manifest_object_set_algorithm); - - if (!PyArg_ParseTuple(args, "s", &s)) - goto error; - - if (self->manifest == NULL) - lose_not_verified("Can't set algorithm OID for unverified manifest"); - - if ((oid = OBJ_txt2obj(s, 1)) == NULL) - lose_no_memory(); - - ASN1_OBJECT_free(self->manifest->fileHashAlg); - self->manifest->fileHashAlg = oid; - Py_RETURN_NONE; - - error: - ASN1_OBJECT_free(oid); - return NULL; -} - -static char manifest_object_add_files__doc__[] = - "Add a collection of <filename, hash> pairs to this manifest.\n" - "\n" - "The \"iterable\" parameter should be an iterable object supplying\n" - "returning two-element sequences; the first element of each sequence\n" - "should be the filename (a text string), the second element should be the\n" - "hash (a binary string).\n" - ; - -static PyObject * -manifest_object_add_files(manifest_object *self, PyObject *args) -{ - PyObject *iterable = NULL; - PyObject *iterator = NULL; - PyObject *item = NULL; - PyObject *fast = NULL; - FileAndHash *fah = NULL; - char *file = NULL; - char *hash = NULL; - Py_ssize_t filelen, hashlen; - int ok = 0; - - ENTERING(manifest_object_add_files); - - if (self->manifest == NULL) - lose_not_verified("Can't add files to unverified manifest"); - - if (!PyArg_ParseTuple(args, "O", &iterable) || - (iterator = PyObject_GetIter(iterable)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - - if ((fast = PySequence_Fast(item, "FileAndHash entry must be a sequence")) == NULL) - goto error; - - if (PySequence_Fast_GET_SIZE(fast) != 2) - lose_type_error("FileAndHash entry must be two-element sequence"); - - if (PyString_AsStringAndSize(PySequence_Fast_GET_ITEM(fast, 0), &file, &filelen) < 0 || - PyString_AsStringAndSize(PySequence_Fast_GET_ITEM(fast, 1), &hash, &hashlen) < 0) - goto error; - - if ((fah = FileAndHash_new()) == NULL || - !ASN1_OCTET_STRING_set(fah->file, (unsigned char *) file, filelen) || - !ASN1_BIT_STRING_set(fah->hash, (unsigned char *) hash, hashlen) || - !sk_FileAndHash_push(self->manifest->fileList, fah)) - lose_no_memory(); - - fah->hash->flags &= ~7; - fah->hash->flags |= ASN1_STRING_FLAG_BITS_LEFT; - - fah = NULL; - Py_XDECREF(item); - Py_XDECREF(fast); - item = fast = NULL; - } - - ok = 1; - - error: - Py_XDECREF(iterator); - Py_XDECREF(item); - Py_XDECREF(fast); - FileAndHash_free(fah); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char manifest_object_get_files__doc__[] = - "Return a tuple of <filename, hash> pairs representing the contents of\n" - "this manifest.\n" - ; - -static PyObject * -manifest_object_get_files(manifest_object *self) -{ - PyObject *result = NULL; - PyObject *item = NULL; - int i; - - ENTERING(manifest_object_get_files); - - if (self->manifest == NULL) - lose_not_verified("Can't get files from unverified manifest"); - - if (self->manifest->fileList == NULL) - lose("Inexplicable NULL manifest fileList pointer"); - - if ((result = PyTuple_New(sk_FileAndHash_num(self->manifest->fileList))) == NULL) - goto error; - - for (i = 0; i < sk_FileAndHash_num(self->manifest->fileList); i++) { - FileAndHash *fah = sk_FileAndHash_value(self->manifest->fileList, i); - - item = Py_BuildValue("(s#s#)", - ASN1_STRING_data(fah->file), - (Py_ssize_t) ASN1_STRING_length(fah->file), - ASN1_STRING_data(fah->hash), - (Py_ssize_t) ASN1_STRING_length(fah->hash)); - if (item == NULL) - goto error; - - PyTuple_SET_ITEM(result, i, item); - item = NULL; - } - - return result; - - error: - Py_XDECREF(result); - Py_XDECREF(item); - return NULL; -} - -static char manifest_object_sign__doc__[] = - "Sign this manifest. See the CMS class's .sign() method for details.\n" - ; - -static PyObject * -manifest_object_sign(manifest_object *self, PyObject *args) -{ - asymmetric_object *signkey = NULL; - x509_object *signcert = NULL; - PyObject *x509_iterable = Py_None; - PyObject *crl_iterable = Py_None; - char *oid = NULL; - unsigned flags = 0; - BIO *bio = NULL; - int ok = 0; - - ENTERING(manifest_object_sign); - - if (!PyArg_ParseTuple(args, "O!O!|OOsI", - &POW_X509_Type, &signcert, - &POW_Asymmetric_Type, &signkey, - &x509_iterable, - &crl_iterable, - &oid, - &flags)) - goto error; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - assert_no_unhandled_openssl_errors(); - - if (!ASN1_item_i2d_bio(ASN1_ITEM_rptr(Manifest), bio, self->manifest)) - lose_openssl_error("Couldn't encode manifest"); - - assert_no_unhandled_openssl_errors(); - - if (!cms_object_sign_helper(&self->cms, bio, signcert, signkey, - x509_iterable, crl_iterable, oid, flags)) - lose_openssl_error("Couldn't sign manifest"); - - assert_no_unhandled_openssl_errors(); - - ok = 1; - - error: - BIO_free(bio); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static struct PyMethodDef manifest_object_methods[] = { - Define_Method(getVersion, manifest_object_get_version, METH_NOARGS), - Define_Method(setVersion, manifest_object_set_version, METH_VARARGS), - Define_Method(getManifestNumber, manifest_object_get_manifest_number, METH_NOARGS), - Define_Method(setManifestNumber, manifest_object_set_manifest_number, METH_VARARGS), - Define_Method(getThisUpdate, manifest_object_get_this_update, METH_NOARGS), - Define_Method(setThisUpdate, manifest_object_set_this_update, METH_VARARGS), - Define_Method(getNextUpdate, manifest_object_get_next_update, METH_NOARGS), - Define_Method(setNextUpdate, manifest_object_set_next_update, METH_VARARGS), - Define_Method(getAlgorithm, manifest_object_get_algorithm, METH_NOARGS), - Define_Method(setAlgorithm, manifest_object_set_algorithm, METH_VARARGS), - Define_Method(getFiles, manifest_object_get_files, METH_NOARGS), - Define_Method(addFiles, manifest_object_add_files, METH_VARARGS), - Define_Method(sign, manifest_object_sign, METH_VARARGS), - Define_Method(verify, manifest_object_verify, METH_KEYWORDS), - Define_Class_Method(pemRead, manifest_object_pem_read, METH_VARARGS), - Define_Class_Method(pemReadFile, manifest_object_pem_read_file, METH_VARARGS), - Define_Class_Method(derRead, manifest_object_der_read, METH_VARARGS), - Define_Class_Method(derReadFile, manifest_object_der_read_file, METH_VARARGS), - {NULL} -}; - -static char POW_Manifest_Type__doc__[] = - "This class provides access to RPKI manifest payload.\n" - "Most methods are inherited from or share code with the CMS class.\n" - ; - -static PyTypeObject POW_Manifest_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.Manifest", /* tp_name */ - sizeof(manifest_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)manifest_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_Manifest_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - manifest_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &POW_CMS_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - manifest_object_new, /* tp_new */ -}; - - - -/* - * ROA object. - */ - -static PyObject * -roa_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - roa_object *self = NULL; - - ENTERING(roa_object_new); - - if ((self = (roa_object *) cms_object_new(type, args, kwds)) != NULL && - (self->roa = ROA_new()) != NULL) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static void -roa_object_dealloc(roa_object *self) -{ - ENTERING(roa_object_dealloc); - ROA_free(self->roa); - cms_object_dealloc(&self->cms); -} - -static char roa_object_verify__doc__[] = - "Verify this ROA. See CMS.verify() for details.\n" - ; - -static PyObject * -roa_object_verify(roa_object *self, PyObject *args, PyObject *kwds) -{ - BIO *bio = NULL; - int ok = 0; - - ENTERING(roa_object_verify); - - if ((bio = cms_object_verify_helper(&self->cms, args, kwds)) == NULL) - goto error; - - if (!ASN1_item_d2i_bio(ASN1_ITEM_rptr(ROA), bio, &self->roa)) - lose_openssl_error("Couldn't decode ROA"); - - ok = 1; - - error: - BIO_free(bio); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static PyObject * -roa_object_pem_read_helper(PyTypeObject *type, BIO *bio) -{ - roa_object *self; - - ENTERING(roa_object_pem_read_helper); - - if ((self = (roa_object *) cms_object_pem_read_helper(type, bio)) != NULL) - self->roa = NULL; - - return (PyObject *) self; -} - -static PyObject * -roa_object_der_read_helper(PyTypeObject *type, BIO *bio) -{ - roa_object *self; - - ENTERING(roa_object_der_read_helper); - - if ((self = (roa_object *) cms_object_der_read_helper(type, bio)) != NULL) - self->roa = NULL; - - return (PyObject *) self; -} - -static char roa_object_pem_read__doc__[] = - "Read a PEM-encoded ROA object from a string.\n" - ; - -static PyObject * -roa_object_pem_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(roa_object_pem_read); - return read_from_string_helper(roa_object_pem_read_helper, type, args); -} - -static char roa_object_pem_read_file__doc__[] = - "Read a PEM-encoded ROA object from a file.\n" - ; - -static PyObject * -roa_object_pem_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(roa_object_pem_read_file); - return read_from_file_helper(roa_object_pem_read_helper, type, args); -} - -static char roa_object_der_read__doc__[] = - "Read a DER-encoded ROA object from a string.\n" - ; - -static PyObject * -roa_object_der_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(roa_object_der_read); - return read_from_string_helper(roa_object_der_read_helper, type, args); -} - -static char roa_object_der_read_file__doc__[] = - "Read a DER-encoded ROA object from a file.\n" - ; - -static PyObject * -roa_object_der_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(roa_object_der_read_file); - return read_from_file_helper(roa_object_der_read_helper, type, args); -} - -static char roa_object_get_version__doc__[] = - "Return the version number of this ROA.\n" - ; - -static PyObject * -roa_object_get_version(roa_object *self) -{ - ENTERING(roa_object_get_version); - - if (self->roa == NULL) - lose_not_verified("Can't get version of unverified ROA"); - - if (self->roa->version) - return Py_BuildValue("N", ASN1_INTEGER_to_PyLong(self->roa->version)); - else - return PyInt_FromLong(0); - - error: - return NULL; -} - -static char roa_object_set_version__doc__[] = - "Set the version number of this ROA.\n" - "\n" - "The \"version\" parameter should be a non-negative integer.\n" - "\n" - "As of this writing, zero is both the default and the only defined version.\n" - "Attempting to set any version number other than zero will fail, as we\n" - "don't understand how to write other versions, by definition.\n" - ; - -static PyObject * -roa_object_set_version(roa_object *self, PyObject *args) -{ - int version = 0; - - ENTERING(roa_object_set_version); - - if (self->roa == NULL) - lose_not_verified("Can't set version of unverified ROA"); - - if (!PyArg_ParseTuple(args, "|i", &version)) - goto error; - - if (version != 0) - lose("RFC 6482 only defines ROA version zero"); - - ASN1_INTEGER_free(self->roa->version); - self->roa->version = NULL; - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char roa_object_get_asid__doc__[] = - "Return the Autonomous System ID of this ROA.\n" - ; - -static PyObject * -roa_object_get_asid(roa_object *self) -{ - ENTERING(roa_object_get_asid); - - if (self->roa == NULL) - lose_not_verified("Can't get ASN of unverified ROA"); - - return Py_BuildValue("N", ASN1_INTEGER_to_PyLong(self->roa->asID)); - - error: - return NULL; -} - -static char roa_object_set_asid__doc__[] = - "Sets the Autonomous System ID of this ROA.\n" - "\n" - "The \"asID\" parameter should be a non-negative integer.\n" - ; - -static PyObject * -roa_object_set_asid(roa_object *self, PyObject *args) -{ - PyObject *asID = NULL; - PyObject *zero = NULL; - int ok = 0; - - ENTERING(roa_object_set_asid); - - if (self->roa == NULL) - lose_not_verified("Can't set ASN of unverified ROA"); - - if (!PyArg_ParseTuple(args, "O", &asID)) - goto error; - - if ((zero = PyInt_FromLong(0)) == NULL) - goto error; - - switch (PyObject_RichCompareBool(asID, zero, Py_GE)) { - case -1: - goto error; - case 0: - lose("Negative asID is not allowed"); - } - - ASN1_INTEGER_free(self->roa->asID); - - if ((self->roa->asID = PyLong_to_ASN1_INTEGER(asID)) == NULL) - goto error; - - ok = 1; - - error: - Py_XDECREF(zero); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char roa_object_get_prefixes__doc__[] = - "Return this ROA's prefix list. This is a two-element\n" - "tuple: the first element is the IPv4 prefix set, the second is the\n" - "IPv6 prefix set.\n" - "\n" - "Each prefix set is either None, if there are no prefixes for this IP\n" - "version, or a sequence of three-element tuple representing ROA prefix\n" - "entries.\n" - "\n" - "Each ROA prefix entry consists of the prefix itself (an IPAddress),\n" - "the prefix length (an integer), and the maxPrefixLen value, which is\n" - "either an integer or None depending on whether the maxPrefixLen value\n" - "is set for this prefix.\n" - ; - -static PyObject * -roa_object_get_prefixes(roa_object *self) -{ - PyObject *result = NULL; - PyObject *ipv4_result = NULL; - PyObject *ipv6_result = NULL; - PyObject *item = NULL; - ipaddress_object *addr = NULL; - int i, j; - - ENTERING(roa_object_get_prefixes); - - if (self->roa == NULL) - lose_not_verified("Can't get prefixes from unverified ROA"); - - for (i = 0; i < sk_ROAIPAddressFamily_num(self->roa->ipAddrBlocks); i++) { - ROAIPAddressFamily *fam = sk_ROAIPAddressFamily_value(self->roa->ipAddrBlocks, i); - const unsigned afi = (fam->addressFamily->data[0] << 8) | (fam->addressFamily->data[1]); - const ipaddress_version *ip_type = NULL; - PyObject **resultp = NULL; - - switch (afi) { - case IANA_AFI_IPV4: resultp = &ipv4_result; ip_type = &ipaddress_version_4; break; - case IANA_AFI_IPV6: resultp = &ipv6_result; ip_type = &ipaddress_version_6; break; - default: lose_type_error("Unknown AFI"); - } - - if (fam->addressFamily->length > 2) - lose_type_error("Unsupported SAFI"); - - if (*resultp != NULL) - lose_type_error("Duplicate ROAIPAddressFamily"); - - if ((*resultp = PyTuple_New(sk_ROAIPAddress_num(fam->addresses))) == NULL) - goto error; - - for (j = 0; j < sk_ROAIPAddress_num(fam->addresses); j++) { - ROAIPAddress *a = sk_ROAIPAddress_value(fam->addresses, j); - unsigned prefixlen = ((a->IPAddress)->length * 8 - ((a->IPAddress)->flags & 7)); - - if ((addr = (ipaddress_object *) POW_IPAddress_Type.tp_alloc(&POW_IPAddress_Type, 0)) == NULL) - goto error; - - addr->type = ip_type; - - memset(addr->address, 0, sizeof(addr->address)); - - if ((unsigned) a->IPAddress->length > addr->type->length) - lose("ROAIPAddress BIT STRING too long for AFI"); - - if (a->IPAddress->length > 0) { - memcpy(addr->address, a->IPAddress->data, a->IPAddress->length); - - if ((a->IPAddress->flags & 7) != 0) { - unsigned char mask = 0xFF >> (8 - (a->IPAddress->flags & 7)); - addr->address[a->IPAddress->length - 1] &= ~mask; - } - } - - if (a->maxLength == NULL) - item = Py_BuildValue("(NIO)", addr, prefixlen, Py_None); - else - item = Py_BuildValue("(NIl)", addr, prefixlen, ASN1_INTEGER_get(a->maxLength)); - - if (item == NULL) - goto error; - - PyTuple_SET_ITEM(*resultp, j, item); - item = NULL; - addr = NULL; - } - } - - result = Py_BuildValue("(OO)", - (ipv4_result == NULL ? Py_None : ipv4_result), - (ipv6_result == NULL ? Py_None : ipv6_result)); - - error: /* Fall through */ - Py_XDECREF(addr); - Py_XDECREF(item); - Py_XDECREF(ipv4_result); - Py_XDECREF(ipv6_result); - - return result; -} - -static char roa_object_set_prefixes__doc__[] = - "Set this ROA's prefix list.\n" - "\n" - "This method takes two arguments, \"ipv4\" and \"ipv6\". Each of these\n" - "is either None, if no prefixes should be set for this IP version, or\n" - "an iterable object returning ROA prefix entries in the same format as\n" - "returned by the .getPrefixes() method. The maxPrefixLen value may be\n" - "omitted (that is, the ROA prefix entry tuple may be of length two\n" - "rather than of length three); this will be taken as equivalent to\n" - "specifying a maxPrefixLen value of None.\n" - ; - -static PyObject * -roa_object_set_prefixes(roa_object *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"ipv4", "ipv6", NULL}; - STACK_OF(ROAIPAddressFamily) *prefixes = NULL; - ROAIPAddressFamily *fam = NULL; - ROAIPAddress *a = NULL; - PyObject *ipv4_arg = Py_None; - PyObject *ipv6_arg = Py_None; - PyObject *iterator = NULL; - PyObject *item = NULL; - PyObject *fast = NULL; - int ok = 0; - int v; - - ENTERING(roa_object_set_prefixes); - - if (self->roa == NULL) - lose_not_verified("Can't set prefixes of unverified ROA"); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &ipv4_arg, &ipv6_arg)) - goto error; - - if ((prefixes = sk_ROAIPAddressFamily_new_null()) == NULL) - lose_no_memory(); - - for (v = 0; v < (int) (sizeof(ipaddress_versions)/sizeof(*ipaddress_versions)); v++) { - const struct ipaddress_version *ip_type = ipaddress_versions[v]; - unsigned char afibuf[2]; - PyObject **argp; - - switch (ip_type->version) { - case 4: argp = &ipv4_arg; break; - case 6: argp = &ipv6_arg; break; - default: continue; - } - - if (*argp == Py_None) - continue; - - afibuf[0] = (ip_type->afi >> 8) & 0xFF; - afibuf[1] = (ip_type->afi ) & 0xFF; - - if ((iterator = PyObject_GetIter(*argp)) == NULL) - goto error; - - while ((item = PyIter_Next(iterator)) != NULL) { - unsigned prefixlen, maxprefixlen, bitlen, bytelen; - ipaddress_object *addr = NULL; - PyObject *maxlenobj = Py_None; - - if ((fast = PySequence_Fast(item, "ROA prefix must be a sequence")) == NULL) - goto error; - - switch (PySequence_Fast_GET_SIZE(fast)) { - case 3: - maxlenobj = PySequence_Fast_GET_ITEM(fast, 2); - /* Fall through */ - case 2: - if (!POW_IPAddress_Check(PySequence_Fast_GET_ITEM(fast, 0))) - lose_type_error("First element of ROA prefix must be an IPAddress object"); - addr = (ipaddress_object *) PySequence_Fast_GET_ITEM(fast, 0); - prefixlen = (unsigned) PyInt_AsLong(PySequence_Fast_GET_ITEM(fast, 1)); - if (PyErr_Occurred()) - goto error; - break; - default: - lose_type_error("ROA prefix must be a two- or three-element sequence"); - } - - if (maxlenobj == Py_None) { - maxprefixlen = prefixlen; - } else { - maxprefixlen = (unsigned) PyInt_AsLong(maxlenobj); - if (PyErr_Occurred()) - goto error; - } - - if (addr->type != ip_type) - lose_type_error("Bad ROA prefix"); - - if (prefixlen > addr->type->length * 8) - lose("Bad prefix length"); - - if (maxprefixlen > addr->type->length * 8 || maxprefixlen < prefixlen) - lose("Bad maxLength value"); - - bytelen = (prefixlen + 7) / 8; - bitlen = prefixlen % 8; - - if ((a = ROAIPAddress_new()) == NULL || - (a->IPAddress == NULL && (a->IPAddress = ASN1_BIT_STRING_new()) == NULL) || - !ASN1_BIT_STRING_set(a->IPAddress, addr->address, bytelen)) - lose_no_memory(); - - a->IPAddress->flags &= ~7; - a->IPAddress->flags |= ASN1_STRING_FLAG_BITS_LEFT; - if (bitlen > 0) { - a->IPAddress->data[bytelen - 1] &= ~(0xFF >> bitlen); - a->IPAddress->flags |= 8 - bitlen; - } - - if (prefixlen != maxprefixlen && - ((a->maxLength = ASN1_INTEGER_new()) == NULL || - !ASN1_INTEGER_set(a->maxLength, maxprefixlen))) - lose_no_memory(); - - if (fam == NULL && - ((fam = ROAIPAddressFamily_new()) == NULL || - !sk_ROAIPAddressFamily_push(prefixes, fam) || - !ASN1_OCTET_STRING_set(fam->addressFamily, afibuf, sizeof(afibuf)))) - lose_no_memory(); - - if (!sk_ROAIPAddress_push(fam->addresses, a)) - lose_no_memory(); - - a = NULL; - Py_XDECREF(item); - Py_XDECREF(fast); - item = fast = NULL; - } - - fam = NULL; - Py_XDECREF(iterator); - iterator = NULL; - } - - sk_ROAIPAddressFamily_pop_free(self->roa->ipAddrBlocks, ROAIPAddressFamily_free); - self->roa->ipAddrBlocks = prefixes; - prefixes = NULL; - - ok = 1; - - error: - sk_ROAIPAddressFamily_pop_free(prefixes, ROAIPAddressFamily_free); - ROAIPAddressFamily_free(fam); - ROAIPAddress_free(a); - Py_XDECREF(iterator); - Py_XDECREF(item); - Py_XDECREF(fast); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static char roa_object_sign__doc__[] = - "Sign this ROA. See CMS.sign() for details.\n" - ; - -static PyObject * -roa_object_sign(roa_object *self, PyObject *args) -{ - asymmetric_object *signkey = NULL; - x509_object *signcert = NULL; - PyObject *x509_iterable = Py_None; - PyObject *crl_iterable = Py_None; - char *oid = NULL; - unsigned flags = 0; - BIO *bio = NULL; - int ok = 0; - - ENTERING(roa_object_sign); - - if (!PyArg_ParseTuple(args, "O!O!|OOsI", - &POW_X509_Type, &signcert, - &POW_Asymmetric_Type, &signkey, - &x509_iterable, - &crl_iterable, - &oid, - &flags)) - goto error; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - assert_no_unhandled_openssl_errors(); - - if (!ASN1_item_i2d_bio(ASN1_ITEM_rptr(ROA), bio, self->roa)) - lose_openssl_error("Couldn't encode ROA"); - - assert_no_unhandled_openssl_errors(); - - if (!cms_object_sign_helper(&self->cms, bio, signcert, signkey, - x509_iterable, crl_iterable, oid, flags)) - lose_openssl_error("Couldn't sign ROA"); - - assert_no_unhandled_openssl_errors(); - - ok = 1; - - error: - BIO_free(bio); - - if (ok) - Py_RETURN_NONE; - else - return NULL; -} - -static struct PyMethodDef roa_object_methods[] = { - Define_Method(getVersion, roa_object_get_version, METH_NOARGS), - Define_Method(setVersion, roa_object_set_version, METH_VARARGS), - Define_Method(getASID, roa_object_get_asid, METH_NOARGS), - Define_Method(setASID, roa_object_set_asid, METH_VARARGS), - Define_Method(getPrefixes, roa_object_get_prefixes, METH_NOARGS), - Define_Method(setPrefixes, roa_object_set_prefixes, METH_KEYWORDS), - Define_Method(sign, roa_object_sign, METH_VARARGS), - Define_Method(verify, roa_object_verify, METH_KEYWORDS), - Define_Class_Method(pemRead, roa_object_pem_read, METH_VARARGS), - Define_Class_Method(pemReadFile, roa_object_pem_read_file, METH_VARARGS), - Define_Class_Method(derRead, roa_object_der_read, METH_VARARGS), - Define_Class_Method(derReadFile, roa_object_der_read_file, METH_VARARGS), - {NULL} -}; - -static char POW_ROA_Type__doc__[] = - "This class provides access to RPKI ROA payload.\n" - "Most methods are inherited from or share code with the CMS class.\n" - ; - -static PyTypeObject POW_ROA_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.ROA", /* tp_name */ - sizeof(roa_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)roa_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_ROA_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - roa_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &POW_CMS_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - roa_object_new, /* tp_new */ -}; - - - -/* - * PKCS10 object. - */ - -static PyObject * -pkcs10_object_new(PyTypeObject *type, GCC_UNUSED PyObject *args, GCC_UNUSED PyObject *kwds) -{ - pkcs10_object *self; - - ENTERING(pkcs10_object_new); - - if ((self = (pkcs10_object *) type->tp_alloc(type, 0)) != NULL && - (self->pkcs10 = X509_REQ_new()) != NULL && - (self->exts = sk_X509_EXTENSION_new_null()) != NULL) - return (PyObject *) self; - - Py_XDECREF(self); - return NULL; -} - -static void -pkcs10_object_dealloc(pkcs10_object *self) -{ - ENTERING(pkcs10_object_dealloc); - X509_REQ_free(self->pkcs10); - sk_X509_EXTENSION_pop_free(self->exts, X509_EXTENSION_free); - self->ob_type->tp_free((PyObject*) self); -} - -static PyObject * -pkcs10_object_pem_read_helper(PyTypeObject *type, BIO *bio) -{ - pkcs10_object *self = NULL; - - ENTERING(pkcs10_object_pem_read_helper); - - assert_no_unhandled_openssl_errors(); - - if ((self = (pkcs10_object *) pkcs10_object_new(type, NULL, NULL)) == NULL) - goto error; - - assert_no_unhandled_openssl_errors(); - - if (!PEM_read_bio_X509_REQ(bio, &self->pkcs10, NULL, NULL)) - lose_openssl_error("Couldn't load PEM encoded PKCS#10 request"); - - sk_X509_EXTENSION_pop_free(self->exts, X509_EXTENSION_free); - self->exts = X509_REQ_get_extensions(self->pkcs10); - - assert_no_unhandled_openssl_errors(); - - return (PyObject *) self; - - error: - - Py_XDECREF(self); - return NULL; -} - -static PyObject * -pkcs10_object_der_read_helper(PyTypeObject *type, BIO *bio) -{ - pkcs10_object *self = NULL; - - ENTERING(pkcs10_object_der_read_helper); - - assert_no_unhandled_openssl_errors(); - - if ((self = (pkcs10_object *) pkcs10_object_new(type, NULL, NULL)) == NULL) - goto error; - - assert_no_unhandled_openssl_errors(); - - if (!d2i_X509_REQ_bio(bio, &self->pkcs10)) - lose_openssl_error("Couldn't load DER encoded PKCS#10 request"); - - sk_X509_EXTENSION_pop_free(self->exts, X509_EXTENSION_free); - self->exts = X509_REQ_get_extensions(self->pkcs10); - - assert_no_unhandled_openssl_errors(); - - return (PyObject *) self; - - error: - Py_XDECREF(self); - return NULL; -} - -static char pkcs10_object_pem_read__doc__[] = - "Read a PEM-encoded PKCS#10 object from a string.\n" - ; - -static PyObject * -pkcs10_object_pem_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(pkcs10_object_pem_read); - return read_from_string_helper(pkcs10_object_pem_read_helper, type, args); -} - -static char pkcs10_object_pem_read_file__doc__[] = - "Read a PEM-encoded PKCS#10 object from a file.\n" - ; - -static PyObject * -pkcs10_object_pem_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(pkcs10_object_pem_read_file); - return read_from_file_helper(pkcs10_object_pem_read_helper, type, args); -} - -static char pkcs10_object_der_read__doc__[] = - "Read a DER-encoded PKCS#10 object from a string.\n" - ; - -static PyObject * -pkcs10_object_der_read(PyTypeObject *type, PyObject *args) -{ - ENTERING(pkcs10_object_der_read); - return read_from_string_helper(pkcs10_object_der_read_helper, type, args); -} - -static char pkcs10_object_der_read_file__doc__[] = - "Read a DER-encoded PKCS#10 object from a file.\n" - ; - -static PyObject * -pkcs10_object_der_read_file(PyTypeObject *type, PyObject *args) -{ - ENTERING(pkcs10_object_der_read_file); - return read_from_file_helper(pkcs10_object_der_read_helper, type, args); -} - -static char pkcs10_object_pem_write__doc__[] = - "Returns the PEM encoding of this PKCS#10 object.\n" - ; - -static PyObject * -pkcs10_object_pem_write(pkcs10_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(pkcs10_object_pem_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!PEM_write_bio_X509_REQ(bio, self->pkcs10)) - lose_openssl_error("Unable to write PKCS#10 request"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static char pkcs10_object_der_write__doc__[] = - "Return the DER encoding of this PKCS#10 object.\n" - ; - -static PyObject * -pkcs10_object_der_write(pkcs10_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(pkcs10_object_der_write); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!i2d_X509_REQ_bio(bio, self->pkcs10)) - lose_openssl_error("Unable to write PKCS#10 request"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static X509_EXTENSIONS ** -pkcs10_object_extension_helper(pkcs10_object *self) -{ - return &self->exts; -} - -static char pkcs10_object_get_public_key__doc__[] = - "Return the public key from this PKCS#10 request, as an Asymmetric\n" - "object.\n" - ; - -static PyObject * -pkcs10_object_get_public_key(pkcs10_object *self) -{ - PyTypeObject *type = &POW_Asymmetric_Type; - asymmetric_object *asym = NULL; - - ENTERING(pkcs10_object_get_public_key); - - if ((asym = (asymmetric_object *) type->tp_alloc(type, 0)) == NULL) - goto error; - - if ((asym->pkey = X509_REQ_get_pubkey(self->pkcs10)) == NULL) - lose_openssl_error("Couldn't extract public key from PKCS#10 request"); - - return (PyObject *) asym; - - error: - Py_XDECREF(asym); - return NULL; -} - -static char pkcs10_object_set_public_key__doc__[] = - "Set the public key for this PKCS#10 request.\n" - "\n" - "The \"key\" parameter should be an instance of the Asymmetric class,\n" - "containing a public key.\n" - ; - -static PyObject * -pkcs10_object_set_public_key(pkcs10_object *self, PyObject *args) -{ - asymmetric_object *asym; - - ENTERING(pkcs10_object_set_public_key); - - if (!PyArg_ParseTuple(args, "O!", &POW_Asymmetric_Type, &asym)) - goto error; - - if (!X509_REQ_set_pubkey(self->pkcs10, asym->pkey)) - lose_openssl_error("Couldn't set certificate's PKCS#10 request"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char pkcs10_object_sign__doc__[] = - "Sign a PKCS#10 request with a private key.\n" - "\n" - "The \"key\" parameter should be an instance of the Asymmetric class,\n" - "containing a private key.\n" - "\n" - "The optional \"digest\" parameter indicates which digest to compute and\n" - "sign, and should be one of the following:\n" - "\n" - "* MD5_DIGEST\n" - "* SHA_DIGEST\n" - "* SHA1_DIGEST\n" - "* SHA256_DIGEST\n" - "* SHA384_DIGEST\n" - "* SHA512_DIGEST\n" - "\n" - "The default digest algorithm is SHA-256.\n" - ; - -static PyObject * -pkcs10_object_sign(pkcs10_object *self, PyObject *args) -{ - asymmetric_object *asym; - int loc, digest_type = SHA256_DIGEST; - const EVP_MD *digest_method = NULL; - - ENTERING(pkcs10_object_sign); - - if (!PyArg_ParseTuple(args, "O!|i", &POW_Asymmetric_Type, &asym, &digest_type)) - goto error; - - if ((digest_method = evp_digest_factory(digest_type)) == NULL) - lose("Unsupported digest algorithm"); - - while ((loc = X509_REQ_get_attr_by_NID(self->pkcs10, NID_ext_req, -1)) >= 0) - X509_ATTRIBUTE_free(X509_REQ_delete_attr(self->pkcs10, loc)); - - if (sk_X509_EXTENSION_num(self->exts) > 0 && - !X509_REQ_add_extensions(self->pkcs10, self->exts)) - lose_openssl_error("Couldn't add extensions block to PKCS#10 request"); - - if (!X509_REQ_sign(self->pkcs10, asym->pkey, digest_method)) - lose_openssl_error("Couldn't sign PKCS#10 request"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char pkcs10_object_verify__doc__[] = - "Verify a PKCS#10 request.\n" - "\n" - "This calls OpenSSL's X509_REQ_verify() method to check the request's\n" - "self-signature.\n" - ; - -static PyObject * -pkcs10_object_verify(pkcs10_object *self) -{ - EVP_PKEY *pkey = NULL; - int status; - - ENTERING(pkcs10_object_verify); - - if ((pkey = X509_REQ_get_pubkey(self->pkcs10)) == NULL) - lose_openssl_error("Couldn't extract public key from PKCS#10 for verification"); - - if ((status = X509_REQ_verify(self->pkcs10, pkey)) < 0) - lose_openssl_error("Couldn't verify PKCS#10 signature"); - - EVP_PKEY_free(pkey); - return PyBool_FromLong(status); - - error: - EVP_PKEY_free(pkey); - return NULL; -} - -static char pkcs10_object_get_version__doc__[] = - "Return the version number of this PKCS#10 request.\n" - ; - -static PyObject * -pkcs10_object_get_version(pkcs10_object *self) -{ - ENTERING(pkcs10_object_get_version); - return Py_BuildValue("l", X509_REQ_get_version(self->pkcs10)); -} - -static char pkcs10_object_set_version__doc__[] = - "Set the version number of this PKCS#10 request.\n" - "\n" - "The \"version\" parameter should be an integer, but the only defined\n" - "value is zero, so this field is optional and defaults to zero.\n" -; - -static PyObject * -pkcs10_object_set_version(pkcs10_object *self, PyObject *args) -{ - long version = 0; - - ENTERING(pkcs10_object_set_version); - - if (!PyArg_ParseTuple(args, "|l", &version)) - goto error; - - if (version != 0) - lose("RFC 6487 6.1.1 forbids non-zero values for this field"); - - if (!X509_REQ_set_version(self->pkcs10, version)) - lose("Couldn't set certificate version"); - - Py_RETURN_NONE; - - error: - - return NULL; -} - -static char pkcs10_object_get_subject__doc__[] = - "Return this PKCS #10 request's subject name.\n" - "\n" - "See the X509.getIssuer() method for details of the return value and\n" - "use of the optional \"format\" parameter.\n" - ; - -static PyObject * -pkcs10_object_get_subject(pkcs10_object *self, PyObject *args) -{ - PyObject *result = NULL; - int format = OIDNAME_FORMAT; - - ENTERING(pkcs10_object_get_subject); - - if (!PyArg_ParseTuple(args, "|i", &format)) - goto error; - - result = x509_object_helper_get_name(X509_REQ_get_subject_name(self->pkcs10), - format); - - error: /* Fall through */ - return result; -} - -static char pkcs10_object_set_subject__doc__[] = - "Set this PKCS#10 request's subject name.\n" - "\n" - "The \"name\" parameter should be in the same format as the return\n" - "value from the \"getSubject\" method.\n" - ; - -static PyObject * -pkcs10_object_set_subject(pkcs10_object *self, PyObject *args) -{ - PyObject *name_sequence = NULL; - X509_NAME *name = NULL; - - ENTERING(pkcs10_object_set_subject); - - if (!PyArg_ParseTuple(args, "O", &name_sequence)) - goto error; - - if (!PySequence_Check(name_sequence)) - lose_type_error("Inapropriate type"); - - if ((name = x509_object_helper_set_name(name_sequence)) == NULL) - goto error; - - if (!X509_REQ_set_subject_name(self->pkcs10, name)) - lose("Unable to set subject name"); - - X509_NAME_free(name); - - Py_RETURN_NONE; - - error: - X509_NAME_free(name); - return NULL; -} - -static char pkcs10_object_get_key_usage__doc__[] = - "Return a FrozenSet of strings representing the KeyUsage settings for\n" - "this PKCS#10 request, or None if the request has no KeyUsage\n" - "extension. The bits have the same names as in RFC 5280.\n" - ; - -static PyObject * -pkcs10_object_get_key_usage(pkcs10_object *self) -{ - return extension_get_key_usage(pkcs10_object_extension_helper(self)); -} - -static char pkcs10_object_set_key_usage__doc__[] = - "Set the KeyUsage extension for this PKCS#10 request.\n" - "\n" - "Argument \"iterable\" should be an iterable object which returns zero or more\n" - "strings naming bits to be enabled. The bits have the same names as in RFC 5280.\n" - "\n" - "Optional argument \"critical\" is a boolean indicating whether the extension\n" - "should be marked as critical or not. RFC 5280 4.2.1.3 says this extension SHOULD\n" - "be marked as critical when used, so the default is True.\n" - ; - -static PyObject * -pkcs10_object_set_key_usage(pkcs10_object *self, PyObject *args) -{ - return extension_set_key_usage(pkcs10_object_extension_helper(self), args); -} - -static char pkcs10_object_get_eku__doc__[] = - "Return a FrozenSet of object identifiers representing the\n" - "ExtendedKeyUsage settings for this PKCS #10 requst, or None if\n" - "the request has no ExtendedKeyUsage extension.\n" - ; - -static PyObject * -pkcs10_object_get_eku(pkcs10_object *self) -{ - return extension_get_eku(pkcs10_object_extension_helper(self)); -} - -static char pkcs10_object_set_eku__doc__[] = - "Set the ExtendedKeyUsage extension for this PKCS #10 request.\n" - "\n" - "Argument \"iterable\" should be an iterable object which returns one or more\n" - "object identifiers.\n" - "\n" - "Optional argument \"critical\" is a boolean indicating whether the extension\n" - "should be marked as critical or not. RFC 6487 4.8.5 says this extension\n" - "MUST NOT be marked as non-critical when used, so the default is False.\n" - ; - -static PyObject * -pkcs10_object_set_eku(pkcs10_object *self, PyObject *args) -{ - return extension_set_eku(pkcs10_object_extension_helper(self), args); -} - -static char pkcs10_object_get_basic_constraints__doc__[] = - "Return BasicConstraints value for this PKCS#10 request.\n" - "\n" - "If this request has no BasicConstraints extension, this method returns\n" - "None.\n" - "\n" - "Otherwise, this method returns a two-element tuple. The first element\n" - "of the tuple is a boolean representing the extension's cA value; the\n" - "second element of the tuple is either an integer representing\n" - "thepathLenConstraint value or None if there is no pathLenConstraint.\n" - ; - -static PyObject * -pkcs10_object_get_basic_constraints(pkcs10_object *self) -{ - return extension_get_basic_constraints(pkcs10_object_extension_helper(self)); -} - -static char pkcs10_object_set_basic_constraints__doc__[] = - "Set BasicConstraints value for this PKCS#10 request.\n" - "\n" - "First argument \"ca\" is a boolean indicating whether the request\n" - "is for a CA certificate or not.\n" - "\n" - "Optional second argument \"pathLenConstraint\" is None or a\n" - "non-negative integer specifying the pathLenConstraint value for this\n" - "certificate. Per RFC 5280, this value may only be set to an integer\n" - "value for CA certificates." - "\n" - "Optional third argument \"critical\" specifies whether the extension\n" - "should be marked as critical. RFC 5280 4.2.1.9 requires that CA\n" - "certificates mark this extension as critical, so the default is True.\n" - ; - -static PyObject * -pkcs10_object_set_basic_constraints(pkcs10_object *self, PyObject *args) -{ - return extension_set_basic_constraints(pkcs10_object_extension_helper(self), args); -} - -static char pkcs10_object_get_sia__doc__[] = - "Return the SIA values for this PKCS#10 request.\n" - "\n" - "If this request has no SIA extension, this method returns None.\n" - "\n" - "Otherwise, this returns a tuple containing three sequences:\n" - "caRepository URIs, rpkiManifest URIs, and signedObject URIs.\n" - "Any other accessMethods are ignored, as are any non-URI\n" - "accessLocations.\n" - ; - -static PyObject * -pkcs10_object_get_sia(pkcs10_object *self) -{ - return extension_get_sia(pkcs10_object_extension_helper(self)); -} - -static char pkcs10_object_set_sia__doc__[] = - "Set SIA values for this PKCS#10 request.\n" - "\n" - "Takes three arguments: caRepository, rpkiManifest, and signedObject.\n" - "\n" - "Each of these should be an iterable which returns URIs.\n" - "\n" - "None is acceptable as an alternate way of specifying an empty\n" - "collection of URIs for a particular argument.\n" - ; - -static PyObject * -pkcs10_object_set_sia(pkcs10_object *self, PyObject *args, PyObject *kwds) -{ - return extension_set_sia(pkcs10_object_extension_helper(self), args, kwds); -} - -static char pkcs10_object_get_signature_algorithm__doc__[] = - "Return this PKCS #10 reqeuest's signature algorithm OID.\n" - ; - -static PyObject * -pkcs10_object_get_signature_algorithm(pkcs10_object *self) -{ - ASN1_OBJECT *oid = NULL; - - ENTERING(pkcs10_object_get_signature_algorithm); - - X509_ALGOR_get0(&oid, NULL, NULL, self->pkcs10->sig_alg); - - return ASN1_OBJECT_to_PyString(oid); -} - -static char pkcs10_object_get_extension_oids__doc__[] = - "Return the set of extension OIDs used in this request. This is mostly\n" - "useful for enforcing restrictions on what extensions are allowed to be\n" - "present, eg, to conform with the RPKI profile.\n" - ; - -static PyObject * -pkcs10_object_get_extension_oids(pkcs10_object *self) -{ - PyObject *result = NULL; - PyObject *oid = NULL; - int i; - - ENTERING(pkcs10_object_get_extension_oids); - - if ((result = PyFrozenSet_New(NULL)) == NULL) - goto error; - - for (i = 0; i < sk_X509_EXTENSION_num(self->exts); i++) { - X509_EXTENSION *ext = sk_X509_EXTENSION_value(self->exts, i); - if ((oid = ASN1_OBJECT_to_PyString(ext->object)) == NULL || - PySet_Add(result, oid) < 0) - goto error; - Py_XDECREF(oid); - oid = NULL; - } - - return result; - - error: - Py_XDECREF(result); - Py_XDECREF(oid); - return NULL; -} - -/* - * May want EKU handlers eventually, skip for now. - */ - -static char pkcs10_object_pprint__doc__[] = - "Return a pretty-printed rendition of this PKCS#10 request.\n" - ; - -static PyObject * -pkcs10_object_pprint(pkcs10_object *self) -{ - PyObject *result = NULL; - BIO *bio = NULL; - - ENTERING(pkcs10_object_pprint); - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - lose_no_memory(); - - if (!X509_REQ_print(bio, self->pkcs10)) - lose_openssl_error("Unable to pretty-print PKCS#10 request"); - - result = BIO_to_PyString_helper(bio); - - error: /* Fall through */ - BIO_free(bio); - return result; -} - -static struct PyMethodDef pkcs10_object_methods[] = { - Define_Method(pemWrite, pkcs10_object_pem_write, METH_NOARGS), - Define_Method(derWrite, pkcs10_object_der_write, METH_NOARGS), - Define_Method(sign, pkcs10_object_sign, METH_VARARGS), - Define_Method(verify, pkcs10_object_verify, METH_NOARGS), - Define_Method(getPublicKey, pkcs10_object_get_public_key, METH_NOARGS), - Define_Method(setPublicKey, pkcs10_object_set_public_key, METH_VARARGS), - Define_Method(getVersion, pkcs10_object_get_version, METH_NOARGS), - Define_Method(setVersion, pkcs10_object_set_version, METH_VARARGS), - Define_Method(getSubject, pkcs10_object_get_subject, METH_VARARGS), - Define_Method(setSubject, pkcs10_object_set_subject, METH_VARARGS), - Define_Method(pprint, pkcs10_object_pprint, METH_NOARGS), - Define_Method(getKeyUsage, pkcs10_object_get_key_usage, METH_NOARGS), - Define_Method(setKeyUsage, pkcs10_object_set_key_usage, METH_VARARGS), - Define_Method(getEKU, pkcs10_object_get_eku, METH_NOARGS), - Define_Method(setEKU, pkcs10_object_set_eku, METH_VARARGS), - Define_Method(getBasicConstraints, pkcs10_object_get_basic_constraints, METH_NOARGS), - Define_Method(setBasicConstraints, pkcs10_object_set_basic_constraints, METH_VARARGS), - Define_Method(getSIA, pkcs10_object_get_sia, METH_NOARGS), - Define_Method(setSIA, pkcs10_object_set_sia, METH_KEYWORDS), - Define_Method(getSignatureAlgorithm, pkcs10_object_get_signature_algorithm, METH_NOARGS), - Define_Method(getExtensionOIDs, pkcs10_object_get_extension_oids, METH_NOARGS), - Define_Class_Method(pemRead, pkcs10_object_pem_read, METH_VARARGS), - Define_Class_Method(pemReadFile, pkcs10_object_pem_read_file, METH_VARARGS), - Define_Class_Method(derRead, pkcs10_object_der_read, METH_VARARGS), - Define_Class_Method(derReadFile, pkcs10_object_der_read_file, METH_VARARGS), - {NULL} -}; - -static char POW_PKCS10_Type__doc__[] = - "This class represents a PKCS#10 request.\n" - "\n" - LAME_DISCLAIMER_IN_ALL_CLASS_DOCUMENTATION - ; - -static PyTypeObject POW_PKCS10_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - "rpki.POW.PKCS10", /* tp_name */ - sizeof(pkcs10_object), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)pkcs10_object_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - POW_PKCS10_Type__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - pkcs10_object_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - pkcs10_object_new, /* tp_new */ -}; - - - -/* - * Module functions. - */ - -static char pow_module_add_object__doc__[] = - "Add new a new object identifier to OpenSSL's internal database.\n" - "\n" - "The \"oid\" should be an ASN.1 object identifer, represented as a string\n" - "in dotted-decimal format.\n" - "\n" - "The \"shortName\" parameter should be the OpenSSL \"short name\" to use.\n" - "\n" - "The \"longName\" parameter should be the OpenSSL \"long name\" to use.\n" - ; - -static PyObject * -pow_module_add_object(GCC_UNUSED PyObject *self, PyObject *args) -{ - char *oid = NULL, *sn = NULL, *ln = NULL; - - ENTERING(pow_module_add_object); - - if (!PyArg_ParseTuple(args, "sss", &oid, &sn, &ln)) - goto error; - - if (!OBJ_create(oid, sn, ln)) - lose_openssl_error("Unable to add object"); - - Py_RETURN_NONE; - - error: - - return NULL; -} - -static char pow_module_get_error__doc__[] = - "Pop one error off OpenSSL's global error stack and returns it as a string.\n" - "\n" - "Returns None if the error stack is empty.\n" - ; - -static PyObject * -pow_module_get_error(GCC_UNUSED PyObject *self) -{ - unsigned long error = ERR_get_error(); - char buf[256]; - - ENTERING(pow_module_get_error); - - if (!error) - Py_RETURN_NONE; - - ERR_error_string_n(error, buf, sizeof(buf)); - return Py_BuildValue("s", buf); -} - -static char pow_module_clear_error__doc__[] = - "Remove all errors from OpenSSL's global error stack.\n" - ; - -static PyObject * -pow_module_clear_error(GCC_UNUSED PyObject *self) -{ - ENTERING(pow_module_clear_error); - ERR_clear_error(); - Py_RETURN_NONE; -} - -static char pow_module_seed__doc__[] = - "Add data to OpenSSL's pseudo-random number generator state.\n" - "\n" - "The \"data\" parameter is the seed to add. Entropy of the data is\n" - "assumed to be equal to the length of the data.\n" - ; - -static PyObject * -pow_module_seed(GCC_UNUSED PyObject *self, PyObject *args) -{ - char *data = NULL; - Py_ssize_t datalen = 0; - - ENTERING(pow_module_seed); - - if (!PyArg_ParseTuple(args, "s#", &data, &datalen)) - goto error; - - RAND_seed(data, datalen); - - Py_RETURN_NONE; - - error: - - return NULL; -} - -static char pow_module_add__doc__[] = - "Add data to OpenSSL's pseudo-random number generator state.\n" - "\n" - "The \"data\" parameter is the data to add.\n" - "\n" - "The \"entropy\" parameter should be an estimate of the number of\n" - "random bytes in the data parameter.\n" - ; - -static PyObject * -pow_module_add(GCC_UNUSED PyObject *self, PyObject *args) -{ - char *data = NULL; - Py_ssize_t datalen = 0; - double entropy = 0; - - ENTERING(pow_module_add); - - if (!PyArg_ParseTuple(args, "s#d", &data, &datalen, &entropy)) - goto error; - - RAND_add(data, datalen, entropy); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char pow_module_write_random_file__doc__[] = - "Write the current state of OpenSSL's pseduo-random number generator to\n" - "a file.\n" - "\n" - "The \"filename\" parameter is the name of the file to write.\n" - ; - -static PyObject * -pow_module_write_random_file(GCC_UNUSED PyObject *self, PyObject *args) -{ - char *filename = NULL; - - ENTERING(pow_module_write_random_file); - - if (!PyArg_ParseTuple(args, "s", &filename)) - goto error; - - if (RAND_write_file(filename) == -1) - lose("Couldn't write random file"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char pow_module_read_random_file__doc__[] = - "Restore the state of OpenSSLs pseudo-random number generator from\n" - "data previously saved to a file.\n" - "\n" - "The \"filename\" parameter is the name of the file to read.\n" - ; - -static PyObject * -pow_module_read_random_file(GCC_UNUSED PyObject *self, PyObject *args) -{ - char *file = NULL; - int len = -1; - - ENTERING(pow_module_read_random_file); - - if (!PyArg_ParseTuple(args, "s|i", &file, &len)) - goto error; - - if (!RAND_load_file(file, len)) - lose("Couldn't load random file"); - - Py_RETURN_NONE; - - error: - return NULL; -} - -static char pow_module_custom_datetime__doc__[] = - "Set constructor callback for customized datetime class.\n" - ; - -static PyObject * -pow_module_custom_datetime(GCC_UNUSED PyObject *self, PyObject *args) -{ - PyObject *cb = NULL; - - ENTERING(pow_module_custom_datetime); - - if (!PyArg_ParseTuple(args, "O", &cb)) - goto error; - - Py_XINCREF(cb); - Py_XDECREF(custom_datetime); - custom_datetime = cb; - - Py_RETURN_NONE; - - error: - return NULL; -} - - -static struct PyMethodDef pow_module_methods[] = { - Define_Method(getError, pow_module_get_error, METH_NOARGS), - Define_Method(clearError, pow_module_clear_error, METH_NOARGS), - Define_Method(seed, pow_module_seed, METH_VARARGS), - Define_Method(add, pow_module_add, METH_VARARGS), - Define_Method(readRandomFile, pow_module_read_random_file, METH_VARARGS), - Define_Method(writeRandomFile, pow_module_write_random_file, METH_VARARGS), - Define_Method(addObject, pow_module_add_object, METH_VARARGS), - Define_Method(customDatetime, pow_module_custom_datetime, METH_VARARGS), - {NULL} -}; - - - -/* - * Module initialization. - */ - -void -init_POW(void) -{ - PyObject *m = Py_InitModule3("_POW", pow_module_methods, pow_module__doc__); - int OpenSSL_ok = 1; - - /* - * Python encourages us to use these functions instead of the ones - * in libc, and OpenSSL allows us to do this. The result seems to - * work, and, in theory, gives Python's memory allocator a better - * idea of how much memory we're really using. Not sure why it - * cares, but let's try to be nice about it. - * - * Note that this must be done BEFORE anything in OpenSSL uses - * dynamic memory, and that this will probably fail in horrible ways - * without the build-time code (-Bsymbolic, etc) which isolates our - * copy of the OpenSSL code from any system shared libraries. - * Enough other things already fail in horrible ways without that - * isolation that adding one more doesn't make much difference, but - * if you tinker with the build script and start seeing nasty - * memory-related issues, this might be the cause. - */ - CRYPTO_set_mem_functions(PyMem_Malloc, PyMem_Realloc, PyMem_Free); - - /* - * Import the DateTime API - */ - - PyDateTime_IMPORT; - -#define Define_Class(__type__) \ - do { \ - char *__name__ = strrchr(__type__.tp_name, '.'); \ - if (PyType_Ready(&__type__) == 0 && __name__ != NULL) { \ - Py_INCREF(&__type__); \ - PyModule_AddObject(m, __name__+1, (PyObject *) &__type__); \ - } \ - } while (0) - - Define_Class(POW_X509_Type); - Define_Class(POW_X509Store_Type); - Define_Class(POW_X509StoreCTX_Type); - Define_Class(POW_CRL_Type); - Define_Class(POW_Asymmetric_Type); - Define_Class(POW_AsymmetricParams_Type); - Define_Class(POW_Digest_Type); - Define_Class(POW_CMS_Type); - Define_Class(POW_IPAddress_Type); - Define_Class(POW_Manifest_Type); - Define_Class(POW_ROA_Type); - Define_Class(POW_PKCS10_Type); - -#undef Define_Class - -#define Define_Exception(__name__, __parent__) \ - PyModule_AddObject(m, #__name__, ((__name__##Object) \ - = PyErr_NewException("rpki.POW." #__name__, __parent__, NULL))) - - Define_Exception(Error, NULL); - Define_Exception(OpenSSLError, ErrorObject); - Define_Exception(POWError, ErrorObject); - Define_Exception(NotVerifiedError, ErrorObject); - -#undef Define_Exception - -#define Define_Integer_Constant(__name__) \ - PyModule_AddIntConstant(m, #__name__, __name__) - - /* Object format types */ - Define_Integer_Constant(LONGNAME_FORMAT); - Define_Integer_Constant(SHORTNAME_FORMAT); - Define_Integer_Constant(OIDNAME_FORMAT); - - /* Message digests */ - Define_Integer_Constant(MD5_DIGEST); - Define_Integer_Constant(SHA_DIGEST); - Define_Integer_Constant(SHA1_DIGEST); - Define_Integer_Constant(SHA256_DIGEST); - Define_Integer_Constant(SHA384_DIGEST); - Define_Integer_Constant(SHA512_DIGEST); - - /* CMS flags */ - Define_Integer_Constant(CMS_NOCERTS); - Define_Integer_Constant(CMS_NOATTR); - Define_Integer_Constant(CMS_NOINTERN); - Define_Integer_Constant(CMS_NOCRL); - Define_Integer_Constant(CMS_NO_SIGNER_CERT_VERIFY); - Define_Integer_Constant(CMS_NO_ATTR_VERIFY); - Define_Integer_Constant(CMS_NO_CONTENT_VERIFY); - - /* X509 validation flags */ - Define_Integer_Constant(X509_V_FLAG_CB_ISSUER_CHECK); - Define_Integer_Constant(X509_V_FLAG_USE_CHECK_TIME); - Define_Integer_Constant(X509_V_FLAG_CRL_CHECK); - Define_Integer_Constant(X509_V_FLAG_CRL_CHECK_ALL); - Define_Integer_Constant(X509_V_FLAG_IGNORE_CRITICAL); - Define_Integer_Constant(X509_V_FLAG_X509_STRICT); - Define_Integer_Constant(X509_V_FLAG_ALLOW_PROXY_CERTS); - Define_Integer_Constant(X509_V_FLAG_POLICY_CHECK); - Define_Integer_Constant(X509_V_FLAG_EXPLICIT_POLICY); - Define_Integer_Constant(X509_V_FLAG_INHIBIT_ANY); - Define_Integer_Constant(X509_V_FLAG_INHIBIT_MAP); - Define_Integer_Constant(X509_V_FLAG_NOTIFY_POLICY); - Define_Integer_Constant(X509_V_FLAG_CHECK_SS_SIGNATURE); - - /* X509 validation error codes */ - Define_Integer_Constant(X509_V_OK); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_GET_CRL); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY); - Define_Integer_Constant(X509_V_ERR_CERT_SIGNATURE_FAILURE); - Define_Integer_Constant(X509_V_ERR_CRL_SIGNATURE_FAILURE); - Define_Integer_Constant(X509_V_ERR_CERT_NOT_YET_VALID); - Define_Integer_Constant(X509_V_ERR_CERT_HAS_EXPIRED); - Define_Integer_Constant(X509_V_ERR_CRL_NOT_YET_VALID); - Define_Integer_Constant(X509_V_ERR_CRL_HAS_EXPIRED); - Define_Integer_Constant(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD); - Define_Integer_Constant(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD); - Define_Integer_Constant(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); - Define_Integer_Constant(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); - Define_Integer_Constant(X509_V_ERR_OUT_OF_MEM); - Define_Integer_Constant(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); - Define_Integer_Constant(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); - Define_Integer_Constant(X509_V_ERR_CERT_CHAIN_TOO_LONG); - Define_Integer_Constant(X509_V_ERR_CERT_REVOKED); - Define_Integer_Constant(X509_V_ERR_INVALID_CA); - Define_Integer_Constant(X509_V_ERR_PATH_LENGTH_EXCEEDED); - Define_Integer_Constant(X509_V_ERR_INVALID_PURPOSE); - Define_Integer_Constant(X509_V_ERR_CERT_UNTRUSTED); - Define_Integer_Constant(X509_V_ERR_CERT_REJECTED); - Define_Integer_Constant(X509_V_ERR_SUBJECT_ISSUER_MISMATCH); - Define_Integer_Constant(X509_V_ERR_AKID_SKID_MISMATCH); - Define_Integer_Constant(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH); - Define_Integer_Constant(X509_V_ERR_KEYUSAGE_NO_CERTSIGN); - Define_Integer_Constant(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER); - Define_Integer_Constant(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION); - Define_Integer_Constant(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN); - Define_Integer_Constant(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); - Define_Integer_Constant(X509_V_ERR_INVALID_NON_CA); - Define_Integer_Constant(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED); - Define_Integer_Constant(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); - Define_Integer_Constant(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); - Define_Integer_Constant(X509_V_ERR_INVALID_EXTENSION); - Define_Integer_Constant(X509_V_ERR_INVALID_POLICY_EXTENSION); - Define_Integer_Constant(X509_V_ERR_NO_EXPLICIT_POLICY); - Define_Integer_Constant(X509_V_ERR_UNNESTED_RESOURCE); - Define_Integer_Constant(X509_V_ERR_APPLICATION_VERIFICATION); - - /* AsymmetricParam EC curve codes */ - Define_Integer_Constant(EC_P256_CURVE); - -#undef Define_Integer_Constant - - /* - * Initialise library. - * - * We shouldn't need any of the SSL code or error strings anymore. - * - * If we cared deeply about avoiding references to symmetric cipher - * algorithms and digest algorithms we're not using, we could - * replace the call to OpenSSL_add_all_algorithms() with calls to - * add just the specific algorithms we use rather than all of them. - * For now, don't worry about it. - */ - - OpenSSL_add_all_algorithms(); - ERR_load_crypto_strings(); - - OpenSSL_ok &= create_missing_nids(); - - x509_store_ctx_ex_data_idx = X509_STORE_CTX_get_ex_new_index(0, "x590_store_ctx_object for verify callback", - NULL, NULL, NULL); - - if (PyErr_Occurred() || !OpenSSL_ok) - Py_FatalError("Can't initialize module POW"); -} - -/* - * Local Variables: - * indent-tabs-mode: nil - * End: - */ |