Re: M2Crypto improvements

Heikki Toivonen <[email protected]>
Newsgroups gmane.comp.python.cryptography
Message-ID <[email protected]>
Well, it was easier than I thought, so I was actually able to port my 
changes to 0.13p1 already. See the attachment for the changes.

Some comments:
* In my opinion we should get rid of the raw C ptrs in the Python object 
method parameters if there is a corresponding high level Python object 
available. For example, we have X509_Name object, therefore we should 
not pass raw X509_NAME pointers around in the interfaces. Witness 
X509.set_issuer_name for example. I fixed a couple of these instances, 
but they should all be fixed.
* Look for XXX in my code for TODO parts and things I am unsure about.

I think 0.13(p1) has also introduced a bug: the server3/client3 samples 
used to work in 0.12 with my changes, but now with the attached patch 
applied against 0.13(p1) the samples no longer work. Namely, I get the 
following traceback:

Traceback (most recent call last):
   File "server3.py", line 99, in ?
     ctx = setup_server_ctx()
   File "server3.py", line 36, in setup_server_ctx
     ctx.load_cert_chain('server.pem')
   File 
"c:\builds\osaf\chandler\release\bin\Lib\site-packages\M2Crypto\SSL\Context.py", 
line 85, in load_cert_chain
     m2.ssl_ctx_use_cert_chain(self.ctx, certchainfile)
M2Crypto.SSL.SSLError: invalid directory

At this point none of my code has been executed (as far as I can see). 
Can anyone figure out what is going on?

-- 
   Heikki Toivonen
heikki.patch (text/plain, 40.8 KB)
diff -ru9N m2crypto-0.13/M2Crypto/SSL/Connection.py m2crypto-0.13-heikki/M2Crypto/SSL/Connection.py
--- m2crypto-0.13/M2Crypto/SSL/Connection.py	2004-03-31 20:59:34.990192000 -0800
+++ m2crypto-0.13-heikki/M2Crypto/SSL/Connection.py	2004-03-31 20:03:21.509364800 -0800
@@ -35,21 +35,32 @@
             m2.bio_free(self.sslbio)
             m2.bio_free(self.sockbio)
         except AttributeError:
             pass
         self.socket.close()
 
     def close(self):
         m2.ssl_shutdown(self.ssl)
 
+    def clear(self):
+        """
+        If there were errors in this connection, call clear() rather
+        than close() to end it, so that bad sessions will be cleared
+        from cache.
+        """
+        return m2.ssl_clear(self.ssl)
+
     def set_shutdown(self, mode):
         m2.ssl_set_shutdown1(self.ssl, mode)
 
+    def get_shutdown(self):
+        return m2.ssl_get_shutdown(self.ssl)
+
     def bind(self, addr):
         self.socket.bind(addr)
 
     def listen(self, qlen=5):
         self.socket.listen(qlen)    
 
     def ssl_get_error(self, ret):
         return m2.ssl_get_error(self.ssl, ret)
 
diff -ru9N m2crypto-0.13/M2Crypto/SSL/Context.py m2crypto-0.13-heikki/M2Crypto/SSL/Context.py
--- m2crypto-0.13/M2Crypto/SSL/Context.py	2004-03-30 10:27:44.000000000 -0800
+++ m2crypto-0.13-heikki/M2Crypto/SSL/Context.py	2004-03-31 20:04:25.982072000 -0800
@@ -196,9 +196,12 @@
 
     def set_session_timeout(self, timeout):
         return m2.ssl_ctx_set_session_timeout(self.ctx, timeout)
 
     def set_session_cache_mode(self, mode):
         return m2.ssl_ctx_set_session_cache_mode(self.ctx, mode)
 
     def get_session_cache_mode(self):
         return m2.ssl_ctx_get_session_cache_mode(self.ctx)
+
+    def set_options(self, op):
+        return m2.ssl_ctx_set_options(self.ctx, op)
diff -ru9N m2crypto-0.13/M2Crypto/SSL/__init__.py m2crypto-0.13-heikki/M2Crypto/SSL/__init__.py
--- m2crypto-0.13/M2Crypto/SSL/__init__.py	2004-03-25 14:36:50.000000000 -0800
+++ m2crypto-0.13-heikki/M2Crypto/SSL/__init__.py	2004-03-31 20:45:29.304155200 -0800
@@ -20,9 +20,11 @@
 
 verify_none = m2.SSL_VERIFY_NONE
 verify_peer = m2.SSL_VERIFY_PEER
 verify_fail_if_no_peer_cert = m2.SSL_VERIFY_FAIL_IF_NO_PEER_CERT
 verify_client_once = m2.SSL_VERIFY_CLIENT_ONCE
 
 SSL_SENT_SHUTDOWN = m2.SSL_SENT_SHUTDOWN
 SSL_RECEIVED_SHUTDOWN = m2.SSL_RECEIVED_SHUTDOWN
 
+op_all = m2.SSL_OP_ALL
+op_no_sslv2 = m2.SSL_OP_NO_SSLv2
diff -ru9N m2crypto-0.13/M2Crypto/X509.py m2crypto-0.13-heikki/M2Crypto/X509.py
--- m2crypto-0.13/M2Crypto/X509.py	2004-03-24 13:46:38.000000000 -0800
+++ m2crypto-0.13-heikki/M2Crypto/X509.py	2004-03-31 21:29:17.102744000 -0800
@@ -4,35 +4,111 @@
 certificate operations (mainly attribute getters for 
 authentication purposes) from within an SSL connection.
 
 This module is emphatically not sufficient to implement CA-like
 functionality in Python. Given the availability of open source CA 
 tools such as OpenSSL's CA.[sh|pl], Oscar, IBM's XXX, it is 
 unlikely that this module will ever evolve to the aforementioned
 sufficiency.
 
-Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
+Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
+
+Portions Copyright (c) 2004 Open Source Applications Foundation.
+Author: Heikki Toivonen
+"""
 
 RCS_id='$Id: X509.py,v 1.11 2004/03/21 12:27:43 ngps Exp $'
 
 # M2Crypto
 import ASN1, BIO, Err
 import m2
 
 class X509Error(Exception): pass
 
 m2.x509_init(X509Error)
 
-#m2.x509_new()
-
 V_OK = m2.X509_V_OK
 
 
+class X509_Extension:
+	"""
+	X509 extension.
+
+	XXX Does not allow copying from existing extension.
+	"""
+	def __init__(self, name, value, critical=0):
+		self.x509_ext = m2.x509v3_ext_conf(None, None, name, value)
+		self.set_critical(critical)
+
+	def __del__(self):
+		m2.x509_extension_free(self.x509_ext)
+
+	def _ptr(self):
+		return self.x509_ext
+
+	def set_critical(self, critical=1):
+		"""
+		Mark this extension critical or noncritical. By default an
+		extension is not critical.
+
+		@type critical:  int
+		@param critical: Nonzero sets this extension as critical.
+                                 Calling this method without arguments will
+                                 set this extension to critical.
+		"""
+		return m2.x509_extension_set_critical(self.x509_ext, critical)
+
+	def get_critical(self):
+		"""
+		Return whether or not this is a critical extension.
+
+		@rtype:   int
+		@return:  Nonzero if this is a critical extension.
+		"""
+		return m2.x509_extension_get_critical(self.x509_ext)
+
+
+class X509_Extension_Stack:
+	def __init__(self, stack=None, _pyfree=0):
+		if stack is not None:
+			self.stack = stack
+			self._pyfree = _pyfree
+		else:
+			self.stack = m2.sk_x509_extension_new_null()
+			self._pyfree = 1
+		self._refkeeper = {}
+
+	def __del__(self):
+		if self._pyfree:
+			m2.sk_x509_extension_free(self.stack)
+
+	def __len__(self):
+		return m2.sk_x509_extension_num(self.stack)
+
+	# XXX How do I get the actual X509_EXTENSION from the stack?
+	#def __getitem__(self, idx):
+	#	if idx < 0 or idx >= m2.sk_x509_extension_num(self.stack):
+	#		raise IndexError, 'index out of range'
+	#	v=m2.sk_x509_extension_value(self.stack, idx)
+	#	return X509_Extension(v)
+
+	def _ptr(self):
+		return self.stack
+
+	def push(self, x509_ext):
+		self._refkeeper[x509_ext._ptr()] = x509_ext
+		return m2.sk_x509_extension_push(self.stack, x509_ext._ptr())
+
+	def pop(self):
+		x509__ext_ptr = m2.sk_x509_extension_pop(self.stack)
+		del self._refkeeper[x509_ext_ptr]
+
+
 class X509_Store_Context:
 	def __init__(self, x509_store_ctx, _pyfree=0):
 		self.ctx = x509_store_ctx
 		self._pyfree = _pyfree
 
 	#def __del__(self):
 	# XXX verify this method
 	#	 m2.x509_store_ctx_cleanup(self.ctx)
 
@@ -80,18 +156,19 @@
 	       'OU' : m2.NID_organizationalUnitName,
 	       'organizationUnitName' : m2.NID_organizationalUnitName,
 	       'CN' : m2.NID_commonName,
 	       'commonName' : m2.NID_commonName,
 	       'Email' : m2.NID_pkcs9_emailAddress,
 	       'emailAddress': m2.NID_pkcs9_emailAddress}
 
 	def __init__(self, x509_name=None, _pyfree=0):
 		if x509_name is not None:
+			assert m2.x509_name_type_check(x509_name), "'x509_name' type error"
 			self.x509_name = x509_name
 			self._pyfree = _pyfree
 		else:
 			self.x509_name = m2.x509_name_new ()
 			self._pyfree = 1
 
 	def __del__(self):
 		try:
 			if self._pyfree:
@@ -174,71 +251,148 @@
 		return buf.read_all()
 
 	def as_der(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		buf=BIO.MemoryBuffer()
 		m2.i2d_x509(buf.bio_ptr(), self.x509)
 		return buf.read_all()
 
 	def set_version(self, version):
+		"""
+		Set version.
+
+		@type version:  int
+		@param version: Version number.
+		@rtype:         int
+		@return:        Returns 0 on failure.
+		"""
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return m2.x509_set_version(self.x509, version)
 
 	def set_not_before(self, timeptr):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return m2.x509_set_not_before(self.x509, timeptr )
 
 	def set_not_after(self, timeptr):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return m2.x509_set_not_after(self.x509, timeptr )
 
 	def set_pubkey(self, pkey):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return m2.x509_set_pubkey(self.x509, pkey.pkey)
 
-	def set_subject_name(self, x509NamePtr):
+	def set_subject_name(self, name):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
-		return m2.x509_set_subject_name(self.x509, x509NamePtr)
+		return m2.x509_set_subject_name(self.x509, name.x509_name)
 
 	def set_issuer_name(self, x509NamePtr):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return m2.x509_set_issuer_name(self.x509, x509NamePtr)
 
 	def get_version(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return m2.x509_get_version(self.x509)
 
 	def get_serial_number(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		asn1_integer = m2.x509_get_serial_number(self.x509)
 		return m2.asn1_integer_get(asn1_integer)
 
+	def set_serial_number(self, serial):
+		"""
+		Set serial number. Every certificate must have a serial number.
+		A CA must issue unique serial numbers for all the certificates
+		that it issues.
+
+		@type serial:   int
+		@param serial:  Serial number.
+		"""
+		assert m2.x509_type_check(self.x509), "'x509' type error"
+		# This "magically" changes serial since asn1_integer
+		# is C pointer to x509's internal serial number.
+		asn1_integer = m2.x509_get_serial_number(self.x509)
+		return m2.asn1_integer_set(asn1_integer, serial)
+		# XXX Or should I do this?
+		#asn1_integer = m2.asn1_integer_new()
+		#m2.asn1_integer_set(asn1_integer, serial)
+		#return m2.x509_set_serial_number(self.x509, asn1_integer)
+
 	def get_not_before(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return ASN1.ASN1_UTCTIME(m2.x509_get_not_before(self.x509))
 
 	def get_not_after(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return ASN1.ASN1_UTCTIME(m2.x509_get_not_after(self.x509))
 
 	def get_pubkey(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return m2.x509_get_pubkey(self.x509)
 
+	def set_pubkey(self, pkey):
+		"""
+		Set the public key for the certificate
+
+		@type pkey:  EVP_PKEY
+		@param pkey: Public key
+		"""
+		assert m2.x509_type_check(self.x509), "'x509' type error"
+		return m2.x509_set_pubkey(self.x509, pkey.pkey)
+
 	def get_issuer(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return X509_Name(m2.x509_get_issuer_name(self.x509))
 
+	def set_issuer(self, name):
+		"""
+		Set issuer name.
+
+		@type name:     X509_Name
+		@param name:    subjectName field.
+		"""
+		assert m2.x509_type_check(self.x509), "'x509' type error"
+		return m2.x509_set_issuer_name(self.x509, name.x509_name)
+
 	def get_subject(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		return X509_Name(m2.x509_get_subject_name(self.x509))
 
+	def set_subject(self, name):
+		"""
+		Set subject name.
+
+		@type name:     X509_Name
+		@param name:    subjectName field.
+		"""
+		assert m2.x509_type_check(self.x509), "'x509' type error"
+		return m2.x509_set_subject_name(self.x509, name.x509_name)
+
+	def add_ext(self, ext):
+		"""
+		Add X509 extension to this certificate.
+
+		@type ext:     X509_Extension
+		@param ext:    Extension
+		"""
+		assert m2.x509_type_check(self.x509), "'x509' type error"
+		return m2.x509_add_ext(self.x509, ext.x509_ext, -1)
+
 	def sign(self, pkey, md):
+		"""
+		Sign the certificate.
+
+		@type pkey:  EVP_PKEY
+		@param pkey: Public key
+		@type md:    str
+		@param md:   Message digest algorithm to use for signing,
+		             for example 'sha1'.
+		"""
+		assert m2.x509_type_check(self.x509), "'x509' type error"
 		mda = getattr(m2, md)
 		if not mda:
 			raise ValueError, ('unknown message digest', md)
 		return m2.x509_sign(self.x509, pkey.pkey, mda())
 
 	def Print(self):
 		assert m2.x509_type_check(self.x509), "'x509' type error"
 		buf = BIO.MemoryBuffer()
 		m2.x509_print( buf.bio_ptr(), self.x509 )
@@ -313,18 +467,22 @@
 		self._refkeeper[x509._ptr()] = x509
 		return m2.sk_x509_push(self.stack, x509._ptr())
 
 	def pop(self):
 		x509_ptr = m2.sk_x509_pop(self.stack)
 		del self._refkeeper[x509_ptr]
 
 
 class Request:
+	"""
+	An X509 certificate request. A request is required to
+	make a certificate.
+	"""
 	def __init__(self, req=None, _pyfree=0):
 		if req is not None:
 			self.req = req
 			self._pyfree = _pyfree
 		else:
 			self.req = m2.x509_req_new()
 			self._pyfree = 1
 
 	def __del__(self):
@@ -339,30 +497,80 @@
 	def as_pem(self):
 		buf=BIO.MemoryBuffer()
 		m2.x509_req_write_pem(buf.bio_ptr(), self.req)
 		return buf.read_all()
 
 	def save_pem(self, filename):
 		bio=BIO.openfile(filename, 'wb')
 		return m2.x509_req_write_pem(bio.bio_ptr(), self.req)
 
+	def get_pubkey(self):
+		"""
+		Get the public key for the request.
+
+		@rtype:      EVP_PKEY
+		@return:     Public key from the request.
+		"""
+		return m2.x509_req_get_pubkey(self.req)
+
 	def set_pubkey(self, pkey):
+		"""
+		Set the public key for the request.
+
+		@type pkey:  EVP_PKEY
+		@param pkey: Public key
+		"""
 		return m2.x509_req_set_pubkey( self.req, pkey.pkey )
 
-	def set_subject_name(self, x509NamePtr):
-		return m2.x509_req_set_subject_name( self.req, x509NamePtr )
+	def get_version(self):
+		"""
+		Get version.
+
+		@rtype:         int
+		@return:        Returns version.
+		"""
+		return m2.x509_req_get_version(self.req)
 
-	def set_version(self):
+	def set_version(self, version):
+		"""
+		Set version.
+
+		@type version:  int
+		@param version: Version number.
+		@rtype:         int
+		@return:        Returns 0 on failure.
+		"""
 		return m2.x509_req_set_version( self.req, version )
 
 	def get_subject(self):
 		return X509_Name(m2.x509_req_get_subject_name( self.req ))
 
+	def set_subject_name(self, name):
+		"""
+		Set subject name.
+
+		@type name:     X509_Name
+		@param name:    subjectName field.
+		"""
+		return m2.x509_req_set_subject_name( self.req, name.x509_name )
+
+	def add_extensions(self, ext_stack):
+		"""
+		Add X509 extensions to this request.
+
+		@type ext_stack:  X509_Extension_Stack
+		@param ext_stack: Stack of extensions to add.
+		"""
+		return m2.x509_req_add_extensions(self.req, ext_stack._ptr())
+
+	def verify(self, pkey):
+		return m2.x509_req_verify(self.req, pkey)
+
 	def sign(self, pkey, md):
 		mda = getattr(m2, md)
 		if not mda:
 			raise ValueError, ('unknown message digest', md)
 		return m2.x509_req_sign(self.req, pkey.pkey, mda())
 
 def load_request(pemfile):
 	f=BIO.openfile(pemfile)
 	cptr=m2.x509_req_read_pem(f.bio_ptr())
diff -ru9N m2crypto-0.13/M2Crypto/m2.py m2crypto-0.13-heikki/M2Crypto/m2.py
--- m2crypto-0.13/M2Crypto/m2.py	2002-12-29 20:52:30.000000000 -0800
+++ m2crypto-0.13-heikki/M2Crypto/m2.py	2004-03-31 20:01:05.894360000 -0800
@@ -1,10 +1,32 @@
-"""M2Crypto
+"""M2Crypto low level OpenSSL wrapper functions.
 
-Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
+m2 is the low level wrapper for OpenSSL functions. Typically you would not
+need to use these directly, since these will be called by the higher level
+objects you should try to use instead.
+
+Naming conventions: All functions wrapped by m2 are all lower case,
+words separated by underscores.
+
+Examples:
+
+OpenSSL                   M2Crypto
+
+X509_get_version          m2.x509_get_version
+X509_get_notBefore        m2.x509_get_not_before
+X509_REQ_verify           m2.x509_req_verify
+
+Exceptions to naming rules:
+
+
+Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
+
+Portions created by Open Source Applications Foundation (OSAF) are
+Copyright (C) 2004 OSAF. All Rights Reserved.
+"""
 
 RCS_id='$Id: m2.py,v 1.3 2002/12/29 12:44:33 ngps Exp $'
 
 from __m2crypto import *
 lib_init()
 
 
diff -ru9N m2crypto-0.13/SWIG/_asn1.i m2crypto-0.13-heikki/SWIG/_asn1.i
--- m2crypto-0.13/SWIG/_asn1.i	2004-03-21 20:34:38.000000000 -0800
+++ m2crypto-0.13-heikki/SWIG/_asn1.i	2004-03-31 20:30:24.322856000 -0800
@@ -1,10 +1,14 @@
 /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.  */
+/*
+** Portions created by Open Source Applications Foundation (OSAF) are
+** Copyright (C) 2004 OSAF. All Rights Reserved.
+*/
 /* $Id: _asn1.i,v 1.2 2004/03/21 12:34:38 ngps Exp $ */
 
 %{
 #include <openssl/asn1.h>
 %}
 
 %apply Pointer NONNULL { BIO * };
 %apply Pointer NONNULL { ASN1_OBJECT * };
 %apply Pointer NONNULL { ASN1_STRING * };
@@ -24,17 +28,18 @@
 
 %name(asn1_utctime_new) extern ASN1_UTCTIME *ASN1_UTCTIME_new( void );
 %name(asn1_utctime_free) extern void ASN1_UTCTIME_free(ASN1_UTCTIME *);
 %name(asn1_utctime_check) extern int ASN1_UTCTIME_check(ASN1_UTCTIME *);
 %name(asn1_utctime_set) extern ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *, long);
 %name(asn1_utctime_set_string) extern int ASN1_UTCTIME_set_string(ASN1_UTCTIME *, char *);
 %name(asn1_utctime_print) extern int ASN1_UTCTIME_print(BIO *, ASN1_UTCTIME *);
 
 %name(asn1_integer_get) extern long ASN1_INTEGER_get(ASN1_INTEGER *);
+%name(asn1_integer_set) extern int ASN1_INTEGER_set(ASN1_INTEGER *, long);
 
 %inline %{
 /* ASN1_UTCTIME_set_string () is a macro */
 int asn1_utctime_type_check(ASN1_UTCTIME *ASN1_UTCTIME) {
     return 1;
 }
 
 %}
diff -ru9N m2crypto-0.13/SWIG/_ssl.i m2crypto-0.13-heikki/SWIG/_ssl.i
--- m2crypto-0.13/SWIG/_ssl.i	2004-03-25 12:41:12.000000000 -0800
+++ m2crypto-0.13-heikki/SWIG/_ssl.i	2004-03-31 20:12:26.753387200 -0800
@@ -1,10 +1,14 @@
 /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */
+/*
+** Portions created by Open Source Applications Foundation (OSAF) are
+** Copyright (C) 2004 OSAF. All Rights Reserved.
+*/
 /* $Id: _ssl.i,v 1.5 2004/03/21 12:36:20 ngps Exp $ */
 
 %{
 #include <pythread.h>
 #include <openssl/bio.h>
 #include <openssl/dh.h>
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 %}
@@ -44,20 +48,22 @@
 
 %name(bio_new_ssl) extern BIO *BIO_new_ssl(SSL_CTX *, int);
 
 %name(ssl_new) extern SSL *SSL_new(SSL_CTX *);
 %name(ssl_free) extern void SSL_free(SSL *);
 %name(ssl_dup) extern SSL *SSL_dup(SSL *);
 %name(ssl_set_bio) extern void SSL_set_bio(SSL *, BIO *, BIO *);
 %name(ssl_set_accept_state) extern void SSL_set_accept_state(SSL *);
 %name(ssl_set_connect_state) extern void SSL_set_connect_state(SSL *);
+%name(ssl_get_shutdown) extern int SSL_get_shutdown(SSL *);
 %name(ssl_set_shutdown) extern void SSL_set_shutdown(SSL *, int);
 %name(ssl_shutdown) extern int SSL_shutdown(SSL *);
+%name(ssl_clear) extern int SSL_clear(SSL *);
 %name(ssl_do_handshake) extern int SSL_do_handshake(SSL *);
 %name(ssl_renegotiate) extern int SSL_renegotiate(SSL *);
 %name(ssl_pending) extern int SSL_pending(SSL *);
 
 %name(ssl_get_peer_cert) extern X509 *SSL_get_peer_certificate(SSL *);
 %name(ssl_get_current_cipher) extern SSL_CIPHER *SSL_get_current_cipher(SSL *);
 %name(ssl_get_verify_mode) extern int SSL_get_verify_mode(SSL *);
 %name(ssl_get_verify_depth) extern int SSL_get_verify_depth(SSL *);
 %name(ssl_get_verify_result) extern long SSL_get_verify_result(SSL *);
@@ -111,18 +117,24 @@
 %constant int SSL_CB_ACCEPT_EXIT              = (SSL_ST_ACCEPT|SSL_CB_EXIT);
 %constant int SSL_CB_CONNECT_LOOP             = (SSL_ST_CONNECT|SSL_CB_LOOP);
 %constant int SSL_CB_CONNECT_EXIT             = (SSL_ST_CONNECT|SSL_CB_EXIT);
 %constant int SSL_CB_HANDSHAKE_START          = 0x10;
 %constant int SSL_CB_HANDSHAKE_DONE           = 0x20;
 
 %constant int SSL_SENT_SHUTDOWN	          = 1;
 %constant int SSL_RECEIVED_SHUTDOWN	  = 2;
 
+%constant int SSL_OP_ALL                  = 0x00000FFFL;
+
+%constant int SSL_OP_NO_SSLv2             = 0x01000000L;
+%constant int SSL_OP_NO_SSLv3             = 0x02000000L;
+%constant int SSL_OP_NO_TLSv1             = 0x04000000L;
+
 %inline %{
 static PyObject *_ssl_err;
 
 void ssl_init(PyObject *ssl_err) {
     SSL_library_init();
     SSL_load_error_strings();
     Py_INCREF(ssl_err);
     _ssl_err = ssl_err;
 }
@@ -233,18 +245,23 @@
     Py_INCREF(pyfunc);
     ssl_set_tmp_rsa_cb_func = pyfunc;
     SSL_CTX_set_tmp_rsa_callback(ctx, ssl_set_tmp_rsa_callback);
 }
 
 int ssl_ctx_load_verify_locations(SSL_CTX *ctx, const char *cafile, const char *capath) {
     return SSL_CTX_load_verify_locations(ctx, cafile, capath);
 }
 
+/* SSL_CTX_set_options is a macro. */
+long ssl_ctx_set_options(SSL_CTX *ctx, long op) {
+    return SSL_CTX_set_options(ctx, op);
+}
+
 int bio_set_ssl(BIO *bio, SSL *ssl, int flag) {
     SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
     return BIO_ctrl(bio, BIO_C_SET_SSL, flag, (char *)ssl);
 }
     
 void ssl_set_client_CA_list_from_file(SSL *ssl, const char *ca_file) {
     SSL_set_client_CA_list(ssl, SSL_load_client_CA_file(ca_file));
 }
 
diff -ru9N m2crypto-0.13/SWIG/_x509.i m2crypto-0.13-heikki/SWIG/_x509.i
--- m2crypto-0.13/SWIG/_x509.i	2004-03-21 20:37:46.000000000 -0800
+++ m2crypto-0.13-heikki/SWIG/_x509.i	2004-03-31 20:37:42.863446400 -0800
@@ -1,71 +1,83 @@
 /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.  */
+/*
+** Portions created by Open Source Applications Foundation (OSAF) are
+** Copyright (C) 2004 OSAF. All Rights Reserved.
+*/
 /* $Id: _x509.i,v 1.2 2004/03/21 12:37:46 ngps Exp $   */
 
 %{
 #include <openssl/x509.h>
+#include <openssl/x509v3.h>
 %}
 
 %apply Pointer NONNULL { BIO * };
 %apply Pointer NONNULL { X509 * };
 %apply Pointer NONNULL { X509_CRL * };
 %apply Pointer NONNULL { X509_REQ * };
 %apply Pointer NONNULL { X509_NAME * };
 %apply Pointer NONNULL { X509_NAME_ENTRY * };
 
 %name(x509_new) extern X509 *X509_new( void );
 %name(x509_free) extern void X509_free(X509 *);
 %name(x509_crl_free) extern void X509_CRL_free(X509_CRL *);
 
 %name(x509_print) extern int X509_print(BIO *, X509 *);
 %name(x509_crl_print) extern int X509_CRL_print(BIO *, X509_CRL *);
 
 %name(x509_get_serial_number) extern ASN1_INTEGER *X509_get_serialNumber(X509 *);
+%name(x509_set_serial_number) extern int X509_set_serialNumber(X509 *, ASN1_INTEGER *);
 %name(x509_get_pubkey) extern EVP_PKEY *X509_get_pubkey(X509 *);
-%name(x509_get_issuer_name) extern X509_NAME *X509_get_issuer_name(X509 *);
-%name(x509_get_subject_name) extern X509_NAME *X509_get_subject_name(X509 *);
 %name(x509_set_pubkey) extern int X509_set_pubkey(X509 *, EVP_PKEY *);
+%name(x509_get_issuer_name) extern X509_NAME *X509_get_issuer_name(X509 *);
 %name(x509_set_issuer_name) extern int X509_set_issuer_name(X509 *, X509_NAME *);
+%name(x509_get_subject_name) extern X509_NAME *X509_get_subject_name(X509 *);
 %name(x509_set_subject_name) extern int X509_set_subject_name(X509 *, X509_NAME *);
 
 %name(x509_get_verify_error) extern const char *X509_verify_cert_error_string(long);
 
+%name(x509_add_ext) extern int X509_add_ext(X509 *, X509_EXTENSION *, int);
+
 %name(x509_name_new) extern X509_NAME *X509_NAME_new( void );
 %name(x509_name_free) extern void X509_NAME_free(X509_NAME *);
 %name(x509_name_print) extern int X509_NAME_print(BIO *, X509_NAME *, int);
 %name(x509_name_get_entry) extern X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *, int);
 %name(x509_name_entry_count) extern int X509_NAME_entry_count(X509_NAME *);
 %name(x509_name_delete_entry) extern X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *, int);
 %name(x509_name_add_entry) extern int X509_NAME_add_entry(X509_NAME *, X509_NAME_ENTRY *, int, int);
 %name(x509_name_add_entry_by_obj) extern int X509_NAME_add_entry_by_OBJ(X509_NAME *, ASN1_OBJECT *, int, unsigned char *, int, int, int );
 %name(x509_name_add_entry_by_nid) extern int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, unsigned char *, int, int, int );
 
 %name(x509_name_entry_new) extern X509_NAME_ENTRY *X509_NAME_ENTRY_new( void );
 %name(x509_name_entry_free) extern void X509_NAME_ENTRY_free( X509_NAME_ENTRY *);
 %name(x509_name_entry_create_by_nid) extern X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID( X509_NAME_ENTRY **, int, int, unsigned char *, int);
 %name(x509_name_entry_set_object) extern int X509_NAME_ENTRY_set_object( X509_NAME_ENTRY *, ASN1_OBJECT *);
 %name(x509_name_entry_set_data) extern int X509_NAME_ENTRY_set_data( X509_NAME_ENTRY *, int, unsigned char *, int);
 %name(x509_name_entry_get_object) extern ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *);
 %name(x509_name_entry_get_data) extern ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *);
 
-
 %name(x509_req_new) extern X509_REQ * X509_REQ_new();
 %name(x509_req_free) extern void X509_REQ_free(X509_REQ *);
 %name(x509_req_print) extern int X509_REQ_print(BIO *, X509_REQ *);
+
+%name(x509_req_get_pubkey) extern EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *);
 %name(x509_req_set_pubkey) extern int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *);
 %name(x509_req_set_subject_name) extern int X509_REQ_set_subject_name(X509_REQ *, X509_NAME *);
 
 %name(i2d_x509) extern int i2d_X509_bio(BIO *, X509 *);
 
 %name(x509_store_new) extern X509_STORE *X509_STORE_new(void);
 %name(x509_store_free) extern void X509_STORE_free(X509_STORE *);
 %name(x509_store_add_cert) extern int X509_STORE_add_cert(X509_STORE *, X509 *);
 
+%name(x509_extension_get_critical) extern int X509_EXTENSION_get_critical(X509_EXTENSION *);
+%name(x509_extension_set_critical) extern int X509_EXTENSION_set_critical(X509_EXTENSION *, int);
+
 %constant int NID_commonName                  = 13;
 %constant int NID_countryName                 = 14;
 %constant int NID_localityName                = 15;
 %constant int NID_stateOrProvinceName         = 16;
 %constant int NID_organizationName            = 17;
 %constant int NID_organizationalUnitName      = 18;
 %constant int NID_pkcs9_emailAddress          = 48;
 
 /* Cribbed from x509_vfy.h. */
@@ -93,18 +105,22 @@
 %constant int		X509_V_ERR_CERT_CHAIN_TOO_LONG			= 22;
 %constant int		X509_V_ERR_CERT_REVOKED				= 23;
 %constant int		X509_V_ERR_INVALID_CA				= 24;
 %constant int		X509_V_ERR_PATH_LENGTH_EXCEEDED			= 25;
 %constant int		X509_V_ERR_INVALID_PURPOSE			= 26;
 %constant int		X509_V_ERR_CERT_UNTRUSTED			= 27;
 %constant int		X509_V_ERR_CERT_REJECTED			= 28;
 %constant int		X509_V_ERR_APPLICATION_VERIFICATION		= 50;
 
+/* Cribbed from rsa.h. */
+%constant int RSA_3                           = 0x3L;
+%constant int RSA_F4                          = 0x10001L;
+
 %inline %{
 static PyObject *_x509_err;
 
 void x509_init(PyObject *x509_err) {
     Py_INCREF(x509_err);
     _x509_err = x509_err;
 }
 
 X509 *x509_read_pem(BIO *bio) {
@@ -151,18 +167,23 @@
 /* X509_get_notAfter() is a macro. */
 ASN1_UTCTIME *x509_get_not_after(X509 *x) {
     return X509_get_notAfter(x);
 }
 
 int x509_sign(X509 *x, EVP_PKEY *pkey, EVP_MD *md) {
     return X509_sign(x, pkey, md);
 }
 
+/* XXX The first parameter is really ASN1_TIME, does it matter? */
+ASN1_TIME *x509_gmtime_adj(ASN1_UTCTIME *s, long adj) {
+    return X509_gmtime_adj(s, adj);
+}
+
 /*
 Blob *x509_name_by_nid(X509_NAME *name, int nid) {
     Blob *blob;
     int buflen;
 
     buflen = X509_NAME_get_text_by_NID(name, nid, NULL, 0);
     if (buflen == -1) {
         return NULL;
     }
@@ -236,26 +257,81 @@
 
 int x509_name_type_check(X509_NAME *name) {
     return 1;
 }
 
 X509_NAME *x509_req_get_subject_name(X509_REQ *x) {
     return X509_REQ_get_subject_name(x);
 }
 
+long x509_req_get_version(X509_REQ *x) {
+    return X509_REQ_get_version(x);
+}
+
+int x509_req_set_version(X509_REQ *x, long version) {
+    return X509_REQ_set_version(x, version);
+}
+
+int x509_req_add_extensions(X509_REQ *req, STACK *exts) {
+    return X509_REQ_add_extensions(req, (STACK_OF(X509_EXTENSION) *)exts);
+}
+
 int x509_req_sign(X509_REQ *x, EVP_PKEY *pkey, EVP_MD *md) {
     return X509_REQ_sign(x, pkey, md);
 }
 
+/* X509_REQ_verify could be a define */
+int x509_req_verify(X509_REQ *x, EVP_PKEY *pkey) {
+    return X509_REQ_verify(x, pkey);
+}
+
 X509_NAME_ENTRY *x509_name_entry_create_by_txt( X509_NAME_ENTRY **ne, char *field, int type, unsigned char *bytes, int len) {
 	return X509_NAME_ENTRY_create_by_txt( ne, field, type, bytes, len);
 }
 
+X509_EXTENSION *x509v3_ext_conf(LHASH *conf, X509V3_CTX *ctx, char *name, char *value) {
+    return X509V3_EXT_conf(conf, ctx, name, value);
+}
+
+/* X509_EXTENSION_free() might be a macro, didn't find definition. */
+void x509_extension_free(X509_EXTENSION *ext) {
+    X509_EXTENSION_free(ext);
+}
+
+/* sk_X509_EXTENSION_new_null is a macro. */
+STACK *sk_x509_extension_new_null(void) {
+    return (STACK *)sk_X509_EXTENSION_new_null();
+}
+
+/* sk_X509_EXTENSION_free() is a macro. */
+void sk_x509_extension_free(STACK *stack) {
+    sk_X509_EXTENSION_free((STACK_OF(X509_EXTENSION) *)stack);
+}
+
+/* sk_X509_EXTENSION_push() is a macro. */
+int sk_x509_extension_push(STACK *stack, X509_EXTENSION *x509_ext) {
+    return sk_X509_EXTENSION_push((STACK_OF(X509_EXTENSION) *)stack, x509_ext);
+}
+
+/* sk_X509_EXTENSION_pop() is a macro. */
+X509_EXTENSION *sk_x509_extension_pop(STACK *stack) {
+    return sk_X509_EXTENSION_pop((STACK_OF(X509_EXTENSION) *)stack);
+}
+
+/* sk_X509_EXTENSION_num() is a macro. */
+int sk_x509_extension_num(STACK *stack) {
+    return sk_X509_EXTENSION_num((STACK_OF(X509_EXTENSION) *)stack);
+}
+
+/* sk_X509_EXTENSION_value() is a macro. */
+char *sk_x509_extension_value(STACK *stack, int i) {
+    return sk_X509_EXTENSION_value((STACK_OF(X509_EXTENSION) *)stack, i);
+}
 %}
 
 /* Free malloc'ed return value for x509_name_oneline */
 %typemap(python, ret) char * {
     if ($1 != NULL)
         free($1);
 }
 %inline %{
 char *x509_name_oneline(X509_NAME *x) {
diff -ru9N m2crypto-0.13/demo/ssl/client3.py m2crypto-0.13-heikki/demo/ssl/client3.py
--- m2crypto-0.13/demo/ssl/client3.py	1969-12-31 16:00:00.000000000 -0800
+++ m2crypto-0.13-heikki/demo/ssl/client3.py	2004-03-31 20:06:54.095048000 -0800
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+"""
+client3 from the book 'Network Security with OpenSSL', but modified to
+Python/M2Crypto from the original C implementation.
+
+Copyright (c) 2004 Open Source Applications Foundation.
+Author: Heikki Toivonen
+"""
+import sys
+from M2Crypto import SSL, Rand
+
+verbose_debug = 1
+
+def verify_callback(ok, store):
+    print '***Is this ever called?' # XXX
+    if not ok:
+        print "***Verify Not ok"
+    return ok
+
+def setup_client_ctx():
+    ctx = SSL.Context('sslv23')
+    if ctx.load_verify_locations('ca.pem') != 1:
+        print "***No CA file"
+    #if ctx.set_default_verify_paths() != 1:
+    #    print "***No default verify paths"
+    ctx.load_cert_chain('client.pem')
+    ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert,
+                   10, verify_callback)
+    ctx.set_options(SSL.op_all | SSL.op_no_sslv2)
+    if ctx.set_cipher_list('ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH') != 1:
+        print "***No valid ciphers"
+    if verbose_debug:
+        ctx.set_info_callback()
+    return ctx
+
+def post_connection_check(conn):
+    cert = conn.get_peer_cert()
+    if cert is None:
+        print "***No peer certificate"
+    # Not sure if we can do any other checks
+
+def do_client_loop(conn):
+    while 1:
+        buf = sys.stdin.readline()
+        if not buf: 
+            break
+        if conn.write(buf) <= 0:
+            return 0
+    return 1
+
+if __name__=='__main__':
+    print 'press enter' # XXX hack to get later readline() working
+    sys.stdin.readline()# XXX
+    Rand.load_file('../randpool.dat', -1)
+    ctx = setup_client_ctx()
+    conn = SSL.Connection(ctx)
+    if conn.connect(('127.0.0.1', 9999)) < 0:
+        print "***Connection error"
+    post_connection_check(conn)
+
+    print 'SSL Connection opened'
+    if do_client_loop(conn):
+        conn.close()
+    else:
+        conn.clear()
+    print 'SSL Connection closed'
diff -ru9N m2crypto-0.13/demo/ssl/server3.py m2crypto-0.13-heikki/demo/ssl/server3.py
--- m2crypto-0.13/demo/ssl/server3.py	1969-12-31 16:00:00.000000000 -0800
+++ m2crypto-0.13-heikki/demo/ssl/server3.py	2004-03-31 20:07:00.794681600 -0800
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+"""
+server3 from the book 'Network Security with OpenSSL', but modified to
+Python/M2Crypto from the original C implementation.
+
+Copyright (c) 2004 Open Source Applications Foundation.
+Author: Heikki Toivonen
+"""
+from M2Crypto import SSL, Rand, threading
+import thread
+from socket import *
+
+verbose_debug = 1
+
+def verify_callback(ok, store):
+    if not ok:
+        print "***Verify Not ok"
+    return ok
+
+dh1024 = None
+
+def init_dhparams():
+    dh1024 = DH.load_params('dh1024.pem')
+
+def tmp_dh_callback(ssl, is_export, keylength):
+    if not dh1024:
+        init_dhparams()
+    return dh1024
+
+def setup_server_ctx():
+    ctx = SSL.Context('sslv23')
+    if ctx.load_verify_locations('ca.pem') != 1:
+        print "***No CA file"
+    #if ctx.set_default_verify_paths() != 1:
+    #    print "***No default verify paths"
+    ctx.load_cert_chain('server.pem')
+    ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert,
+                   10)#, verify_callback) # XXX Crash with callback
+    ctx.set_options(SSL.op_all | SSL.op_no_sslv2)
+    #ctx.set_tmp_dh_callback(tmp_dh_callback)# XXX This causes crash
+    ctx.set_tmp_dh('dh1024.pem')
+    if ctx.set_cipher_list('ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH') != 1:
+        print "***No valid ciphers"
+    if verbose_debug:
+        ctx.set_info_callback()
+    return ctx
+
+def post_connection_check(conn):
+    cert = conn.get_peer_cert()
+    if cert is None:
+        print "***No peer certificate"
+    # Not sure if we can do any other checks
+
+def do_server_loop(conn):
+    while 1:
+        try:
+            buf = conn.read()
+            if not buf:
+                break
+            print buf
+        except SSL.SSLError, what:
+            if str(what) == 'unexpected eof':
+                break
+            else:
+                raise
+        except:
+            break
+            
+    if conn.get_shutdown():
+        return 1
+    return 0
+
+# How about something like:
+#def server_thread(ctx, ssl, addr):
+#    conn = SSL.Connection(ctx, None)
+#    conn.ssl = ssl
+#    conn.setup_addr(addr)
+def server_thread(ctx, sock, addr):
+    conn = SSL.Connection(ctx, sock)
+    conn.setup_addr(addr)
+    conn.set_accept_state()
+    conn.setup_ssl()
+    conn.accept_ssl()
+    
+    post_connection_check(conn)
+
+    print 'SSL Connection opened'
+    if do_server_loop(conn):
+        conn.close()
+    else:
+        conn.clear()
+    print 'SSL Connection closed'        
+    
+
+if __name__=='__main__':
+    threading.init()
+    Rand.load_file('../randpool.dat', -1) 
+
+    ctx = setup_server_ctx()
+
+    # How about something like this?
+    #conn_root = SSL.Connection(ctx)
+    #conn_root.bind(('127.0.0.1', 9999))
+    #conn_root.listen(5)
+    #while 1:
+    #    ssl, addr = conn_root.accept()
+    #    thread.start_new_thread(server_thread, (ctx, ssl, addr))
+
+    sock = socket(AF_INET, SOCK_STREAM)
+    sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
+    sock.bind(('', 9999))
+    sock.listen(5)
+    while 1:
+        conn, addr = sock.accept()
+        thread.start_new_thread(server_thread, (ctx, conn, addr))
+ 
+    Rand.save_file('../randpool.dat')
+    threading.cleanup()
diff -ru9N m2crypto-0.13/demo/x509/ca.py m2crypto-0.13-heikki/demo/x509/ca.py
--- m2crypto-0.13/demo/x509/ca.py	1969-12-31 16:00:00.000000000 -0800
+++ m2crypto-0.13-heikki/demo/x509/ca.py	2004-03-31 21:27:10.901275200 -0800
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+
+"""
+How to create a CA certificate with Python.
+
+WARNING: This sample only demonstrates how to use the objects and methods,
+         not how to create a safe and correct certificate.
+
+Copyright (c) 2004 Open Source Applications Foundation.
+Author: Heikki Toivonen
+"""
+
+from M2Crypto import RSA, X509, EVP, m2, Rand, Err
+
+# XXX Do I actually need more keys?
+# XXX Check return values from functions
+
+def generateRSAKey():
+    return RSA.gen_key(2048, m2.RSA_F4)
+
+def makePKey(key):
+    pkey = EVP.PKey()
+    pkey.assign_rsa(key)
+    return pkey
+    
+def makeRequest(pkey):
+    req = X509.Request()
+    # Seems to default to 0, but we can now set it as well, so just API test
+    req.set_version(req.get_version())
+    req.set_pubkey(pkey)
+    req.set_pubkey(EVP.PKey(req.get_pubkey()))# Just a test of the API
+    name = X509.X509_Name()
+    name.CN = 'My CA, Inc.'
+    req.set_subject_name(name)
+    ext1 = X509.X509_Extension('subjectAltName', 'DNS:foobar.example.com')
+    ext2 = X509.X509_Extension('nsComment', 'Hello there')
+    extstack = X509.X509_Extension_Stack()
+    extstack.push(ext1)
+    extstack.push(ext2)
+    req.add_extensions(extstack)
+    req.sign(pkey, 'sha1')
+    return req
+
+def makeCert(req, caPkey):
+    pkey = req.get_pubkey()
+    #woop = makePKey(generateRSAKey())
+    #if not req.verify(woop.pkey):
+    if not req.verify(pkey):
+        # XXX What error object should I use?
+        raise ValueError, 'Error verifying request'
+    sub = req.get_subject()
+    # If this were a real certificate request, you would display
+    # all the relevant data from the request and ask a human operator
+    # if you were sure. Now we just create the certificate blindly based
+    # on the request.
+    cert = X509.X509()
+    # We know we are making CA cert now...
+    # Serial defaults to 0.
+    cert.set_serial_number(1)
+    cert.set_version(2)
+    cert.set_subject_name(sub)
+    issuer = X509.X509_Name()
+    issuer.CN = 'The Issuer Monkey'
+    issuer.O = 'The Organization Otherwise Known as My CA, Inc.'
+    cert.set_issuer(issuer)
+    cert.set_pubkey(EVP.PKey(pkey))
+    cert.set_pubkey(EVP.PKey(cert.get_pubkey()))# Just a test of the API
+    notBefore = m2.x509_get_not_before(cert.x509)
+    notAfter  = m2.x509_get_not_after(cert.x509)
+    m2.x509_gmtime_adj(notBefore, 0)
+    days = 30
+    m2.x509_gmtime_adj(notAfter, 60*60*24*days)
+    cert.add_ext(
+        X509.X509_Extension('subjectAltName', 'DNS:foobar.example.com'))
+    ext = X509.X509_Extension('nsComment', 'M2Crypto generated certificate')
+    ext.set_critical(0)# Defaults to non-critical, but we can also set it
+    cert.add_ext(ext)
+    cert.sign(caPkey, 'sha1')
+    return cert
+
+def ca():
+    key = generateRSAKey()
+    pkey = makePKey(key)
+    req = makeRequest(pkey)
+    cert = makeCert(req, pkey)
+    return (cert, pkey)
+
+if __name__ == '__main__':
+    Rand.load_file('../randpool.dat', -1)
+    key = generateRSAKey()
+    pkey = makePKey(key)
+    req = makeRequest(pkey)
+    print req.as_text()
+    cert = makeCert(req, pkey)
+    print cert.as_text()
+    Rand.save_file('../randpool.dat')
diff -ru9N m2crypto-0.13/demo/x509/fingerprint.py m2crypto-0.13-heikki/demo/x509/fingerprint.py
--- m2crypto-0.13/demo/x509/fingerprint.py	1969-12-31 16:00:00.000000000 -0800
+++ m2crypto-0.13-heikki/demo/x509/fingerprint.py	2004-03-31 20:06:21.408046400 -0800
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+"""
+How to create the fingerprint of a certificate with Python.
+
+Copyright (c) 2004 Open Source Applications Foundation.
+Author: Heikki Toivonen
+"""
+
+import os
+from M2Crypto import X509, util
+from M2Crypto.EVP import MessageDigest
+
+def test():
+    cmd = os.popen('openssl x509 -fingerprint -sha1 -noout -in server.pem')
+    expected = cmd.read()
+    expected = expected[expected.find('=')+1:].strip()
+
+    cert = X509.load_cert('server.pem')
+    der = cert.as_der()
+    md = MessageDigest('sha1')
+    md.update(der)
+    digest = md.final()
+    
+    hexstr = hex(util.octx_to_num(digest))
+    fingerprint = hexstr[2:len(hexstr)-1]
+    list = [fingerprint[x:x+2] for x in range(len(fingerprint)) if x%2 == 0]
+    fingerprint = ':'.join(list)
+    
+    if expected == fingerprint:
+        print "Fingerprint matched"
+    else:
+        print "Unexpected fingerprint"
+        print "Expected: ", expected
+        print "Got:      ", fingerprint
+
+if __name__ == "__main__":
+    test()
diff -ru9N m2crypto-0.13/demo/x509/other.py m2crypto-0.13-heikki/demo/x509/other.py
--- m2crypto-0.13/demo/x509/other.py	1969-12-31 16:00:00.000000000 -0800
+++ m2crypto-0.13-heikki/demo/x509/other.py	2004-03-31 21:30:47.192286400 -0800
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+
+"""
+How to create a non-CA certificate with Python.
+
+WARNING: This sample only demonstrates how to use the objects and methods,
+         not how to create a safe and correct certificate.
+
+Copyright (c) 2004 Open Source Applications Foundation.
+Author: Heikki Toivonen
+"""
+
+from M2Crypto import RSA, X509, EVP, m2, Rand, Err
+import ca
+
+# XXX Do I actually need more keys?
+# XXX Check return values from functions
+
+def generateRSAKey():
+    return RSA.gen_key(2048, m2.RSA_F4)
+
+def makePKey(key):
+    pkey = EVP.PKey()
+    pkey.assign_rsa(key)
+    return pkey
+    
+def makeRequest(pkey):
+    req = X509.Request()
+    req.set_version(0)# Seems to default to 0, but we can now set it as well
+    req.set_pubkey(pkey)
+    name = X509.X509_Name()
+    name.CN = 'Some Individual'
+    req.set_subject_name(name)
+    # XXX Extensions
+    req.sign(pkey, 'sha1')
+    return req
+
+def makeCert(req, caCert, caPKey):
+    pkey = req.get_pubkey()
+    #woop = makePKey(generateRSAKey())
+    #if not req.verify(woop.pkey):
+    if not req.verify(pkey):
+        # XXX What error object should I use?
+        raise ValueError, 'Error verifying request'
+    sub = req.get_subject()
+    # If this were a real certificate request, you would display
+    # all the relevant data from the request and ask a human operator
+    # if you were sure. Now we just create the certificate blindly based
+    # on the request.
+    cert = X509.X509()
+    cert.set_version(2)
+    cert.set_serial_number(caCert.get_serial_number()+1)
+    print '***Serial: ', cert.get_serial_number()
+    cert.set_subject_name(sub)
+    issuer = caCert.get_subject()
+    cert.set_issuer(issuer)
+    cert.set_pubkey(EVP.PKey(pkey))
+    notBefore = m2.x509_get_not_before(cert.x509)
+    notAfter  = m2.x509_get_not_after(cert.x509)
+    m2.x509_gmtime_adj(notBefore, 0)
+    days = 30
+    m2.x509_gmtime_adj(notAfter, 60*60*24*days)
+    # XXX extensions
+    cert.sign(caPKey, 'sha1')
+    return cert
+
+if __name__ == '__main__':
+    Rand.load_file('../randpool.dat', -1)
+    key = generateRSAKey()
+    pkey = makePKey(key)
+    req = makeRequest(pkey)
+    print req.as_text()
+    (caCert, caPKey) = ca.ca()
+    cert = makeCert(req, caCert, caPKey)
+    print cert.as_text()
+    Rand.save_file('../randpool.dat')
signature.asc (application/pgp-signature, 249 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFAa7Nfb8x8KoP+JuwRAqYGAJ463dSpvZASax33F8TWJRM5T+c+RQCbBMKR
e8FtqGis1i2W1nwYoEar1vM=
=WrM6
-----END PGP SIGNATURE-----
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.