aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2012-09-22 20:35:37 +0000
committerRob Austein <sra@hactrn.net>2012-09-22 20:35:37 +0000
commitf1e4209de7625509cd9c5a26404d52b297a78ae5 (patch)
tree4ab0f26847fedf0811cccd7d69098a8ba0478b22
parent1dfedcf7c4929d46367eceedd4e427ccb6906b75 (diff)
Drag Asymmetric class up to using the EVP_PKEY API, which simplifies
the Asymmetric code considerably and gets us most of the way towards being able to support ECDSA, which, in theory, we'll want for BGPSEC. svn path=/branches/tk274/; revision=4732
-rw-r--r--rpkid/ext/POW.c203
1 files changed, 90 insertions, 113 deletions
diff --git a/rpkid/ext/POW.c b/rpkid/ext/POW.c
index 47488f35..19f7cc7a 100644
--- a/rpkid/ext/POW.c
+++ b/rpkid/ext/POW.c
@@ -115,7 +115,9 @@
* PEM_write_bio_PUBKEY().
*
* PEM passphrases use a callback which takes a void* cookie, so that
- * shouldn't be too bad.
+ * 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()
@@ -127,6 +129,11 @@
* 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.
*/
/*
@@ -312,9 +319,7 @@ typedef struct {
typedef struct {
PyObject_HEAD
- void *cipher;
- int key_type;
- int cipher_type;
+ EVP_PKEY *pkey;
} asymmetric_object;
typedef struct {
@@ -1504,23 +1509,17 @@ static char x509_object_set_public_key__doc__[] =
static PyObject *
x509_object_set_public_key(x509_object *self, PyObject *args)
{
- EVP_PKEY *pkey = NULL;
asymmetric_object *asym;
if (!PyArg_ParseTuple(args, "O!", &POW_Asymmetric_Type, &asym))
goto error;
- if ((pkey = EVP_PKEY_new()) == NULL)
- lose_no_memory();
-
- if (!EVP_PKEY_assign_RSA(pkey, asym->cipher) ||
- !X509_set_pubkey(self->x509, pkey))
+ if (!X509_set_pubkey(self->x509, asym->pkey))
lose_openssl_error("Couldn't set certificate's public key");
Py_RETURN_NONE;
error:
- EVP_PKEY_free(pkey);
return NULL;
}
@@ -1546,7 +1545,6 @@ static char x509_object_sign__doc__[] =
static PyObject *
x509_object_sign(x509_object *self, PyObject *args)
{
- EVP_PKEY *pkey = NULL;
asymmetric_object *asym;
int digest_type = SHA256_DIGEST;
const EVP_MD *digest_method = NULL;
@@ -1554,25 +1552,15 @@ x509_object_sign(x509_object *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O!|i", &POW_Asymmetric_Type, &asym, &digest_type))
goto error;
- if ((pkey = EVP_PKEY_new()) == NULL)
- lose_no_memory();
-
- if (asym->key_type != RSA_PRIVATE_KEY)
- lose("Don't know how to use this type of key");
-
- if (!EVP_PKEY_assign_RSA(pkey, asym->cipher))
- lose_openssl_error("EVP_PKEY assignment error");
-
if ((digest_method = evp_digest_factory(digest_type)) == NULL)
lose("Unsupported digest algorithm");
- if (!X509_sign(self->x509, pkey, digest_method))
+ if (!X509_sign(self->x509, asym->pkey, digest_method))
lose_openssl_error("Couldn't sign certificate");
Py_RETURN_NONE;
error:
- EVP_PKEY_free(pkey);
return NULL;
}
@@ -2819,7 +2807,7 @@ x509_object_get_aia(x509_object *self)
PyObject *result = NULL;
const char *uri;
PyObject *obj;
- int i, nid, n = 0;
+ int i, n = 0;
if ((ext = X509_get_ext_d2i(self->x509, NID_info_access, NULL, NULL)) == NULL)
Py_RETURN_NONE;
@@ -2869,7 +2857,7 @@ x509_object_set_aia(x509_object *self, PyObject *args)
ASN1_OBJECT *oid = NULL;
PyObject *item = NULL;
ACCESS_DESCRIPTION *a;
- int i, ok = 0;
+ int ok = 0;
size_t urilen;
char *uri;
@@ -2943,7 +2931,7 @@ x509_object_get_crldp(x509_object *self)
PyObject *result = NULL;
const char *uri;
PyObject *obj;
- int i, nid, n = 0;
+ int i, n = 0;
if ((ext = X509_get_ext_d2i(self->x509, NID_crl_distribution_points, NULL, NULL)) == NULL ||
(dp = sk_DIST_POINT_value(ext, 0)) == NULL ||
@@ -4093,7 +4081,6 @@ static char crl_object_sign__doc__[] =
static PyObject *
crl_object_sign(crl_object *self, PyObject *args)
{
- EVP_PKEY *pkey = NULL;
asymmetric_object *asym;
int digest_type = SHA256_DIGEST;
const EVP_MD *digest_method = NULL;
@@ -4101,23 +4088,15 @@ crl_object_sign(crl_object *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O!|i", &POW_Asymmetric_Type, &asym, &digest_type))
goto error;
- if ((pkey = EVP_PKEY_new()) == NULL)
- lose_no_memory();
-
- if (asym->key_type != RSA_PRIVATE_KEY)
- lose("Don't know how to use this type of key");
-
if ((digest_method = evp_digest_factory(digest_type)) == NULL)
lose("Unsupported digest algorithm");
- if (!EVP_PKEY_assign_RSA(pkey, asym->cipher) ||
- !X509_CRL_sign(self->crl, pkey, digest_method))
+ if (!X509_CRL_sign(self->crl, asym->pkey, digest_method))
lose_openssl_error("Couldn't sign CRL");
Py_RETURN_NONE;
error:
- EVP_PKEY_free(pkey);
return NULL;
}
@@ -4132,22 +4111,14 @@ static char crl_object_verify__doc__[] =
static PyObject *
crl_object_verify(crl_object *self, PyObject *args)
{
- EVP_PKEY *pkey = NULL;
asymmetric_object *asym;
if (!PyArg_ParseTuple(args, "O!", &POW_Asymmetric_Type, &asym))
goto error;
- if ((pkey = EVP_PKEY_new()) == NULL)
- lose_no_memory();
-
- if (!EVP_PKEY_assign_RSA(pkey, asym->cipher))
- lose_openssl_error("EVP_PKEY assignment error");
-
- return PyBool_FromLong(X509_CRL_verify(self->crl, pkey));
+ return PyBool_FromLong(X509_CRL_verify(self->crl, asym->pkey));
error:
- EVP_PKEY_free(pkey);
return NULL;
}
@@ -4423,7 +4394,7 @@ asymmetric_object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if ((self = (asymmetric_object *) type->tp_alloc(type, 0)) == NULL)
goto error;
- self->cipher = NULL;
+ self->pkey = NULL;
return (PyObject *) self;
@@ -4438,30 +4409,47 @@ asymmetric_object_init(asymmetric_object *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"cipher", "key_size", NULL};
int cipher_type = RSA_CIPHER, key_size = 2048;
+ EVP_PKEY_CTX *ctx = NULL;
+ int ok = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist, &cipher_type, &key_size))
goto error;
+ /*
+ * This silliness is necessary until we move this to an RSA-specific class method.
+ */
if (cipher_type != RSA_CIPHER)
lose("unsupported cipher");
- switch (self->cipher_type) {
+ 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)
+ lose_openssl_error("Couldn't initialize EVP_PKEY_CTX");
- case RSA_CIPHER:
- RSA_free(self->cipher);
- break;
- }
+#warning Look up how to set additional RSA key generation parameters like F4
+ /*
+ * Should set RSA_F4 for drill, although I think it's the default now.
+ * Looks like the call is
+ * int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *pubexp);
+ * while RSA_F4 is a plain C long integer, so would need to make a bignum (sigh),
+ * which is probably BN_new()/BN_set_word()/BN_free().
+ */
- if ((self->cipher = RSA_generate_key(key_size, RSA_F4, NULL, NULL)) == NULL)
- lose("could not generate key");
+ EVP_PKEY_free(self->pkey);
+ self->pkey = NULL;
- self->key_type = RSA_PRIVATE_KEY;
- self->cipher_type = RSA_CIPHER;
+ if (EVP_PKEY_keygen(ctx, &self->pkey) <= 0)
+ lose_openssl_error("Couldn't generate new RSA key");
- return 0;
+ ok = 1;
error:
- return -1;
+ EVP_PKEY_CTX_free(ctx);
+
+ if (ok)
+ return 0;
+ else
+ return -1;
}
static PyObject *
@@ -4472,11 +4460,9 @@ asymmetric_object_pem_read_private_helper(PyTypeObject *type, BIO *in, char *pas
if ((self = (asymmetric_object *) asymmetric_object_new(type, NULL, NULL)) == NULL)
goto error;
- if ((self->cipher = PEM_read_bio_RSAPrivateKey(in, NULL, NULL, pass)) == NULL)
+ if ((self->pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, pass)) == NULL)
lose_openssl_error("Couldn't load private key");
- self->key_type = RSA_PRIVATE_KEY;
- self->cipher_type = RSA_CIPHER;
return (PyObject *) self;
error:
@@ -4552,11 +4538,9 @@ asymmetric_object_der_read_private_helper(PyTypeObject *type, BIO *bio)
if ((self = (asymmetric_object *) asymmetric_object_new(&POW_Asymmetric_Type, NULL, NULL)) == NULL)
goto error;
- if ((self->cipher = d2i_RSAPrivateKey_bio(bio, NULL)) == NULL)
+ if ((self->pkey = d2i_PrivateKey_bio(bio, NULL)) == NULL)
lose_openssl_error("Couldn't load private key");
- self->key_type = RSA_PRIVATE_KEY;
- self->cipher_type = RSA_CIPHER;
return (PyObject *) self;
error:
@@ -4593,11 +4577,9 @@ asymmetric_object_pem_read_public_helper(PyTypeObject *type, BIO *in)
if ((self = (asymmetric_object *) asymmetric_object_new(&POW_Asymmetric_Type, NULL, NULL)) == NULL)
goto error;
- if ((self->cipher = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL)) == NULL)
+ if ((self->pkey = PEM_read_bio_PUBKEY(in, NULL, NULL, NULL)) == NULL)
lose_openssl_error("Couldn't load public key");
- self->key_type = RSA_PUBLIC_KEY;
- self->cipher_type = RSA_CIPHER;
return (PyObject *) self;
error:
@@ -4613,11 +4595,9 @@ asymmetric_object_der_read_public_helper(PyTypeObject *type, BIO *bio)
if ((self = (asymmetric_object *) asymmetric_object_new(&POW_Asymmetric_Type, NULL, NULL)) == NULL)
goto error;
- if ((self->cipher = d2i_RSA_PUBKEY_bio(bio, NULL)) == NULL)
+ if ((self->pkey = d2i_PUBKEY_bio(bio, NULL)) == NULL)
lose_openssl_error("Couldn't load public key");
- self->key_type = RSA_PUBLIC_KEY;
- self->cipher_type = RSA_CIPHER;
return (PyObject *) self;
error:
@@ -4685,16 +4665,13 @@ asymmetric_object_pem_write_private(asymmetric_object *self, PyObject *args)
if (!PyArg_ParseTuple(args, "|s", &passphrase))
goto error;
- if (self->key_type != RSA_PRIVATE_KEY)
- lose("Sorry, this object is not a private key");
-
if ((bio = BIO_new(BIO_s_mem())) == NULL)
lose_no_memory();
if (passphrase)
evp_method = EVP_aes_256_cbc();
- if (!PEM_write_bio_RSAPrivateKey(bio, self->cipher, evp_method, NULL, 0, NULL, passphrase))
+ 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);
@@ -4718,7 +4695,7 @@ asymmetric_object_pem_write_public(asymmetric_object *self)
if ((bio = BIO_new(BIO_s_mem())) == NULL)
lose_no_memory();
- if (!PEM_write_bio_RSA_PUBKEY(bio, self->cipher))
+ if (!PEM_write_bio_PUBKEY(bio, self->pkey))
lose_openssl_error("Unable to write key");
result = BIO_to_PyString_helper(bio);
@@ -4738,13 +4715,10 @@ asymmetric_object_der_write_private(asymmetric_object *self)
PyObject *result = NULL;
BIO *bio = NULL;
- if (self->key_type != RSA_PRIVATE_KEY)
- lose("Sorry, this object is not an RSA private key");
-
if ((bio = BIO_new(BIO_s_mem())) == NULL)
lose_no_memory();
- if (!i2d_RSAPrivateKey_bio(bio, self->cipher))
+ if (!i2d_PrivateKey_bio(bio, self->pkey))
lose_openssl_error("Unable to write private key");
result = BIO_to_PyString_helper(bio);
@@ -4767,7 +4741,7 @@ asymmetric_object_der_write_public(asymmetric_object *self)
if ((bio = BIO_new(BIO_s_mem())) == NULL)
lose_no_memory();
- if (!i2d_RSA_PUBKEY_bio(bio, self->cipher))
+ if (!i2d_PUBKEY_bio(bio, self->pkey))
lose_openssl_error("Unable to write public key");
result = BIO_to_PyString_helper(bio);
@@ -4798,25 +4772,36 @@ 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;
+ EVP_PKEY_CTX *ctx = NULL;
PyObject *result = NULL;
if (!PyArg_ParseTuple(args, "s#i", &digest_text, &digest_len, &digest_type))
goto error;
- if (self->key_type != RSA_PRIVATE_KEY)
- lose("Unsupported key type");
-
- if ((signed_text = malloc(RSA_size(self->cipher))) == NULL)
+#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 ((ctx = EVP_PKEY_CTX_new(self->pkey, NULL)) == NULL ||
+ EVP_PKEY_sign_init(ctx) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_signature_md(ctx, evp_digest_factory(digest_type)) <= 0 ||
+ EVP_PKEY_sign(ctx, NULL, &signed_len, digest_text, digest_len) <= 0)
+ lose_openssl_error("Couldn't set up signing context");
+
+ if ((signed_text = malloc(signed_len)) == NULL)
lose_no_memory();
- if (!RSA_sign(evp_digest_nid(digest_type),
- digest_text, digest_len,
- signed_text, &signed_len, self->cipher))
+ if (EVP_PKEY_sign(ctx, signed_text, &signed_len, digest_text, digest_len) <= 0)
lose_openssl_error("Couldn't sign digest");
result = Py_BuildValue("s#", signed_text, signed_len);
error: /* Fall through */
+ EVP_PKEY_CTX_free(ctx);
if (signed_text)
free(signed_text);
return result;
@@ -4849,6 +4834,8 @@ asymmetric_object_verify(asymmetric_object *self, PyObject *args)
{
unsigned char *digest_text = NULL, *signed_text = NULL;
int digest_type = 0, signed_len = 0, digest_len = 0;
+ EVP_PKEY_CTX *ctx = NULL;
+ int ok = 0, result;
if (!PyArg_ParseTuple(args, "s#s#i",
&signed_text, &signed_len,
@@ -4856,13 +4843,24 @@ asymmetric_object_verify(asymmetric_object *self, PyObject *args)
&digest_type))
goto error;
- return PyBool_FromLong(RSA_verify(evp_digest_nid(digest_type),
- digest_text, digest_len,
- signed_text, signed_len, self->cipher));
+ if ((ctx = EVP_PKEY_CTX_new(self->pkey, NULL)) == NULL ||
+ EVP_PKEY_verify_init(ctx) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_signature_md(ctx, evp_digest_factory(digest_type)) <= 0)
+ lose_openssl_error("Couldn't set up EVP_PKEY_CTX");
+
+ if ((result = EVP_PKEY_verify(ctx, signed_text, signed_len, digest_text, digest_len)) < 0)
+ lose_openssl_error("Unable to perform public key validation");
+
+ ok = 1;
error:
+ EVP_PKEY_CTX_free(ctx);
- return NULL;
+ if (ok)
+ PyBool_FromLong(result);
+ else
+ return NULL;
}
static struct PyMethodDef asymmetric_object_methods[] = {
@@ -4886,11 +4884,7 @@ static struct PyMethodDef asymmetric_object_methods[] = {
static void
asymmetric_object_dealloc(asymmetric_object *self)
{
- switch (self->cipher_type) {
- case RSA_CIPHER:
- RSA_free(self->cipher);
- break;
- }
+ EVP_PKEY_free(self->pkey);
self->ob_type->tp_free((PyObject*) self);
}
@@ -5318,7 +5312,6 @@ cms_object_sign(cms_object *self, PyObject *args)
PyObject *crl_sequence = Py_None;
PyObject *result = NULL;
STACK_OF(X509) *x509_stack = NULL;
- EVP_PKEY *pkey = NULL;
char *buf = NULL, *oid = NULL;
int i, n, len;
unsigned flags = 0;
@@ -5341,24 +5334,11 @@ cms_object_sign(cms_object *self, PyObject *args)
flags &= CMS_NOCERTS | CMS_NOATTR;
flags |= CMS_BINARY | CMS_NOSMIMECAP | CMS_PARTIAL | CMS_USE_KEYID;
- if (signkey->key_type != RSA_PRIVATE_KEY)
- lose("Unsupported key type");
-
if ((x509_stack = x509_helper_sequence_to_stack(x509_sequence)) == NULL)
goto error;
assert_no_unhandled_openssl_errors();
- if ((pkey = EVP_PKEY_new()) == NULL)
- lose_no_memory();
-
- assert_no_unhandled_openssl_errors();
-
- if (!EVP_PKEY_assign_RSA(pkey, signkey->cipher))
- lose_openssl_error("EVP_PKEY assignment error");
-
- assert_no_unhandled_openssl_errors();
-
if ((bio = BIO_new_mem_buf(buf, len)) == NULL)
lose_no_memory();
@@ -5379,11 +5359,9 @@ cms_object_sign(cms_object *self, PyObject *args)
assert_no_unhandled_openssl_errors();
- if (!CMS_add1_signer(cms, signcert->x509, pkey, EVP_sha256(), flags))
+ if (!CMS_add1_signer(cms, signcert->x509, signkey->pkey, EVP_sha256(), flags))
lose_openssl_error("Couldn't sign CMS message");
- pkey = NULL; /* CMS_add1_signer() now owns pkey */
-
assert_no_unhandled_openssl_errors();
if (crl_sequence != Py_None) {
@@ -5432,7 +5410,6 @@ cms_object_sign(cms_object *self, PyObject *args)
CMS_ContentInfo_free(cms);
BIO_free(bio);
sk_X509_free(x509_stack);
- EVP_PKEY_free(pkey);
ASN1_OBJECT_free(econtent_type);
Py_XDECREF(crlobj);