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')
