[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[minion-cvs] Additions to C-level code: Added ability to generate X5...
Update of /home/minion/cvsroot/src/minion/src
In directory moria.seul.org:/tmp/cvs-serv10819/src
Modified Files:
_minionlib.h crypt.c main.c tls.c
Log Message:
Additions to C-level code: Added ability to generate X509 certs, and
to read and write RSA keys from PEM format.
This isn't used yet beyond a verified-to-work-once level, but I'm
checkpointing it before my next batch of hacks so I can't break
anything.
Index: _minionlib.h
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/_minionlib.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- _minionlib.h 1 Jul 2002 18:03:05 -0000 1.5
+++ _minionlib.h 5 Jul 2002 23:34:33 -0000 1.6
@@ -57,11 +57,12 @@
FUNC_DOC(mm_check_oaep_padding);
FUNC_DOC(mm_rsa_generate);
FUNC_DOC(mm_rsa_crypt);
-FUNC_DOC(mm_rsa_encode_key);
FUNC_DOC(mm_rsa_decode_key);
-FUNC_DOC(mm_rsa_get_modulus_bytes);
+FUNC_DOC(mm_rsa_PEM_read_key);
FUNC_DOC(mm_rsa_get_public_key);
FUNC_DOC(mm_rsa_make_public_key);
+FUNC_DOC(mm_generate_dh_parameters);
+FUNC_DOC(mm_generate_cert);
extern PyObject *mm_CryptoError;
extern char mm_CryptoError__doc__[];
Index: crypt.c
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/crypt.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- crypt.c 1 Jul 2002 18:03:05 -0000 1.6
+++ crypt.c 5 Jul 2002 23:34:33 -0000 1.7
@@ -8,6 +8,8 @@
#include <openssl/sha.h>
#include <openssl/rand.h>
#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
#include <_minionlib.h>
#include <assert.h>
@@ -437,6 +439,128 @@
return mm_RSA_new(rsa);
}
+const char mm_RSA_PEM_write_key__doc__[]=
+ "rsa.PEM_write_key(file, public, [password])\n\n"
+ "Writes an RSA key to a file in PEM format with PKCS#8 encryption.\n"
+ "If public is true, writes only the public key, and ignores the password.\n"
+ "Otherwise, writes the full private key, optionally encrypted by a\n"
+ "password.\n";
+
+PyObject *
+mm_RSA_PEM_write_key(PyObject *self, PyObject *args, PyObject *kwdict)
+{
+ static char* kwlist[] = { "file", "public", "password", NULL };
+ PyObject *pyfile;
+ int public, passwordlen=0;
+ char *password=NULL;
+
+ RSA *rsa = NULL;
+ EVP_PKEY *pkey = NULL;
+ FILE *file;
+
+ assert(mm_RSA_Check(self));
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O!i|s#:PEM_write_key",
+ kwlist, &PyFile_Type, &pyfile,
+ &public,
+ &password, &passwordlen))
+ return NULL;
+ if (!(file = PyFile_AsFile(pyfile))) {
+ TYPE_ERR("Invalid file object");
+ return NULL;
+ }
+
+ if (public) {
+ rsa = ((mm_RSA*)self)->rsa;
+ if (!PEM_write_RSAPublicKey(file, rsa))
+ goto error;
+ } else {
+ if (!(rsa = RSAPrivateKey_dup(((mm_RSA*)self)->rsa)))
+ goto error;
+ if (!(pkey = EVP_PKEY_new()))
+ goto error;
+ if (!EVP_PKEY_assign_RSA(pkey,rsa))
+ goto error;
+ rsa = NULL;
+
+ if (password) {
+ printf("Got here 1\n");
+ if (!PEM_write_PKCS8PrivateKey(file, pkey,
+ EVP_des_ede3_cbc(),
+ NULL, 0,
+ NULL, password))
+ goto error;
+ } else {
+ printf("Got here 2\n");
+ if (!PEM_write_PKCS8PrivateKey(file, pkey,
+ NULL,
+ NULL, 0,
+ NULL, NULL))
+ goto error;
+ }
+ printf("got here 3\n");
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+
+ error:
+ if (rsa && !public)
+ RSA_free(rsa);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ mm_SSL_ERR(1);
+ return NULL;
+}
+
+const char mm_rsa_PEM_read_key__doc__[]=
+ "rsa_PEM_read_key(file, public, [password]) -> rsa\n\n"
+ "Writes an RSA key to a file in PEM format with PKCS#8 encryption.\n"
+ "If public is true, reads only the public key, and ignores the password.\n"
+ "Otherwise, writes the full private key, optionally encrypted by a\n"
+ "password.\n";
+
+PyObject *
+mm_rsa_PEM_read_key(PyObject *self, PyObject *args, PyObject *kwdict)
+{
+ static char *kwlist[] = { "file", "public", "password", NULL };
+ PyObject *pyfile;
+ int public, passwordlen=0;
+ char *password=NULL;
+
+ RSA *rsa;
+ FILE *file;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict,
+ "O!i|s#:rsa_PEM_read_key",
+ kwlist, &PyFile_Type, &pyfile,
+ &public,
+ &password, &passwordlen))
+ return NULL;
+ if (!(file = PyFile_AsFile(pyfile))) {
+ TYPE_ERR("Invalid file object");
+ return NULL;
+ }
+ if (!passwordlen)
+ password = "";
+
+ if (public) {
+ rsa = PEM_read_RSAPublicKey(file, NULL, NULL, NULL);
+ } else {
+ rsa = PEM_read_RSAPrivateKey(file, NULL,
+ NULL, password);
+ }
+ if (!rsa) {
+ mm_SSL_ERR(1);
+ return NULL;
+ }
+
+ return mm_RSA_new(rsa);
+}
+
+
+
+
+
/**
* Converts a BIGNUM into a newly allocated PyLongObject.
**/
@@ -555,14 +679,14 @@
"Returns the number of *bytes* (not bits) in an RSA modulus.\n";
static PyObject *
-mm_RSA_get_modulus_bytes(PyObject *self, PyObject *args, PyObject *kwdict)
+mm_RSA_get_modulus_bytes(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { NULL };
RSA *rsa;
assert(mm_RSA_Check(self));
rsa = ((mm_RSA*)self)->rsa;
- if (!PyArg_ParseTupleAndKeywords(args, kwdict,
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
":get_modulus_bytes", kwlist))
return NULL;
@@ -574,6 +698,7 @@
METHOD(mm_RSA, encode_key),
METHOD(mm_RSA, get_modulus_bytes),
METHOD(mm_RSA, get_public_key),
+ METHOD(mm_RSA, PEM_write_key),
{ NULL, NULL }
};
@@ -610,7 +735,7 @@
"be used, in bytes; Param is the security parameter string.\n";
PyObject *
-mm_add_oaep_padding(PyObject *self, PyObject *args, PyObject *kwdict)
+mm_add_oaep_padding(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "s", "param", "keylen", NULL };
@@ -620,7 +745,7 @@
PyObject *output;
- if (!PyArg_ParseTupleAndKeywords(args, kwdict,
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"s#s#i:add_oaep_padding", kwlist,
&input,&inputlen,¶m,¶mlen,&keylen))
return NULL;
@@ -656,7 +781,7 @@
"If the padding is in tact, the original string is returned.\n";
PyObject *
-mm_check_oaep_padding(PyObject *self, PyObject *args, PyObject *kwdict)
+mm_check_oaep_padding(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "s", "param", "keylen", NULL };
@@ -666,7 +791,7 @@
PyObject *output;
- if (!PyArg_ParseTupleAndKeywords(args, kwdict,
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"s#s#i:check_oaep_padding", kwlist,
&input,&inputlen,¶m,¶mlen,&keylen))
return NULL;
@@ -692,6 +817,148 @@
if(_PyString_Resize(&output, r)) return NULL;
return output;
+}
+
+static void
+gen_dh_callback(int p, int n, void *arg)
+{
+ if (p == 0) fputs(".", stderr);
+ if (p == 1) fputs("+", stderr);
+ if (p == 2) fputs("*", stderr);
+ if (p == 3) fputs("\n", stderr);
+}
+
+const char mm_generate_dh_parameters__doc__[] =
+ "generate_dh_parameters(filename, [bits, [verbose]])\n\n"
+ "XXXX";
+
+PyObject *
+mm_generate_dh_parameters(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "filename", "verbose", NULL };
+ char *filename;
+ int bits=512, verbose=0;
+
+ BIO *out = NULL;
+ DH *dh = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "s|i:generate_dh_parameters",
+ kwlist,
+ &filename, &verbose))
+ return NULL;
+
+ if (!(out = BIO_new_file(filename, "w")))
+ goto error;
+ if (!(dh = DH_generate_parameters(bits, 2,
+ verbose?gen_dh_callback:NULL,
+ NULL)))
+ goto error;
+ if (!PEM_write_bio_DHparams(out, dh))
+ goto error;
+ BIO_free(out);
+ DH_free(dh);
+ Py_INCREF(Py_None);
+ return Py_None;
+
+ error:
+ if (out)
+ BIO_free(out);
+ if (dh)
+ DH_free(dh);
+ mm_SSL_ERR(0);
+ return NULL;
+}
+
+const char mm_generate_cert__doc__[] =
+ "generate_cert(filename, rsa, days, cn)\n\n"
+ "XXXX";
+
+PyObject *
+mm_generate_cert(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "filename", "rsa", "days", "cn", NULL };
+ char *filename, *cn;
+ PyObject *_rsa;
+ int days;
+
+ RSA *rsa = NULL;
+ EVP_PKEY *pkey = NULL;
+ BIO *out = NULL;
+ X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+ int nid;
+ PyObject *retval;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!is:PEM_write_key",
+ kwlist, &filename,
+ &mm_RSA_Type, &_rsa, &days, &cn))
+ return NULL;
+
+ if (!(rsa = RSAPrivateKey_dup(((mm_RSA*)_rsa)->rsa)))
+ goto error;
+ if (!(pkey = EVP_PKEY_new()))
+ goto error;
+ if (!(EVP_PKEY_assign_RSA(pkey, rsa)))
+ goto error;
+ rsa = NULL;
+
+ if (!(x509 = X509_new()))
+ goto error;
+ if (!(X509_set_version(x509, 2)))
+ goto error;
+ if (!(ASN1_INTEGER_set(X509_get_serialNumber(x509),0L)))
+ goto error;
+ if (!(name = X509_NAME_new()))
+ goto error;
+
+#define SET_PART(part, val) \
+ if ((nid = OBJ_txt2nid(part)) == NID_undef) goto error; \
+ if (!X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,\
+ val, -1, -1, 0)) goto error;
+
+ SET_PART("countryName", "US");
+ SET_PART("organizationName", "Mixminion network");
+ SET_PART("commonName", cn);
+
+ if (!(X509_set_issuer_name(x509, name)))
+ goto error;
+ if (!X509_gmtime_adj(X509_get_notBefore(x509),0))
+ goto error;
+ /* XXXX */
+ if (!X509_gmtime_adj(X509_get_notAfter(x509), 60L*60L*24L*days))
+ goto error;
+ if (!(X509_set_pubkey(x509, pkey)))
+ goto error;
+ if (!(X509_sign(x509, pkey, EVP_md5())))
+ goto error;
+
+ if (!(out = BIO_new_file(filename, "w")))
+ goto error;
+ if (!(PEM_write_bio_X509(out, x509)))
+ goto error;
+
+ retval = Py_None;
+ Py_INCREF(Py_None);
+ goto done;
+
+error:
+ P(error);
+ retval = NULL;
+ mm_SSL_ERR(1);
+ done:
+ if (out)
+ BIO_free(out);
+ if (name)
+ X509_NAME_free(name);
+ if (x509)
+ X509_free(x509);
+ if (rsa)
+ RSA_free(rsa);
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ return retval;
}
/*
Index: main.c
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/main.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- main.c 1 Jul 2002 18:03:05 -0000 1.4
+++ main.c 5 Jul 2002 23:34:33 -0000 1.5
@@ -29,8 +29,11 @@
ENTRY(check_oaep_padding),
ENTRY(rsa_generate),
ENTRY(rsa_decode_key),
+ ENTRY(rsa_PEM_read_key),
ENTRY(rsa_make_public_key),
-
+ ENTRY(generate_dh_parameters),
+ ENTRY(generate_cert),
+
ENTRY(TLSContext_new),
{ NULL, NULL }
};
@@ -85,6 +88,8 @@
/* crypt */
ERR_load_ERR_strings();
ERR_load_RSA_strings();
+
+ OpenSSL_add_all_algorithms();
if (exc(d, &mm_CryptoError, "mixminion._minionlib.CryptoError",
"CryptoError", mm_CryptoError__doc__))
Index: tls.c
===================================================================
RCS file: /home/minion/cvsroot/src/minion/src/tls.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- tls.c 1 Jul 2002 18:03:05 -0000 1.3
+++ tls.c 5 Jul 2002 23:34:33 -0000 1.4
@@ -85,13 +85,11 @@
#define mm_TLSSock_Check(v) ((v)->ob_type == &mm_TLSSock_Type)
/* XXXX Code to make new cert */
-/* XXXX Code to make new dhparam */
-/* XXXX IO for certs, dhparams. */
const char mm_TLSContext_new__doc__[] =
- "TLSContext([certfile, [pkfile, [dhfile] ] ] )\n\n"
+ "TLSContext([certfile, [rsa, [dhfile] ] ] )\n\n"
"Allocates a new TLSContext object. The files, if provided, are used\n"
- "contain the PEM-encoded X509 public keys, private key file, and DH\n"
+ "contain the PEM-encoded X509 public keys, private key, and DH\n"
"parameters for this context.\n\n"
"BUG:In the future, certs, pks, and dh parameters will be first-class.\n\n"
"LIMITATION: We don\'t expose any more features than Mixminion needs.\n";
@@ -100,16 +98,22 @@
mm_TLSContext_new(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "certfile", "pkfile", "dhfile", NULL };
- char *certfile = NULL, *pkfile=NULL, *dhfile=NULL;
+ char *certfile = NULL, *dhfile=NULL;
+ mm_RSA *rsa = NULL;
+
SSL_METHOD *method;
SSL_CTX *ctx;
DH *dh;
mm_TLSContext *result;
BIO *bio;
+ RSA *_rsa = NULL;
+ EVP_PKEY *pkey = NULL; /* Leaked? ???? */
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sss:TLSContext_new",
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sO!s:TLSContext_new",
kwlist,
- &certfile, &pkfile, &dhfile))
+ &certfile,
+ &mm_RSA_Type, &rsa,
+ &dhfile))
return NULL;
method = TLSv1_method();
@@ -117,7 +121,6 @@
if (!(ctx = SSL_CTX_new(method))) {
mm_SSL_ERR(0); return NULL;
}
-
if (!SSL_CTX_set_cipher_list(ctx, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA)){
SSL_CTX_free(ctx); mm_SSL_ERR(0); return NULL;
}
@@ -125,9 +128,18 @@
!SSL_CTX_use_certificate_file(ctx,certfile,SSL_FILETYPE_PEM)) {
SSL_CTX_free(ctx); mm_SSL_ERR(0); return NULL;
}
- if (pkfile &&
- !(SSL_CTX_use_PrivateKey_file(ctx,pkfile,SSL_FILETYPE_PEM))) {
- SSL_CTX_free(ctx); mm_SSL_ERR(0); return NULL;
+ if (rsa) {
+ if (!(_rsa = RSAPrivateKey_dup(rsa->rsa)) ||
+ !(pkey = EVP_PKEY_new()) ||
+ !EVP_PKEY_assign_RSA(pkey, _rsa)) {
+ if (!pkey && _rsa) RSA_free(_rsa);
+ if (pkey) EVP_PKEY_free(pkey);
+ SSL_CTX_free(ctx); mm_SSL_ERR(0); return NULL;
+ }
+ if (!(SSL_CTX_use_PrivateKey(ctx, pkey))) {
+ EVP_PKEY_free(pkey);
+ SSL_CTX_free(ctx); mm_SSL_ERR(0); return NULL;
+ }
}
if (dhfile) {
@@ -487,7 +499,7 @@
mm_SSL_ERR(0); return NULL; /* ???? */
}
pkey = X509_get_pubkey(cert);
- /* ???? */
+ /* ???? free? leak? */
if (!(rsa = EVP_PKEY_get1_RSA(pkey)))
return NULL; /* XXXX */