Merge lp:~rick-fdd/pyopenssl/subject_and_issuer2 into lp:~exarkun/pyopenssl/trunk

Proposed by rick_dean
Status: Merged
Merged at revision: not available
Proposed branch: lp:~rick-fdd/pyopenssl/subject_and_issuer2
Merge into: lp:~exarkun/pyopenssl/trunk
Diff against target: None lines
To merge this branch: bzr merge lp:~rick-fdd/pyopenssl/subject_and_issuer2
Reviewer Review Type Date Requested Status
Jean-Paul Calderone Pending
Review via email: mp+8896@code.launchpad.net
To post a comment you must log in.
Revision history for this message
rick_dean (rick-fdd) wrote :

This new functionality is critical for generating root x509v3 certificates. It includes documentation and test cases. The actual patch is tiny like a good design should be.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/pyOpenSSL.tex'
2--- doc/pyOpenSSL.tex 2009-07-04 20:15:36 +0000
3+++ doc/pyOpenSSL.tex 2009-07-08 21:17:17 +0000
4@@ -188,8 +188,11 @@
5 See \class{X509Extension}.
6 \end{datadesc}
7
8-\begin{classdesc}{X509Extension}{typename, critical, value}
9-A class representing an X.509 v3 certificate extensions.
10+\begin{classdesc}{X509Extension}{typename, critical, value\optional{, subject}\optional{, issuer}}
11+A class representing an X.509 v3 certificate extensions.
12+See \url{http://openssl.org/docs/apps/x509v3_config.html\#STANDARD_EXTENSIONS}
13+for \var{typename} strings and their options.
14+Optional parameters \var{subject} and \var{issuer} must be X509 objects.
15 \end{classdesc}
16
17 \begin{datadesc}{NetscapeSPKIType}
18
19=== modified file 'src/crypto/crypto.h'
20--- src/crypto/crypto.h 2009-04-01 16:58:26 +0000
21+++ src/crypto/crypto.h 2009-07-08 21:17:17 +0000
22@@ -58,7 +58,7 @@
23
24 #define crypto_X509Extension_New_NUM 5
25 #define crypto_X509Extension_New_RETURN crypto_X509ExtensionObj *
26-#define crypto_X509Extension_New_PROTO (char *, int, char *)
27+#define crypto_X509Extension_New_PROTO (char *, int, char *, crypto_X509Obj *, crypto_X509Obj *)
28
29 #define crypto_PKCS7_New_NUM 6
30 #define crypto_PKCS7_New_RETURN crypto_PKCS7Obj *
31
32=== modified file 'src/crypto/x509ext.c'
33--- src/crypto/x509ext.c 2009-06-27 15:17:28 +0000
34+++ src/crypto/x509ext.c 2009-07-08 21:17:17 +0000
35@@ -75,7 +75,8 @@
36 * Returns: The newly created X509Extension object
37 */
38 crypto_X509ExtensionObj *
39-crypto_X509Extension_New(char *type_name, int critical, char *value)
40+crypto_X509Extension_New(char *type_name, int critical, char *value,
41+ crypto_X509Obj *subject, crypto_X509Obj *issuer)
42 {
43 X509V3_CTX ctx;
44 crypto_X509ExtensionObj *self;
45@@ -84,7 +85,12 @@
46 /* We have no configuration database - but perhaps we should. Anyhow, the
47 * context is necessary for any extension which uses the r2i conversion
48 * method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx. */
49+ X509V3_set_ctx(&ctx, NULL, NULL, NULL, NULL, 0);
50 X509V3_set_ctx_nodb(&ctx);
51+ if(subject)
52+ ctx.subject_cert = subject->x509;
53+ if(issuer)
54+ ctx.issuer_cert = issuer->x509;
55
56 self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type);
57
58@@ -137,27 +143,40 @@
59 }
60
61 static char crypto_X509Extension_doc[] = "\n\
62-X509Extension(typename, critical, value) -> X509Extension instance\n\
63+X509Extension(typename, critical, value[, subject][, issuer]) -> \n\
64+ X509Extension instance\n\
65 \n\
66 @param typename: The name of the extension to create.\n\
67 @type typename: C{str}\n\
68 @param critical: A flag indicating whether this is a critical extension.\n\
69 @param value: The value of the extension.\n\
70 @type value: C{str}\n\
71+@param subject: Optional X509 cert to use as subject.\n\
72+@type subject: C{X509}\n\
73+@param issuer: Optional X509 cert to use as issuer.\n\
74+@type issuer: C{X509}\n\
75 @return: The X509Extension object\n\
76 ";
77
78 static PyObject *
79-crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
80+crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args,
81+ PyObject *kwargs) {
82 char *type_name, *value;
83- int critical;
84+ int critical = 0;
85+ crypto_X509Obj * subject = NULL;
86+ crypto_X509Obj * issuer = NULL;
87+ static char *kwlist[] = {"type_name", "critical", "value", "subject",
88+ "issuer", NULL};
89
90- if (!PyArg_ParseTuple(args, "sis:X509Extension", &type_name, &critical,
91- &value)) {
92+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sis|O!O!:X509Extension",
93+ kwlist, &type_name, &critical, &value,
94+ &crypto_X509_Type, &subject,
95+ &crypto_X509_Type, &issuer )) {
96 return NULL;
97 }
98
99- return (PyObject *)crypto_X509Extension_New(type_name, critical, value);
100+ return (PyObject *)crypto_X509Extension_New(type_name, critical, value,
101+ subject, issuer);
102 }
103
104 /*
105
106=== modified file 'test/test_crypto.py'
107--- test/test_crypto.py 2009-07-05 16:54:05 +0000
108+++ test/test_crypto.py 2009-07-08 21:17:17 +0000
109@@ -7,6 +7,7 @@
110 from unittest import main
111
112 from os import popen2
113+from datetime import datetime, timedelta
114
115 from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
116 from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
117@@ -234,6 +235,51 @@
118 self.assertEqual(ext.get_short_name(), 'nsComment')
119
120
121+ def test_issuer_and_subject(self):
122+ """
123+ Use L{X509Extension} to create a root cert with X509v3
124+ extensions, which requires the "subject" or "issuer" optional args.
125+ """
126+ # Basic setup stuff to generate a certificate
127+ pkey = PKey()
128+ pkey.generate_key(TYPE_RSA, 1024)
129+ req = X509Req()
130+ req.set_pubkey(pkey)
131+ req.get_subject().commonName = "Yoda root CA" # Authority good you have.
132+ x509 = X509()
133+ subject = x509.get_subject()
134+ subject.commonName = req.get_subject().commonName
135+ x509.set_issuer(subject)
136+ x509.set_pubkey(pkey)
137+ now = datetime.now().strftime("%Y%m%d%H%M%SZ")
138+ expire = (datetime.now() + timedelta(days=100)).strftime("%Y%m%d%H%M%SZ")
139+ x509.set_notBefore(now)
140+ x509.set_notAfter(expire)
141+ # Test "subject" as a unneeded parameter
142+ ext1 = X509Extension('basicConstraints', False, 'CA:TRUE', subject=x509)
143+ x509.add_extensions( (ext1, ) )
144+ # Correct use of "subject" and "issuer"
145+ ext3 = X509Extension('subjectKeyIdentifier', False, 'hash', subject=x509, )
146+ x509.add_extensions( (ext3, ) )
147+ ext2 = X509Extension('authorityKeyIdentifier', False, 'keyid:always,issuer:always', issuer=x509, )
148+ x509.add_extensions( (ext2, ) )
149+ # Test missing issuer
150+ self.assertRaises(Error, X509Extension, 'authorityKeyIdentifier', False, 'keyid:always,issuer:always', )
151+ # Test missing subject
152+ self.assertRaises(Error, X509Extension, 'subjectKeyIdentifier', False, 'hash', )
153+ # Test bad type of issuer and subject
154+ self.assertRaises(TypeError, eval,
155+ "OpenSSL.crypto.X509Extension('basicConstraints', False, 'CA:TRUE', subject=True)", ())
156+ self.assertRaises(TypeError, eval,
157+ "OpenSSL.crypto.X509Extension('basicConstraints', False, 'CA:TRUE', issuer=3)", ())
158+ # Complete the certificate
159+ x509.sign(pkey, 'sha1')
160+ # Verify the certificate
161+ text = dump_certificate(FILETYPE_TEXT, x509)
162+ self.assertTrue( text.index('X509v3 Subject Key Identifier') > 100 )
163+ self.assertTrue( text.index('X509v3 Authority Key Identifier') > 100 )
164+
165+
166
167 class PKeyTests(TestCase):
168 """
169
170=== modified file 'test/util.py'
171--- test/util.py 2009-07-05 17:05:45 +0000
172+++ test/util.py 2009-07-08 21:17:17 +0000
173@@ -11,6 +11,7 @@
174 import os, os.path
175 from tempfile import mktemp
176 from unittest import TestCase
177+import sys
178
179
180 class TestCase(TestCase):
181@@ -81,10 +82,10 @@
182 except exception, inst:
183 return inst
184 except:
185- raise self.failureException('%s raised instead of %s:\n %s'
186+ raise self.failureException('%s raised instead of %s'
187 % (sys.exc_info()[0],
188 exception.__name__,
189- failure.Failure().getTraceback()))
190+ ))
191 else:
192 raise self.failureException('%s not raised (%r returned)'
193 % (exception.__name__, result))

Subscribers

People subscribed via source and target branches

to status/vote changes: