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