diff options
-rw-r--r-- | rpkid/ext/POW.c | 301 |
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, ¶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; @@ -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 /* |