diff options
Diffstat (limited to 'rpkid/ext/POW.c')
-rw-r--r-- | rpkid/ext/POW.c | 623 |
1 files changed, 452 insertions, 171 deletions
diff --git a/rpkid/ext/POW.c b/rpkid/ext/POW.c index b728e7f1..b0a4dea6 100644 --- a/rpkid/ext/POW.c +++ b/rpkid/ext/POW.c @@ -81,13 +81,6 @@ /* $Id: rcynic.c 4613 2012-07-30 23:24:15Z sra $ */ -#warning Consider making ROA and Manifest C/API-level subclasses of CMS -/* - * This would be a major change to the Python code but really seems - * like the right thing at the API level, the current two-level API is - * a horrible kludge forced on us by circumstance. - */ - /* * Disable compilation of X509 certificate signature and verification * API. We don't currently need this for RPKI but I'm not quite ready @@ -220,7 +213,8 @@ static const struct { static PyObject *ErrorObject, *OpenSSLErrorObject, - *POWErrorObject; + *POWErrorObject, + *NotVerifiedErrorObject; /* * Declarations of type objects (definitions come later). @@ -283,12 +277,12 @@ typedef struct { } cms_object; typedef struct { - PyObject_HEAD + cms_object cms; /* Subclass of CMS */ ROA *roa; } roa_object; typedef struct { - PyObject_HEAD + cms_object cms; /* Subclass of CMS */ Manifest *manifest; } manifest_object; @@ -315,17 +309,8 @@ typedef struct { #endif /* - * Error handling macros. These macros make two assumptions: - * - * 1) All the macros assume that there's a cleanup label named - * "error" which these macros can use as a goto target. - * - * 2) assert_no_unhandled_openssl_errors() assumes that the return - * value is stored in a PyObject* variable named "result". - * - * These are icky assumptions, but they make it easier to provide - * uniform error handling and make the code easier to read, not to - * mention making it easier to track down obscure OpenSSL errors. + * 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_) \ @@ -352,15 +337,16 @@ typedef struct { 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()) { \ - if (result) { \ - Py_XDECREF(result); \ - result = NULL; \ - } \ + if (ERR_peek_error()) \ lose_openssl_error(assert_helper(__LINE__)); \ - } \ } while (0) static char * @@ -1312,7 +1298,7 @@ x509_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static PyObject * -x509_object_pem_read_helper(PyTypeObject *type, BIO *in) +x509_object_pem_read_helper(PyTypeObject *type, BIO *bio) { x509_object *self = NULL; @@ -1321,7 +1307,7 @@ x509_object_pem_read_helper(PyTypeObject *type, BIO *in) X509_free(self->x509); - if ((self->x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) + if ((self->x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) lose_openssl_error("Couldn't load PEM encoded certificate"); return (PyObject *) self; @@ -3536,7 +3522,7 @@ crl_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static PyObject * -crl_object_pem_read_helper(PyTypeObject *type, BIO *in) +crl_object_pem_read_helper(PyTypeObject *type, BIO *bio) { crl_object *self; @@ -3545,7 +3531,7 @@ crl_object_pem_read_helper(PyTypeObject *type, BIO *in) X509_CRL_free(self->crl); - if ((self->crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL)) == NULL) + if ((self->crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) == NULL) lose_openssl_error("Couldn't PEM encoded load CRL"); return (PyObject *) self; @@ -4412,14 +4398,14 @@ asymmetric_object_init(asymmetric_object *self, PyObject *args, PyObject *kwds) } static PyObject * -asymmetric_object_pem_read_private_helper(PyTypeObject *type, BIO *in, char *pass) +asymmetric_object_pem_read_private_helper(PyTypeObject *type, BIO *bio, char *pass) { asymmetric_object *self = NULL; if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL) goto error; - if ((self->pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, pass)) == NULL) + if ((self->pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, pass)) == NULL) lose_openssl_error("Couldn't load private key"); return (PyObject *) self; @@ -4529,14 +4515,14 @@ asymmetric_object_der_read_private_file(PyTypeObject *type, PyObject *args) } static PyObject * -asymmetric_object_pem_read_public_helper(PyTypeObject *type, BIO *in) +asymmetric_object_pem_read_public_helper(PyTypeObject *type, BIO *bio) { asymmetric_object *self = NULL; if ((self = (asymmetric_object *) asymmetric_object_new(&POW_Asymmetric_Type, NULL, NULL)) == NULL) goto error; - if ((self->pkey = PEM_read_bio_PUBKEY(in, NULL, NULL, NULL)) == NULL) + if ((self->pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) lose_openssl_error("Couldn't load public key"); return (PyObject *) self; @@ -5110,14 +5096,14 @@ cms_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static PyObject * -cms_object_pem_read_helper(PyTypeObject *type, BIO *in) +cms_object_pem_read_helper(PyTypeObject *type, BIO *bio) { cms_object *self; - if ((self = (cms_object *) cms_object_new(type, NULL, NULL)) == NULL) + if ((self = (cms_object *) type->tp_new(type, NULL, NULL)) == NULL) goto error; - if ((self->cms = PEM_read_bio_CMS(in, NULL, NULL, NULL)) == NULL) + if ((self->cms = PEM_read_bio_CMS(bio, NULL, NULL, NULL)) == NULL) lose_openssl_error("Couldn't load PEM encoded CMS message"); return (PyObject *) self; @@ -5132,7 +5118,7 @@ cms_object_der_read_helper(PyTypeObject *type, BIO *bio) { cms_object *self; - if ((self = (cms_object *) cms_object_new(type, NULL, NULL)) == NULL) + if ((self = (cms_object *) type->tp_new(type, NULL, NULL)) == NULL) goto error; if ((self->cms = CMS_ContentInfo_new()) == NULL) @@ -5234,60 +5220,22 @@ cms_object_der_write(cms_object *self) return result; } -static char cms_object_sign__doc__[] = - "This method signs a 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 a sequence of X509 objects\n" - "to be included in the signed message.\n" - "\n" - "The optional \"crls\" parameter should be a sequence of 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) +static int +cms_object_sign_helper(cms_object *self, + BIO *bio, + x509_object *signcert, + asymmetric_object *signkey, + PyObject *x509_sequence, + PyObject *crl_sequence, + char *oid, + unsigned flags) { - asymmetric_object *signkey = NULL; - x509_object *signcert = NULL; crl_object *crlobj = NULL; - PyObject *x509_sequence = Py_None; - PyObject *crl_sequence = Py_None; - PyObject *result = NULL; STACK_OF(X509) *x509_stack = NULL; - char *buf = NULL, *oid = NULL; - int i, n, len; - unsigned flags = 0; - BIO *bio = NULL; + int i, n, ok = 0; CMS_ContentInfo *cms = NULL; ASN1_OBJECT *econtent_type = NULL; - if (!PyArg_ParseTuple(args, "O!O!s#|OOsI", - &POW_X509_Type, &signcert, - &POW_Asymmetric_Type, &signkey, - &buf, &len, - &x509_sequence, - &crl_sequence, - &oid, - &flags)) - goto error; - assert_no_unhandled_openssl_errors(); flags &= CMS_NOCERTS | CMS_NOATTR; @@ -5298,11 +5246,6 @@ cms_object_sign(cms_object *self, PyObject *args) assert_no_unhandled_openssl_errors(); - if ((bio = BIO_new_mem_buf(buf, len)) == NULL) - lose_no_memory(); - - assert_no_unhandled_openssl_errors(); - if (oid && (econtent_type = OBJ_txt2obj(oid, 1)) == NULL) lose_openssl_error("Couldn't parse OID"); @@ -5360,50 +5303,99 @@ cms_object_sign(cms_object *self, PyObject *args) self->cms = cms; cms = NULL; - result = Py_BuildValue(""); + ok = 1; error: /* fall through */ - - assert_no_unhandled_openssl_errors(); - CMS_ContentInfo_free(cms); - BIO_free(bio); sk_X509_free(x509_stack); ASN1_OBJECT_free(econtent_type); Py_XDECREF(crlobj); - return result; + return ok; } -static char cms_object_verify__doc__[] = - "This method verifies a message against a trusted store.\n" +static char cms_object_sign__doc__[] = + "This method signs a message with a private key.\n" "\n" - "The \"store\" parameter is an X509Store object, the trusted certificate\n" - "store to use in verification.\n" + "The \"signcert\" parameter should be the certificate against which the\n" + "message will eventually be verified, an X509 object.\n" "\n" - "The optional \"certs\" parameter is a set of certificates to search\n" - "for the signer's certificate.\n" + "The \"key\" parameter should be the private key with which to sign the\n" + "message, an Asymmetric object.\n" "\n" - "The optional \"flags\" parameter is an integer of bit flags,\n" - "containing zero or more of the following:\n" + "The \"data\" parameter should be the message to be signed, a string.\n" "\n" - " * CMS_NOINTERN\n" - " * CMS_NOCRL\n" - " * CMS_NO_SIGNER_CERT_VERIFY\n" - " * CMS_NO_ATTR_VERIFY\n" - " * CMS_NO_CONTENT_VERIFY\n" + "The optional \"certs\" parameter should be a sequence of X509 objects\n" + "to be included in the signed message.\n" + "\n" + "The optional \"crls\" parameter should be a sequence of 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_verify(cms_object *self, PyObject *args) +cms_object_sign(cms_object *self, PyObject *args) +{ + asymmetric_object *signkey = NULL; + x509_object *signcert = NULL; + PyObject *x509_sequence = Py_None; + PyObject *crl_sequence = Py_None; + char *buf = NULL, *oid = NULL; + int len; + unsigned flags = 0; + BIO *bio = NULL; + int ok = 0; + + if (!PyArg_ParseTuple(args, "O!O!s#|OOsI", + &POW_X509_Type, &signcert, + &POW_Asymmetric_Type, &signkey, + &buf, &len, + &x509_sequence, + &crl_sequence, + &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(); + + ok = cms_object_sign_helper(self, bio, signcert, signkey, + x509_sequence, crl_sequence, oid, flags); + + error: + BIO_free(bio); + + if (ok) + Py_RETURN_NONE; + else + return NULL; +} + +#warning Might want to convert flag bits here to keyword argument booleans + +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 *result = NULL, *certs_sequence = Py_None; + PyObject *certs_sequence = Py_None; STACK_OF(X509) *certs_stack = NULL; - unsigned flags = 0; + unsigned flags = 0, ok = 0; BIO *bio = NULL; - if (!PyArg_ParseTuple(args, "O!|OI", &POW_X509Store_Type, &store, &certs_sequence, &flags)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|OI", kwlist, &POW_X509Store_Type, &store, &certs_sequence, &flags)) goto error; if ((bio = BIO_new(BIO_s_mem())) == NULL) @@ -5425,15 +5417,47 @@ cms_object_verify(cms_object *self, PyObject *args) assert_no_unhandled_openssl_errors(); - result = BIO_to_PyString_helper(bio); + ok = 1; error: /* fall through */ + sk_X509_free(certs_stack); - assert_no_unhandled_openssl_errors(); + if (ok) + return bio; - sk_X509_free(certs_stack); BIO_free(bio); + return NULL; +} +static char cms_object_verify__doc__[] = + "This method verifies a message against a trusted 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; + + if ((bio = cms_object_verify_helper(self, args, kwds)) != NULL) + result = BIO_to_PyString_helper(bio); + + BIO_free(bio); return result; } @@ -5454,12 +5478,11 @@ cms_object_eContentType(cms_object *self) if (OBJ_obj2txt(buf, sizeof(buf), oid, 1) <= 0) lose("Couldn't translate OID"); + assert_no_unhandled_openssl_errors(); + result = Py_BuildValue("s", buf); error: - - assert_no_unhandled_openssl_errors(); - return result; } @@ -5512,9 +5535,6 @@ cms_object_signingTime(cms_object *self) } error: - - assert_no_unhandled_openssl_errors(); - return result; } @@ -5536,8 +5556,7 @@ cms_object_pprint(cms_object *self) result = BIO_to_PyString_helper(bio); - error: /* fall through */ - assert_no_unhandled_openssl_errors(); + error: BIO_free(bio); return result; } @@ -5621,7 +5640,7 @@ 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_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), @@ -5700,7 +5719,7 @@ manifest_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { manifest_object *self = NULL; - if ((self = (manifest_object *) type->tp_alloc(type, 0)) != NULL && + if ((self = (manifest_object *) cms_object_new(type, args, kwds)) != NULL && (self->manifest = Manifest_new()) != NULL) return (PyObject *) self; @@ -5708,22 +5727,45 @@ manifest_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } +static char manifest_object_verify__doc__[] = + "Needs doc.\n" + ; + static PyObject * -manifest_object_der_read_helper(PyTypeObject *type, BIO *bio) +manifest_object_verify(manifest_object *self, PyObject *args, PyObject *kwds) { - manifest_object *self; + BIO *bio = NULL; + int ok = 0; - if ((self = (manifest_object *) manifest_object_new(type, NULL, NULL)) == NULL) + if ((bio = cms_object_verify_helper(&self->cms, args, kwds)) == NULL) goto error; + Manifest_free(self->manifest); + self->manifest = NULL; + if (!ASN1_item_d2i_bio(ASN1_ITEM_rptr(Manifest), bio, &self->manifest)) - lose_openssl_error("Couldn't load DER encoded manifest"); + lose_openssl_error("Couldn't decode manifest"); - return (PyObject *) self; + ok = 1; error: - Py_XDECREF(self); - return NULL; + 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; + + 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__[] = @@ -5736,6 +5778,47 @@ manifest_object_der_read(PyTypeObject *type, PyObject *args) return read_from_string_helper(manifest_object_der_read_helper, type, args); } +static PyObject * +manifest_object_pem_read_helper(PyTypeObject *type, BIO *bio) +{ + manifest_object *self; + + 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__[] = + "Class method to read a PEM-encoded manifest object from a string.\n" + ; + +static PyObject * +manifest_object_pem_read(PyTypeObject *type, PyObject *args) +{ + return read_from_string_helper(manifest_object_pem_read_helper, type, args); +} + +static char manifest_object_pem_read_file__doc__[] = + "Class method to read a PEM-encoded manifest object from a file.\n" + ; + +static PyObject * +manifest_object_pem_read_file(PyTypeObject *type, PyObject *args) +{ + return read_from_file_helper(manifest_object_pem_read_helper, type, args); +} + +static char manifest_object_der_read_file__doc__[] = + "Class method to read a DER-encoded manifest object from a file.\n" + ; + +static PyObject * +manifest_object_der_read_file(PyTypeObject *type, PyObject *args) +{ + return read_from_file_helper(manifest_object_der_read_helper, type, args); +} + static char manifest_object_get_version__doc__[] = "This method returns the version number of this manifest.\n" ; @@ -5743,10 +5826,16 @@ static char manifest_object_get_version__doc__[] = static PyObject * manifest_object_get_version(manifest_object *self) { + 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__[] = @@ -5770,6 +5859,9 @@ manifest_object_set_version(manifest_object *self, PyObject *args) 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; @@ -5786,7 +5878,13 @@ static char manifest_object_get_manifest_number__doc__[] = static PyObject * manifest_object_get_manifest_number(manifest_object *self) { + 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__[] = @@ -5815,6 +5913,9 @@ manifest_object_set_manifest_number(manifest_object *self, PyObject *args) 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) @@ -5847,6 +5948,9 @@ manifest_object_set_this_update (manifest_object *self, PyObject *args) if (!PyArg_ParseTuple(args, "s", &s)) goto error; + if (self->manifest == NULL) + lose_not_verified("Can't set thisUpdate value of unverified manifest"); + if ((t = Python_to_ASN1_TIME(s, 0)) == NULL) lose("Couldn't convert thisUpdate string"); @@ -5867,7 +5971,13 @@ static char manifest_object_get_this_update__doc__[] = static PyObject * manifest_object_get_this_update (manifest_object *self) { + 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__[] = @@ -5886,6 +5996,9 @@ manifest_object_set_next_update (manifest_object *self, PyObject *args) if (!PyArg_ParseTuple(args, "s", &s)) goto error; + if (self->manifest == NULL) + lose_not_verified("Can't set nextUpdate value of unverified manifest"); + if ((t = Python_to_ASN1_TIME(s, 0)) == NULL) lose("Couldn't parse nextUpdate string"); @@ -5906,7 +6019,13 @@ static char manifest_object_get_next_update__doc__[] = static PyObject * manifest_object_get_next_update (manifest_object *self) { + 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__[] = @@ -5919,6 +6038,9 @@ manifest_object_get_algorithm(manifest_object *self) PyObject *result = NULL; char oid[512]; + if (self->manifest == NULL) + lose_not_verified("Can't extract algorithm OID of unverified manifest"); + if (OBJ_obj2txt(oid, sizeof(oid), self->manifest->fileHashAlg, 1) <= 0) lose("Couldn't translate OID"); @@ -5941,6 +6063,9 @@ manifest_object_set_algorithm(manifest_object *self, PyObject *args) 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(); @@ -5973,6 +6098,9 @@ manifest_object_add_files(manifest_object *self, PyObject *args) char *hash = NULL; int filelen, hashlen, ok = 0; + 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; @@ -6018,6 +6146,9 @@ manifest_object_get_files(manifest_object *self) PyObject *item = NULL; int i; + 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"); @@ -6044,27 +6175,54 @@ manifest_object_get_files(manifest_object *self) return NULL; } -static char manifest_object_der_write__doc__[] = - "This method returns a DER encoded manifest as a string.\n" +static char manifest_object_sign__doc__[] = + "Needs doc.\n" ; + static PyObject * -manifest_object_der_write(manifest_object *self) +manifest_object_sign(manifest_object *self, PyObject *args) { - PyObject *result = NULL; + asymmetric_object *signkey = NULL; + x509_object *signcert = NULL; + PyObject *x509_sequence = Py_None; + PyObject *crl_sequence = Py_None; + char *buf = NULL, *oid = NULL; + int len; + unsigned flags = 0; BIO *bio = NULL; + int ok = 0; + + if (!PyArg_ParseTuple(args, "O!O!s#|OOsI", + &POW_X509_Type, &signcert, + &POW_Asymmetric_Type, &signkey, + &buf, &len, + &x509_sequence, + &crl_sequence, + &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("Unable to write manifest"); - result = BIO_to_PyString_helper(bio); + assert_no_unhandled_openssl_errors(); - error: /* Fall through */ + ok = cms_object_sign_helper(&self->cms, bio, signcert, signkey, + x509_sequence, crl_sequence, oid, flags); + + error: BIO_free(bio); - return result; + + if (ok) + Py_RETURN_NONE; + else + return NULL; } static struct PyMethodDef manifest_object_methods[] = { @@ -6080,8 +6238,12 @@ static struct PyMethodDef manifest_object_methods[] = { 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(derWrite, manifest_object_der_write, METH_NOARGS), - Define_Class_Method(derRead, manifest_object_der_read, 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} }; @@ -6089,7 +6251,7 @@ static void manifest_object_dealloc(manifest_object *self) { Manifest_free(self->manifest); - self->ob_type->tp_free((PyObject*) self); + self->cms.ob_type->tp_free((PyObject*) self); } static char POW_Manifest_Type__doc__[] = @@ -6128,7 +6290,7 @@ static PyTypeObject POW_Manifest_Type = { manifest_object_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ - 0, /* tp_base */ + &POW_CMS_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ @@ -6149,7 +6311,7 @@ roa_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { roa_object *self = NULL; - if ((self = (roa_object *) type->tp_alloc(type, 0)) != NULL && + if ((self = (roa_object *) cms_object_new(type, args, kwds)) != NULL && (self->roa = ROA_new()) != NULL) return (PyObject *) self; @@ -6157,26 +6319,80 @@ roa_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } +static char roa_object_verify__doc__[] = + "Needs doc. For now, see CMS.verify().\n" + ; + static PyObject * -roa_object_der_read_helper(PyTypeObject *type, BIO *bio) +roa_object_verify(roa_object *self, PyObject *args, PyObject *kwds) { - roa_object *self; + BIO *bio = NULL; + int ok = 0; - if ((self = (roa_object *) roa_object_new(type, NULL, NULL)) == NULL) + if ((bio = cms_object_verify_helper(&self->cms, args, kwds)) == NULL) goto error; + ROA_free(self->roa); + self->roa = NULL; + if (!ASN1_item_d2i_bio(ASN1_ITEM_rptr(ROA), bio, &self->roa)) - lose_openssl_error("Couldn't load DER encoded roa"); + lose_openssl_error("Couldn't decode ROA"); - return (PyObject *) self; + ok = 1; error: - Py_XDECREF(self); - return NULL; + 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; + + 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; + + 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__[] = + "Class method to read a PEM-encoded ROA object from a string.\n" + ; + +static PyObject * +roa_object_pem_read(PyTypeObject *type, PyObject *args) +{ + return read_from_string_helper(roa_object_pem_read_helper, type, args); +} + +static char roa_object_pem_read_file__doc__[] = + "Class method to read a PEM-encoded ROA object from a file.\n" + ; + +static PyObject * +roa_object_pem_read_file(PyTypeObject *type, PyObject *args) +{ + return read_from_file_helper(roa_object_pem_read_helper, type, args); } static char roa_object_der_read__doc__[] = - "Class method to read a DER-encoded ROA from a string.\n" + "Class method to read a DER-encoded ROA object from a string.\n" ; static PyObject * @@ -6185,6 +6401,16 @@ roa_object_der_read(PyTypeObject *type, PyObject *args) return read_from_string_helper(roa_object_der_read_helper, type, args); } +static char roa_object_der_read_file__doc__[] = + "Class method to read a DER-encoded ROA object from a file.\n" + ; + +static PyObject * +roa_object_der_read_file(PyTypeObject *type, PyObject *args) +{ + return read_from_file_helper(roa_object_der_read_helper, type, args); +} + static char roa_object_get_version__doc__[] = "This method returns the version number of this ROA.\n" ; @@ -6192,10 +6418,16 @@ static char roa_object_get_version__doc__[] = static PyObject * roa_object_get_version(roa_object *self) { + 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__[] = @@ -6213,6 +6445,9 @@ roa_object_set_version(roa_object *self, PyObject *args) { int version = 0; + if (self->roa == NULL) + lose_not_verified("Can't set version of unverified ROA"); + if (!PyArg_ParseTuple(args, "|i", &version)) goto error; @@ -6235,7 +6470,13 @@ static char roa_object_get_asid__doc__[] = static PyObject * roa_object_get_asid(roa_object *self) { + 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__[] = @@ -6251,6 +6492,9 @@ roa_object_set_asid(roa_object *self, PyObject *args) PyObject *zero = NULL; int ok = 0; + if (self->roa == NULL) + lose_not_verified("Can't set ASN of unverified ROA"); + if (!PyArg_ParseTuple(args, "O", &asID)) goto error; @@ -6298,6 +6542,9 @@ roa_object_get_prefixes(roa_object *self) ipaddress_object *addr = NULL; int i, j; + 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]); @@ -6398,6 +6645,9 @@ roa_object_set_prefixes(roa_object *self, PyObject *args, PyObject *kwds) PyObject *item = NULL; int afi, ok = 0; + 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; @@ -6511,27 +6761,53 @@ roa_object_set_prefixes(roa_object *self, PyObject *args, PyObject *kwds) return NULL; } -static char roa_object_der_write__doc__[] = - "This method returns a DER encoded roa as a string.\n" +static char roa_object_sign__doc__[] = + "Needs doc. For now, see CMS.sign.\n" ; static PyObject * -roa_object_der_write(roa_object *self) +roa_object_sign(roa_object *self, PyObject *args) { - PyObject *result = NULL; + asymmetric_object *signkey = NULL; + x509_object *signcert = NULL; + PyObject *x509_sequence = Py_None; + PyObject *crl_sequence = Py_None; + char *buf = NULL, *oid = NULL; + int len; + unsigned flags = 0; BIO *bio = NULL; + int ok = 0; + + if (!PyArg_ParseTuple(args, "O!O!s#|OOsI", + &POW_X509_Type, &signcert, + &POW_Asymmetric_Type, &signkey, + &buf, &len, + &x509_sequence, + &crl_sequence, + &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("Unable to write ROA"); - result = BIO_to_PyString_helper(bio); + assert_no_unhandled_openssl_errors(); - error: /* Fall through */ + ok = cms_object_sign_helper(&self->cms, bio, signcert, signkey, + x509_sequence, crl_sequence, oid, flags); + + error: BIO_free(bio); - return result; + + if (ok) + Py_RETURN_NONE; + else + return NULL; } static struct PyMethodDef roa_object_methods[] = { @@ -6541,8 +6817,12 @@ static struct PyMethodDef roa_object_methods[] = { 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(derWrite, roa_object_der_write, METH_NOARGS), - Define_Class_Method(derRead, roa_object_der_read, METH_VARARGS), + 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} }; @@ -6550,7 +6830,7 @@ static void roa_object_dealloc(roa_object *self) { ROA_free(self->roa); - self->ob_type->tp_free((PyObject*) self); + self->cms.ob_type->tp_free((PyObject*) self); } static char POW_ROA_Type__doc__[] = @@ -6589,7 +6869,7 @@ static PyTypeObject POW_ROA_Type = { roa_object_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ - 0, /* tp_base */ + &POW_CMS_Type, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ @@ -6620,7 +6900,7 @@ pkcs10_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } static PyObject * -pkcs10_object_pem_read_helper(PyTypeObject *type, BIO *in) +pkcs10_object_pem_read_helper(PyTypeObject *type, BIO *bio) { pkcs10_object *self = NULL; @@ -6632,7 +6912,7 @@ pkcs10_object_pem_read_helper(PyTypeObject *type, BIO *in) self->pkcs10 = NULL; self->exts = NULL; - if ((self->pkcs10 = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL)) == NULL) + if ((self->pkcs10 = PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL)) == NULL) lose_openssl_error("Couldn't load PEM encoded PKCS#10 request"); self->exts = X509_REQ_get_extensions(self->pkcs10); @@ -7672,9 +7952,10 @@ init_POW(void) PyModule_AddObject(m, #__name__, ((__name__##Object) \ = PyErr_NewException("POW." #__name__, __parent__, NULL))) - Define_Exception(Error, NULL); - Define_Exception(OpenSSLError, ErrorObject); - Define_Exception(POWError, ErrorObject); + Define_Exception(Error, NULL); + Define_Exception(OpenSSLError, ErrorObject); + Define_Exception(POWError, ErrorObject); + Define_Exception(NotVerifiedError, ErrorObject); #undef Define_Exception |