patches for X509_EXTENSION and a few other things
Matt Rodriguez <[email protected]>
| Newsgroups | gmane.comp.python.cryptography |
|---|---|
| Message-ID | <[email protected]> |
I've done a little work with M2Crypto because I've been using it to generate proxy certificates. Proxy Certificates need to have a proxy certificate info extension for openssl to recognize them. Openssl versions 0.9.8 and later have support for proxy certificates. So here are the changes that I've made. 1. I added a as_der method to the EVP class in EVP.py. This calls i2d_PUBKEY to get the DER encoding. 2. I changed the new_extensions function in X509. It initializes a LHASH and a X509V3_CTX objects, and passes them into the X509V3_ext_conf function. I did this was because to use the ProxyCertInfo extension it needed an initialized context object, otherwise I would get a segmentation fault. This is because the X509_EXTENSION_METHOD object assoctiated with PCI does not contain v2i or s2i functions. The method does have an r2i function, but the do_ext_nconf does a check on the context to see if it has a db or db_meth object. If the context is NULL then there is a segmentation fault. If there is another way to create a PCI extension using M2Crypto without this patch, I'd like to know about it. 3. Changes to setup.py. I've mentioned this in previous posts. I added an option so that one could build M2Crypto against openssl that is installed in an arbitrary location. 4. I added a quick test to test_evp.py that tests the as_der method. 5. I fixed an obvious memory leak in _x509.i in the x509_extension_get_name. I've tested these changes with openssl-0.9.8a using valgrind to make sure my changes didn't leak any more memory. Please let me know if there are any problems with the patches or if there is anything I can do to facilitate adding these patches to M2Crypto. Matt Rodriguez
ext.patch
(text/x-patch, 5.8 KB)
Index: M2Crypto/EVP.py
===================================================================
--- M2Crypto/EVP.py (revision 319)
+++ M2Crypto/EVP.py (working copy)
@@ -282,6 +282,12 @@
self.save_key_bio(bio, cipher, callback)
return bio.read_all()
+ def as_der(self):
+ buf = m2.pkey_as_der(self.pkey)
+ if buf == None:
+ raise "Raising a string for now, the der conversion failed"
+ bio = BIO.MemoryBuffer(buf)
+ return bio.read_all()
def load_key(file, callback=util.passphrase_callback):
"""
Index: M2Crypto/X509.py
===================================================================
--- M2Crypto/X509.py (revision 319)
+++ M2Crypto/X509.py (working copy)
@@ -23,10 +23,12 @@
"""
Create new X509_Extension instance.
"""
- x509_ext_ptr = m2.x509v3_ext_conf(None, None, name, value)
+ lhash = m2.x509v3_lhash()
+ ctx = m2.x509v3_set_conf_lhash(lhash)
+ x509_ext_ptr = m2.x509v3_ext_conf(lhash, ctx, name, value)
x509_ext = X509_Extension(x509_ext_ptr, _pyfree)
x509_ext.set_critical(critical)
- return x509_ext
+ return x509_ext
class X509_Extension:
Index: setup.py
===================================================================
--- setup.py (revision 319)
+++ setup.py (working copy)
@@ -15,6 +15,30 @@
from distutils.core import setup, Extension
from distutils.command import build_ext
+global_option_dict = {'openssl_prefix': '/usr'}
+
+def print_help():
+ print "M2Crypto help"
+ print "--openssl=path_to_openssl, defaults to /usr"
+ print "--help, this usage message"
+
+def parse_args():
+ global global_option_dict
+ args = sys.argv[1:]
+ for arg in args:
+ if arg.find("--openssl") != -1:
+ sys.argv.remove(arg)
+ prefix = arg.split('=')[1]
+ global_option_dict['openssl_prefix'] = prefix
+
+ if arg.find("--help") != -1:
+ sys.argv.remove(arg)
+ print_help()
+ sys.exit(0)
+
+parse_args()
+
+
my_inc = os.path.join(os.getcwd(), 'SWIG')
if os.name == 'nt':
@@ -25,9 +49,11 @@
libraries = ['ssleay32', 'libeay32']
elif os.name == 'posix':
- include_dirs = [my_inc, '/usr/include']
- swig_opts_str = '-I/usr/include'
- library_dirs = ['/usr/lib']
+ include_dir = os.path.join(global_option_dict['openssl_prefix'], "include")
+ include_dirs = [my_inc, include_dir]
+ library_dir = os.path.join(global_option_dict['openssl_prefix'], "lib")
+ library_dirs = [library_dir]
+ swig_opts_str = "-I" + include_dir
if sys.platform == 'cygwin':
# Cygwin SHOULD work (there's code in distutils), but
# if one first starts a Windows command prompt, then bash,
@@ -77,7 +103,10 @@
return new_sources
swig = self.find_swig()
- swig_cmd = [swig, "-python", "-ISWIG"]
+ include_dir = os.path.join(
+ global_option_dict['openssl_prefix'],
+ "include")
+ swig_cmd = [swig, "-python", "-ISWIG"]
if self.swig_cpp:
swig_cmd.append("-c++")
Index: tests/test_evp.py
===================================================================
--- tests/test_evp.py (revision 319)
+++ tests/test_evp.py (working copy)
@@ -37,6 +37,15 @@
self.assertRaises(ValueError, pkey.as_pem, cipher='noXX$$%%suchcipher',
callback=self._pass_callback)
+ def check_as_der(self):
+ rsa = RSA.gen_key(512, 3, callback=self._gen_callback)
+ pkey = EVP.PKey()
+ pkey.assign_rsa(rsa)
+ der_blob = pkey.as_der()
+ #A quick but not thorough sanity check
+ assert len(der_blob) == 92
+
+
def check_MessageDigest(self):
md = EVP.MessageDigest('sha1')
md.update('Hello')
Index: SWIG/_evp.i
===================================================================
--- SWIG/_evp.i (revision 319)
+++ SWIG/_evp.i (working copy)
@@ -467,5 +467,19 @@
int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) {
return EVP_PKEY_assign_RSA(pkey, rsa);
}
+
+PyObject * pkey_as_der(EVP_PKEY *pkey){
+ unsigned char * pp = NULL;
+ int len;
+ PyObject * buffer;
+ len = i2d_PUBKEY(pkey, &pp);
+ if (len < 0){
+ return NULL;
+ }
+ buffer = PyString_FromStringAndSize(&pp, len);
+ free(pp);
+ return buffer;
+}
+
%}
Index: SWIG/_x509.i
===================================================================
--- SWIG/_x509.i (revision 319)
+++ SWIG/_x509.i (working copy)
@@ -314,8 +314,25 @@
return X509_NAME_ENTRY_create_by_txt( ne, field, type, bytes, len);
}
+LHASH *
+x509v3_lhash(){
+ return lh_new(NULL,NULL);
+}
+
+X509V3_CTX *
+x509v3_set_conf_lhash(LHASH * lhash){
+ X509V3_CTX * ctx;
+ ctx = PyMem_New(X509V3_CTX,sizeof(X509V3_CTX));
+ X509V3_set_conf_lhash(ctx, lhash);
+ return ctx;
+}
+
X509_EXTENSION *x509v3_ext_conf(LHASH *conf, X509V3_CTX *ctx, char *name, char *value) {
- return X509V3_EXT_conf(conf, ctx, name, value);
+ X509_EXTENSION * ext = NULL;
+ ext = X509V3_EXT_conf(conf, ctx, name, value);
+ PyMem_Free(ctx);
+ lh_free(conf);
+ return ext;
}
/* X509_EXTENSION_free() might be a macro, didn't find definition. */
@@ -323,8 +340,12 @@
X509_EXTENSION_free(ext);
}
-char *x509_extension_get_name(X509_EXTENSION *ext) {
- return strdup(OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))));
+PyObject *x509_extension_get_name(X509_EXTENSION *ext) {
+ PyObject * ext_name = NULL;
+ char * ext_name_str = NULL;
+ ext_name_str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
+ ext_name = PyString_FromStringAndSize(ext_name_str, strlen(ext_name_str));
+ return ext_name;
}
/* sk_X509_EXTENSION_new_null is a macro. */