aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2013-10-08 05:03:33 +0000
committerRob Austein <sra@hactrn.net>2013-10-08 05:03:33 +0000
commit57d5b2e106e18bdcde954b257f5d89ddb567fcf4 (patch)
tree38f09f041ed5e0f2ee440c7d6637f20b2bce1032
parent9a6b8284b0912344993f6af9929915c6363396e3 (diff)
Preliminary support for ECDSA and EC key parameter generation. At the
moment, the only kind of parameters we know how to generate are for EC on the P-256 curve, but the key generation code should accept any parameters that the OpenSSL command line tool's genpkey command can generate (and is not limited to ECDSA -- DSA and DH should work, most likely ECDH as well). Adding capability of generating parameters for other well-known EC curves would just mean exposing additional NID values, so we could easily support any curve OpenSSL knows about. Adding parameter generation for DH etc would be maybe a dozen additional lines of C code per algorithm, as all of these use the same internal EVP_PKEY interface with minor variations. svn path=/trunk/; revision=5554
-rw-r--r--rpkid/ext/POW.c301
1 files changed, 276 insertions, 25 deletions
diff --git a/rpkid/ext/POW.c b/rpkid/ext/POW.c
index bab7b94c..72b5b415 100644
--- a/rpkid/ext/POW.c
+++ b/rpkid/ext/POW.c
@@ -126,9 +126,6 @@ define GCC_UNUSED
*/
#define MAX_ASN1_INTEGER_LEN 20
-/* Asymmetric ciphers */
-#define RSA_CIPHER 1
-
/* Digests */
#define MD5_DIGEST 2
#define SHA_DIGEST 3
@@ -142,9 +139,8 @@ define GCC_UNUSED
#define LONGNAME_FORMAT 2
#define OIDNAME_FORMAT 3
-/* Output format */
-#define PEM_FORMAT 1
-#define DER_FORMAT 2
+/* 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)
@@ -152,6 +148,7 @@ define GCC_UNUSED
#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)
@@ -283,6 +280,7 @@ static PyTypeObject
POW_X509StoreCTX_Type,
POW_CRL_Type,
POW_Asymmetric_Type,
+ POW_AsymmetricParams_Type,
POW_Digest_Type,
POW_CMS_Type,
POW_IPAddress_Type,
@@ -330,6 +328,11 @@ typedef struct {
typedef struct {
PyObject_HEAD
+ EVP_PKEY *pkey;
+} asymmetric_params_object;
+
+typedef struct {
+ PyObject_HEAD
EVP_MD_CTX digest_ctx;
int digest_type;
} digest_object;
@@ -5319,24 +5322,56 @@ asymmetric_object_generate_rsa(PyTypeObject *type, PyObject *args, PyObject *kwd
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)
- lose_openssl_error("Couldn't initialize EVP_PKEY_CTX");
+ 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");
- /*
- * We should set RSA_F4 for drill, but it's the default so not urgent.
- * 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().
- */
+ ok = 1;
- EVP_PKEY_free(self->pkey);
- self->pkey = NULL;
+ error:
+ EVP_PKEY_CTX_free(ctx);
- if (EVP_PKEY_keygen(ctx, &self->pkey) <= 0)
- lose_openssl_error("Couldn't generate new RSA key");
+ 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, &params))
+ 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;
@@ -5395,15 +5430,13 @@ static struct PyMethodDef asymmetric_object_methods[] = {
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"
- "At the moment the only supported algorithm is RSA, but that will\n"
- "likely change, as BGPSEC will require EC-DSA.\n"
- "\n"
LAME_DISCLAIMER_IN_ALL_CLASS_DOCUMENTATION
;
@@ -5452,6 +5485,223 @@ static PyTypeObject POW_Asymmetric_Type = {
/*
+ * 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)
+{
+ const EVP_CIPHER *evp_method = NULL;
+ 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 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),
+ {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.
*/
@@ -8789,6 +9039,7 @@ init_POW(void)
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);
@@ -8817,9 +9068,6 @@ init_POW(void)
Define_Integer_Constant(SHORTNAME_FORMAT);
Define_Integer_Constant(OIDNAME_FORMAT);
- /* Asymmetric ciphers */
- Define_Integer_Constant(RSA_CIPHER);
-
/* Message digests */
Define_Integer_Constant(MD5_DIGEST);
Define_Integer_Constant(SHA_DIGEST);
@@ -8899,6 +9147,9 @@ init_POW(void)
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
/*