diff options
-rw-r--r-- | rpkid/ext/POW.c | 178 |
1 files changed, 71 insertions, 107 deletions
diff --git a/rpkid/ext/POW.c b/rpkid/ext/POW.c index 19f7cc7a..a749bf6e 100644 --- a/rpkid/ext/POW.c +++ b/rpkid/ext/POW.c @@ -82,6 +82,20 @@ /* $Id: rcynic.c 4613 2012-07-30 23:24:15Z sra $ */ #warning Still need PKCS10 type and methods +/* + * From rpki.x509.PKCS10, it looks like we need to: + * get/set basicConstraints, SIA, and keyUsage (check RFC) + * get/set version + * get/set subject name + * get/set subject public key / sign with private key + * + * The last two are integrated even POW.pkix, almost certainly they + * are in OpenSSL as well. See: X509_REQ_ in x509/x509.h, + * x509/x509_req.c, x509/x509rset.c, x509/x_all.c. + * + * Looks like Xt09_REQ_add_extensions() wants to add all extensions as + * a group. Yum. + */ #warning Consider making ROA and Manifest C/API-level subclasses of CMS /* @@ -90,52 +104,12 @@ * a horrible kludge forced on us by circumstance. */ -#warning May want to tighten up type checking using O-bang PyArg_ParseTuple format -/* - * Probably a good idea to let PyArg_ParseTuple do the type checking - * for us where it can. - */ - #warning Might want common worker code supporting extensions for X509, CRL, and PKCS10 classes /* * May not really be necessary, neither CRLs nor PKCS10 requests are * allowed very many extensions in the RPKI profile. */ -#warning Asymmetric class probably should be storing an EVP and using the EVP API for everything -/* - * EVP_PKEY == EVP public key. We already construct an EVP_PKEY - * almost every time we use the underlying RSA object that we store - * now, seems it would make more sense to store the EVP_PKEY. - * - * EVP_PKEY_new(), EVP_PKEY_free(), EVP_PKEY_assign_RSA(), - * EVP_PKEY_set1_RSA(), i2d_PrivateKey_bio(), d2i_PrivateKey_bio(), - * i2d_PUBKEY_bio(), d2i_PUBKEY_bio(), PEM_read_bio_PrivateKey(), - * PEM_write_bio_PrivateKey(), PEM_read_bio_PUBKEY(), - * PEM_write_bio_PUBKEY(). - * - * PEM passphrases use a callback which takes a void* cookie, so that - * shouldn't be too bad. Furthermore, it looks like if we just leave - * the callback pointer NULL and pass the password as the void* - * cookie, the default callback handler will do exactly what we want. - * - * A lot of the EVP_PKEY manipulation we'd need to do here looks like - * we'd just be incrementing reference counts. EVP_PKEY_free() - * appears to do the right thing, and I see no EVP_PKEY_dup(). The - * approved way of incrementing the reference count appears to be: - * - * CRYPTO_add(&my_evp_pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); - * - * Return value from CRYPTO_add() can be ignored when incrementing, - * not when decrementing (might go to zero). Probably just use - * EVP_PKEY_free() to decrement even if it looks funny. - * - * Looks like the way to find out what kind of public key this is, if - * we really need to know, is to use EVP_PKEY_asn1_get0_info() to get - * the pkey_id value, which happens to map exactly to algorithm NIDs - * but conceptually is a separate space. - */ - /* * Disable compilation of X509 certificate signature and verification * API. We don't currently need this for RPKI but I'm not quite ready @@ -178,10 +152,6 @@ */ #define MAX_ASN1_INTEGER_LEN 20 -/* PEM encoded data types */ -#define RSA_PUBLIC_KEY 1 -#define RSA_PRIVATE_KEY 2 - /* Asymmetric ciphers */ #define RSA_CIPHER 1 @@ -436,20 +406,6 @@ evp_digest_factory(int digest_type) } } -static int -evp_digest_nid(int digest_type) -{ - switch (digest_type) { - case MD5_DIGEST: return NID_md5; - case SHA_DIGEST: return NID_sha; - case SHA1_DIGEST: return NID_sha1; - case SHA256_DIGEST: return NID_sha256; - case SHA384_DIGEST: return NID_sha384; - case SHA512_DIGEST: return NID_sha512; - default: return NID_undef; - } -} - /* * Raise an exception with data pulled from the OpenSSL error stack. * Exception value is a tuple with some internal structure. If a @@ -533,11 +489,12 @@ x509_object_helper_set_name(PyObject *dn_obj) (value_str = PyString_AsString(value_obj)) == NULL) goto error; - if ((asn1_type = ASN1_PRINTABLE_type(value_str, -1)) != V_ASN1_PRINTABLESTRING) + 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, - value_str, strlen(value_str), + (unsigned char *) value_str, + strlen((char *) value_str), -1, (j ? -1 : 0))) lose("Unable to add name entry"); @@ -1494,11 +1451,28 @@ x509_object_der_write(x509_object *self) return result; } -#warning Where did x509_object_get_public_key go +static char x509_object_get_public_key__doc__[] = + "This method gets the public key for this certificate object.\n" + ; -/* - * Currently this function only supports RSA keys. - */ +static PyObject * +x509_object_get_public_key(x509_object *self) +{ + PyTypeObject *type = &POW_Asymmetric_Type; + asymmetric_object *asym = NULL; + + 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__[] = "This method sets the public key for this certificate object.\n" @@ -2474,19 +2448,19 @@ x509_object_set_rfc3779(x509_object *self, PyObject *args, PyObject *kwds) while ((item = PyIter_Next(iterator)) != NULL) { - if (!PyArg_ParseTuple(item, "OO", &range_b, &range_e)) + if (!PyArg_ParseTuple(item, "O!O!", + &POW_IPAddress_Type, &range_b, + &POW_IPAddress_Type, &range_e)) goto error; addr_b = (ipaddress_object *) range_b; addr_e = (ipaddress_object *) range_e; - if (!POW_IPAddress_Check(range_b) || - !POW_IPAddress_Check(range_e) || - addr_b->version != addr_e->version || + if (addr_b->version != addr_e->version || addr_b->length != len || addr_e->length != len || memcmp(addr_b->address, addr_e->address, addr_b->length) > 0) - lose_type_error("IPAddrBlock must be sequence of address pairs, or \"inherit\""); + lose("IPAddrBlock must be sequence of address pairs, or \"inherit\""); if (!v3_addr_add_range(addr, afi, NULL, addr_b->address, addr_e->address)) lose_openssl_error("Couldn't add range to IPAddrBlock"); @@ -2568,7 +2542,7 @@ x509_object_set_basic_constraints(x509_object *self, PyObject *args) PyObject *is_ca = NULL; PyObject *pathlen_obj = Py_None; PyObject *critical = Py_True; - long pathlen; + long pathlen = -1; int ok = 0; if (!PyArg_ParseTuple(args, "O|OO", &is_ca, &pathlen_obj, &critical)) @@ -2664,7 +2638,7 @@ x509_object_get_sia(x509_object *self) if (a->location->type != GEN_URI) continue; nid = OBJ_obj2nid(a->method); - uri = ASN1_STRING_data(a->location->d.uniformResourceIdentifier); + uri = (char *) ASN1_STRING_data(a->location->d.uniformResourceIdentifier); if (nid == NID_caRepository) { if ((obj = PyString_FromString(uri)) == NULL) goto error; @@ -2717,9 +2691,9 @@ x509_object_set_sia(x509_object *self, PyObject *args) ASN1_OBJECT *oid = NULL; PyObject **pobj = NULL; PyObject *item = NULL; - ACCESS_DESCRIPTION *a; - int i, nid, ok = 0; - size_t urilen; + ACCESS_DESCRIPTION *a = NULL; + int i, nid = NID_undef, ok = 0; + Py_ssize_t urilen; char *uri; if (!PyArg_ParseTuple(args, "OOO", &caRepository, &rpkiManifest, &signedObject)) @@ -2758,7 +2732,7 @@ x509_object_set_sia(x509_object *self, PyObject *args) 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, uri, urilen)) + !ASN1_OCTET_STRING_set(a->location->d.uniformResourceIdentifier, (unsigned char *) uri, urilen)) lose_no_memory(); a->location->type = GEN_URI; @@ -2827,7 +2801,7 @@ x509_object_get_aia(x509_object *self) 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 = ASN1_STRING_data(a->location->d.uniformResourceIdentifier); + uri = (char *) ASN1_STRING_data(a->location->d.uniformResourceIdentifier); if ((obj = PyString_FromString(uri)) == NULL) goto error; PyTuple_SET_ITEM(result, n++, obj); @@ -2856,9 +2830,9 @@ x509_object_set_aia(x509_object *self, PyObject *args) PyObject *iterator = NULL; ASN1_OBJECT *oid = NULL; PyObject *item = NULL; - ACCESS_DESCRIPTION *a; + ACCESS_DESCRIPTION *a = NULL; int ok = 0; - size_t urilen; + Py_ssize_t urilen; char *uri; if (!PyArg_ParseTuple(args, "O", &caIssuers)) @@ -2881,7 +2855,7 @@ x509_object_set_aia(x509_object *self, PyObject *args) 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, uri, urilen)) + !ASN1_OCTET_STRING_set(a->location->d.uniformResourceIdentifier, (unsigned char *) uri, urilen)) lose_no_memory(); a->location->type = GEN_URI; @@ -2953,7 +2927,7 @@ x509_object_get_crldp(x509_object *self) 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 = ASN1_STRING_data(gn->d.uniformResourceIdentifier); + uri = (char *) ASN1_STRING_data(gn->d.uniformResourceIdentifier); if ((obj = PyString_FromString(uri)) == NULL) goto error; PyTuple_SET_ITEM(result, n++, obj); @@ -2982,8 +2956,8 @@ x509_object_set_crldp(x509_object *self, PyObject *args) PyObject *iterator = NULL; PyObject *item = NULL; DIST_POINT *dp = NULL; - GENERAL_NAME *gn; - size_t urilen; + GENERAL_NAME *gn = NULL; + Py_ssize_t urilen; char *uri; int ok = 0; @@ -3008,7 +2982,7 @@ x509_object_set_crldp(x509_object *self, PyObject *args) if ((gn = GENERAL_NAME_new()) == NULL || (gn->d.uniformResourceIdentifier = ASN1_IA5STRING_new()) == NULL || - !ASN1_OCTET_STRING_set(gn->d.uniformResourceIdentifier, uri, urilen)) + !ASN1_OCTET_STRING_set(gn->d.uniformResourceIdentifier, (unsigned char *) uri, urilen)) lose_no_memory(); gn->type = GEN_URI; @@ -3185,6 +3159,7 @@ 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), @@ -4689,7 +4664,6 @@ static PyObject * asymmetric_object_pem_write_public(asymmetric_object *self) { PyObject *result = NULL; - const EVP_CIPHER *evp_method = NULL; BIO *bio = NULL; if ((bio = BIO_new(BIO_s_mem())) == NULL) @@ -4771,19 +4745,20 @@ static PyObject * asymmetric_object_sign(asymmetric_object *self, PyObject *args) { unsigned char *digest_text = NULL, *signed_text = NULL; - unsigned int digest_type = 0, signed_len = 0, digest_len = 0; + unsigned int digest_type = 0; + size_t signed_len = 0, digest_len = 0; EVP_PKEY_CTX *ctx = NULL; PyObject *result = NULL; if (!PyArg_ParseTuple(args, "s#i", &digest_text, &digest_len, &digest_type)) goto error; -#warning Not sure if I should be setting signature_md here or not - /* - * More precisely, I'm sure I should but I'm also sure that the - * POW API here is an antique, and something we want to go away. - * Try setting signature_md here, revisit if this doesn't work. - */ + /* + * If we need to find out what kind of public key this is, we can + * use EVP_PKEY_asn1_get0_info() to get the pkey_id value, which + * happens to map exactly to algorithm NIDs but conceptually is a + * separate space. + */ if ((ctx = EVP_PKEY_CTX_new(self->pkey, NULL)) == NULL || EVP_PKEY_sign_init(ctx) <= 0 || @@ -4858,7 +4833,7 @@ asymmetric_object_verify(asymmetric_object *self, PyObject *args) EVP_PKEY_CTX_free(ctx); if (ok) - PyBool_FromLong(result); + return PyBool_FromLong(result); else return NULL; } @@ -6024,8 +5999,8 @@ manifest_object_add_files(manifest_object *self, PyObject *args) goto error; if ((fah = FileAndHash_new()) == NULL || - !ASN1_OCTET_STRING_set(fah->file, file, filelen) || - !ASN1_BIT_STRING_set(fah->hash, hash, hashlen) || + !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(); @@ -6474,7 +6449,7 @@ roa_object_set_prefixes(roa_object *self, PyObject *args, PyObject *kwds) ipaddress_object *addr = NULL; PyObject *maxlenobj = Py_None; - if (!PyArg_ParseTuple(item, "OI|O", &addr, &prefixlen, &maxlenobj)) + if (!PyArg_ParseTuple(item, "O!I|O", &POW_IPAddress_Type, &addr, &prefixlen, &maxlenobj)) goto error; if (maxlenobj == Py_None) @@ -6485,7 +6460,7 @@ roa_object_set_prefixes(roa_object *self, PyObject *args, PyObject *kwds) goto error; } - if (!POW_IPAddress_Check(addr) || addr->length != len) + if (addr->length != len) lose_type_error("Bad ROA prefix"); if (prefixlen > addr->length * 8) @@ -6692,9 +6667,6 @@ pow_module_get_error(PyObject *self) ERR_error_string_n(error, buf, sizeof(buf)); return Py_BuildValue("s", buf); - - error: - return NULL; } static char pow_module_clear_error__doc__[] = @@ -6872,16 +6844,8 @@ init_POW(void) Define_Integer_Constant(SHORTNAME_FORMAT); Define_Integer_Constant(OIDNAME_FORMAT); - /* PEM encoded types */ -#ifndef OPENSSL_NO_RSA - Define_Integer_Constant(RSA_PUBLIC_KEY); - Define_Integer_Constant(RSA_PRIVATE_KEY); -#endif - /* Asymmetric ciphers */ -#ifndef OPENSSL_NO_RSA Define_Integer_Constant(RSA_CIPHER); -#endif /* Message digests */ Define_Integer_Constant(MD5_DIGEST); |