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. */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.