merge in trunk to help with the pkcs12 type unit tests a bit
diff --git a/ChangeLog b/ChangeLog
index 98ae8ff..d9d45f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-07-17 Rick Dean <rick@fdd.com>
+ Jean-Paul Calderone <exarkun@twistedmatrix.com>
+
+ * src/crypto/x509ext.c: Add subject and issuer parameters to
+ X509Extension, allowing creation of extensions which require that
+ information. Fixes LP#322813.
+
2009-07-16 Jean-Paul Calderone <exarkun@twistedmatrix.com>
* test/util.py: Changed the base TestCase's tearDown to assert that
diff --git a/INSTALL b/INSTALL
index 793b9bb..b650ba6 100644
--- a/INSTALL
+++ b/INSTALL
@@ -11,47 +11,59 @@
pyOpenSSL uses distutils, so there really shouldn't be any problems. To build
the library:
- python setup.py build
+ $ python setup.py build
If your OpenSSL header files aren't in /usr/include, you may need to supply
the -I flag to let the setup script know where to look. The same goes for the
libraries of course, use the -L flag. Note that build won't accept these
flags, so you have to run first build_ext and then build! Example:
- python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib
- python setup.py build
+ $ python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib
+ $ python setup.py build
Now you should have a directory called OpenSSL that contains e.g. SSL.so and
__init__.py somewhere in the build dicrectory, so just:
- python setup.py install
+ $ python setup.py install
If you, for some arcane reason, don't want the module to appear in the
site-packages directory, use the --prefix option.
You can, of course, do
- python setup.py --help
+ $ python setup.py --help
to find out more about how to use the script.
-- Building the Module on a Windows System --
-Big thanks to Itamar Shtull-Trauring and Oleg Orlov for their help with
-Windows build instructions. Same as for Unix systems, we have to separate
-the build_ext and the build.
+pyOpenSSL is known to build with mingw32 for Python 2.3 through Python 2.5.
+For Python 2.6, the official Windows installer of which is built with
+Microsoft Visual Studio 2008 (version 9.0), Microsoft Visual Studio 2008
+(version 9.0) is required. You can specify that mingw32 be used by passing
+the --compiler argument to build_ext. You will also need to specify the
+location of the OpenSSL headers and libraries:
-Building the library:
+ C:\pyOpenSSL-X.Y> setup.py build_ext -c mingw32 -I C:\OpenSSL\include ^
+ -L C:\OpenSSL bdist_msi
- setup.py build_ext -I ...\openssl\inc32 -L ...\openssl\out32dll
- setup.py build
+The correct header and library paths depend on how you have OpenSSL
+installed. The above paths are correct for the default installation of
+(<http://www.slproweb.com/products/Win32OpenSSL.html>).
-Where ...\openssl is of course the location of your OpenSSL installation.
+The bdist_msi command will build an MSI installer. It can be substituted
+with another bdist command if another kind of installer is desired.
-Installation is the same as for Unix systems:
+To build with MSVC instead, omit the -c option and pass a slightly different
+library directory:
- setup.py install
+ C:\pyOpenSSL-X.Y> setup.py build_ext -I C:\OpenSSL\include ^
+ -L C:\OpenSSL\lib bdist_msi
+
+The resulting binary distribution will be placed in the dist directory. To
+install it, dDepending on what kind of distribution you create, run it,
+unzip it, or copy it to Python installation's site-packages.
And similarily, you can do
@@ -59,6 +71,9 @@
to get more information.
+Big thanks to Itamar Shtull-Trauring, Oleg Orlov, Zooko O'Whielacronx, Chris
+Galvan, and #python and #distutils on FreeNode for their help with Windows
+build instructions.
-- Documentation --
diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex
index 3d2ce8f..cea48e9 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -188,8 +188,11 @@
See \class{X509Extension}.
\end{datadesc}
-\begin{classdesc}{X509Extension}{typename, critical, value}
-A class representing an X.509 v3 certificate extensions.
+\begin{classdesc}{X509Extension}{typename, critical, value\optional{, subject}\optional{, issuer}}
+A class representing an X.509 v3 certificate extensions.
+See \url{http://openssl.org/docs/apps/x509v3_config.html\#STANDARD_EXTENSIONS}
+for \var{typename} strings and their options.
+Optional parameters \var{subject} and \var{issuer} must be X509 objects.
\end{classdesc}
\begin{datadesc}{NetscapeSPKIType}
diff --git a/setup.py b/setup.py
index 06d477b..a6a446c 100755
--- a/setup.py
+++ b/setup.py
@@ -42,34 +42,27 @@
# Add more platforms here when needed
if os.name == 'nt' or sys.platform == 'win32':
- Libraries = ['eay32', 'Ws2_32']
- # Try to find it...
- for path in ["C:\\OpenSSL\\lib\\MinGW", "C:\\Python23\\libs",
- "C:\\Python24\\libs", "C:\\Python25\\libs", "C:\\Python26\\libs"]:
- # The .a is the "export library". It's the thing we need to link
- # against to let us use the .dll.
- ssleay32 = os.path.join(path, "ssleay32.a")
- if os.path.exists(ssleay32):
- ExtraObjects = [ssleay32]
- break
- else:
- raise SystemExit("Cannot find ssleay32.a, aborting")
+
+ Libraries = ['Ws2_32']
+ def makeTellMeIf(original, what):
+ class tellMeIf(original):
+ def __init__(*a, **kw):
+ Libraries.extend(what)
+ return original.__init__(*a, **kw)
+ return tellMeIf
+
+ from distutils import cygwinccompiler
+ cygwinccompiler.Mingw32CCompiler = makeTellMeIf(cygwinccompiler.Mingw32CCompiler, ['eay32', 'ssl32'])
+ from distutils import msvccompiler
+ msvccompiler.MSVCCompiler = makeTellMeIf(msvccompiler.MSVCCompiler, ['libeay32', 'ssleay32'])
+
+ import shutil
+ shutil.copy("C:\\OpenSSL\\ssleay32.dll", os.path.split(os.path.abspath(__file__))[0])
+ shutil.copy("C:\\OpenSSL\\libeay32.dll", os.path.split(os.path.abspath(__file__))[0])
+ package_data = {'': ['ssleay32.dll', 'libeay32.dll']}
else:
Libraries = ['ssl', 'crypto']
- ExtraObjects = []
-
-if sys.platform == 'darwin':
- IncludeDirs = ['/sw/include']
- LibraryDirs = ['/sw/lib']
-
-# On Windows, make sure the necessary .dll's get added to the egg.
-data_files = []
-if sys.platform == 'win32':
- import ctypes.util
- libeay32 = ctypes.util.find_library("libeay32")
- if libeay32 is None:
- raise SystemExit("Cannot find libeay32.dll, aborting")
- data_files = [("OpenSSL", [libeay32])]
+ package_data = {}
def mkExtension(name):
@@ -77,10 +70,11 @@
src = globals()[name.lower() + '_src']
dep = globals()[name.lower() + '_dep']
return Extension(modname, src, libraries=Libraries, depends=dep,
- include_dirs=IncludeDirs, library_dirs=LibraryDirs,
- extra_objects=ExtraObjects)
+ include_dirs=IncludeDirs, library_dirs=LibraryDirs)
+
setup(name='pyOpenSSL', version=__version__,
+ packages = ['OpenSSL'],
package_dir = {'OpenSSL': '.'},
ext_modules = [mkExtension('crypto'), mkExtension('rand'),
mkExtension('SSL')],
@@ -90,7 +84,8 @@
'OpenSSL.test.test_crypto',
'OpenSSL.test.test_rand',
'OpenSSL.test.test_ssl'],
- data_files = data_files,
+ zip_safe = False,
+ package_data = package_data,
description = 'Python wrapper module around the OpenSSL library',
author = 'Martin Sjögren, AB Strakt',
author_email = 'msjogren@gmail.com',
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 5d0bf27..b5e6b65 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -49,7 +49,7 @@
#define crypto_X509Extension_New_NUM 5
#define crypto_X509Extension_New_RETURN crypto_X509ExtensionObj *
-#define crypto_X509Extension_New_PROTO (char *, int, char *)
+#define crypto_X509Extension_New_PROTO (char *, int, char *, crypto_X509Obj *, crypto_X509Obj *)
#define crypto_PKCS7_New_NUM 6
#define crypto_PKCS7_New_RETURN crypto_PKCS7Obj *
diff --git a/src/crypto/x509ext.c b/src/crypto/x509ext.c
index e7ab5e1..90ef543 100644
--- a/src/crypto/x509ext.c
+++ b/src/crypto/x509ext.c
@@ -72,20 +72,44 @@
* Arguments: type_name - ???
* critical - ???
* value - ???
+ * subject - An x509v3 certificate which is the subject for this extension.
+ * issuer - An x509v3 certificate which is the issuer for this extension.
* Returns: The newly created X509Extension object
*/
crypto_X509ExtensionObj *
-crypto_X509Extension_New(char *type_name, int critical, char *value)
-{
+crypto_X509Extension_New(char *type_name, int critical, char *value,
+ crypto_X509Obj *subject, crypto_X509Obj *issuer) {
X509V3_CTX ctx;
crypto_X509ExtensionObj *self;
char* value_with_critical = NULL;
- /* We have no configuration database - but perhaps we should. Anyhow, the
- * context is necessary for any extension which uses the r2i conversion
- * method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx. */
+
+ /*
+ * A context is necessary for any extension which uses the r2i conversion
+ * method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
+ * Start off by initializing most of the fields to NULL.
+ */
+ X509V3_set_ctx(&ctx, NULL, NULL, NULL, NULL, 0);
+
+ /*
+ * We have no configuration database - but perhaps we should (some
+ * extensions may require it).
+ */
X509V3_set_ctx_nodb(&ctx);
+ /*
+ * Initialize the subject and issuer, if appropriate. ctx is a local, and
+ * as far as I can tell none of the X509V3_* APIs invoked here steal any
+ * references, so no need to incref subject or issuer.
+ */
+ if (subject) {
+ ctx.subject_cert = subject->x509;
+ }
+
+ if (issuer) {
+ ctx.issuer_cert = issuer->x509;
+ }
+
self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type);
if (self == NULL) {
@@ -137,27 +161,40 @@
}
static char crypto_X509Extension_doc[] = "\n\
-X509Extension(typename, critical, value) -> X509Extension instance\n\
+X509Extension(typename, critical, value[, subject][, issuer]) -> \n\
+ X509Extension instance\n\
\n\
@param typename: The name of the extension to create.\n\
@type typename: C{str}\n\
@param critical: A flag indicating whether this is a critical extension.\n\
@param value: The value of the extension.\n\
@type value: C{str}\n\
+@param subject: Optional X509 cert to use as subject.\n\
+@type subject: C{X509}\n\
+@param issuer: Optional X509 cert to use as issuer.\n\
+@type issuer: C{X509}\n\
@return: The X509Extension object\n\
";
static PyObject *
-crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args,
+ PyObject *kwargs) {
char *type_name, *value;
- int critical;
+ int critical = 0;
+ crypto_X509Obj * subject = NULL;
+ crypto_X509Obj * issuer = NULL;
+ static char *kwlist[] = {"type_name", "critical", "value", "subject",
+ "issuer", NULL};
- if (!PyArg_ParseTuple(args, "sis:X509Extension", &type_name, &critical,
- &value)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sis|O!O!:X509Extension",
+ kwlist, &type_name, &critical, &value,
+ &crypto_X509_Type, &subject,
+ &crypto_X509_Type, &issuer )) {
return NULL;
}
- return (PyObject *)crypto_X509Extension_New(type_name, critical, value);
+ return (PyObject *)crypto_X509Extension_New(type_name, critical, value,
+ subject, issuer);
}
/*
diff --git a/test/test_crypto.py b/test/test_crypto.py
index dcc8cef..312a1b0 100644
--- a/test/test_crypto.py
+++ b/test/test_crypto.py
@@ -7,6 +7,7 @@
from unittest import main
from os import popen2
+from datetime import datetime, timedelta
from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
@@ -225,8 +226,44 @@
"""
-
class X509ExtTests(TestCase):
+ """
+ Tests for L{OpenSSL.crypto.X509Extension}.
+ """
+
+ def setUp(self):
+ """
+ Create a new private key and start a certificate request (for a test
+ method to finish in one way or another).
+ """
+ # Basic setup stuff to generate a certificate
+ self.pkey = PKey()
+ self.pkey.generate_key(TYPE_RSA, 384)
+ self.req = X509Req()
+ self.req.set_pubkey(self.pkey)
+ # Authority good you have.
+ self.req.get_subject().commonName = "Yoda root CA"
+ self.x509 = X509()
+ self.subject = self.x509.get_subject()
+ self.subject.commonName = self.req.get_subject().commonName
+ self.x509.set_issuer(self.subject)
+ self.x509.set_pubkey(self.pkey)
+ now = datetime.now().strftime("%Y%m%d%H%M%SZ")
+ expire = (datetime.now() + timedelta(days=100)).strftime("%Y%m%d%H%M%SZ")
+ self.x509.set_notBefore(now)
+ self.x509.set_notAfter(expire)
+
+
+ def test_type(self):
+ """
+ L{X509Extension} and L{X509ExtensionType} refer to the same type object
+ and can be used to create instances of that type.
+ """
+ self.assertIdentical(X509Extension, X509ExtensionType)
+ self.assertConsistentType(
+ X509Extension, 'X509Extension', 'basicConstraints', True, 'CA:true')
+
+
def test_construction(self):
"""
L{X509Extension} accepts an extension type name, a critical flag,
@@ -286,14 +323,122 @@
self.assertEqual(ext.get_short_name(), 'nsComment')
+ def test_unused_subject(self):
+ """
+ The C{subject} parameter to L{X509Extension} may be provided for an
+ extension which does not use it and is ignored in this case.
+ """
+ ext1 = X509Extension('basicConstraints', False, 'CA:TRUE', subject=self.x509)
+ self.x509.add_extensions([ext1])
+ self.x509.sign(self.pkey, 'sha1')
+ # This is a little lame. Can we think of a better way?
+ text = dump_certificate(FILETYPE_TEXT, self.x509)
+ self.assertTrue('X509v3 Basic Constraints:' in text)
+ self.assertTrue('CA:TRUE' in text)
+
+
+ def test_subject(self):
+ """
+ If an extension requires a subject, the C{subject} parameter to
+ L{X509Extension} provides its value.
+ """
+ ext3 = X509Extension('subjectKeyIdentifier', False, 'hash', subject=self.x509)
+ self.x509.add_extensions([ext3])
+ self.x509.sign(self.pkey, 'sha1')
+ text = dump_certificate(FILETYPE_TEXT, self.x509)
+ self.assertTrue('X509v3 Subject Key Identifier:' in text)
+
+
+ def test_missing_subject(self):
+ """
+ If an extension requires a subject and the C{subject} parameter is
+ given no value, something happens.
+ """
+ self.assertRaises(
+ Error, X509Extension, 'subjectKeyIdentifier', False, 'hash')
+
+
+ def test_invalid_subject(self):
+ """
+ If the C{subject} parameter is given a value which is not an L{X509}
+ instance, L{TypeError} is raised.
+ """
+ for badObj in [True, object(), "hello", [], self]:
+ self.assertRaises(
+ TypeError,
+ X509Extension,
+ 'basicConstraints', False, 'CA:TRUE', subject=badObj)
+
+
+ def test_unused_issuer(self):
+ """
+ The C{issuer} parameter to L{X509Extension} may be provided for an
+ extension which does not use it and is ignored in this case.
+ """
+ ext1 = X509Extension('basicConstraints', False, 'CA:TRUE', issuer=self.x509)
+ self.x509.add_extensions([ext1])
+ self.x509.sign(self.pkey, 'sha1')
+ text = dump_certificate(FILETYPE_TEXT, self.x509)
+ self.assertTrue('X509v3 Basic Constraints:' in text)
+ self.assertTrue('CA:TRUE' in text)
+
+
+ def test_issuer(self):
+ """
+ If an extension requires a issuer, the C{issuer} parameter to
+ L{X509Extension} provides its value.
+ """
+ ext2 = X509Extension(
+ 'authorityKeyIdentifier', False, 'issuer:always',
+ issuer=self.x509)
+ self.x509.add_extensions([ext2])
+ self.x509.sign(self.pkey, 'sha1')
+ text = dump_certificate(FILETYPE_TEXT, self.x509)
+ self.assertTrue('X509v3 Authority Key Identifier:' in text)
+ self.assertTrue('DirName:/CN=Yoda root CA' in text)
+
+
+ def test_missing_issuer(self):
+ """
+ If an extension requires an issue and the C{issuer} parameter is given
+ no value, something happens.
+ """
+ self.assertRaises(
+ Error,
+ X509Extension,
+ 'authorityKeyIdentifier', False, 'keyid:always,issuer:always')
+
+
+ def test_invalid_issuer(self):
+ """
+ If the C{issuer} parameter is given a value which is not an L{X509}
+ instance, L{TypeError} is raised.
+ """
+ for badObj in [True, object(), "hello", [], self]:
+ self.assertRaises(
+ TypeError,
+ X509Extension,
+ 'authorityKeyIdentifier', False, 'keyid:always,issuer:always',
+ issuer=badObj)
+
+
class PKeyTests(TestCase):
"""
Unit tests for L{OpenSSL.crypto.PKey}.
"""
+ def test_type(self):
+ """
+ L{PKey} and L{PKeyType} refer to the same type object and can be used
+ to create instances of that type.
+ """
+ self.assertIdentical(PKey, PKeyType)
+ self.assertConsistentType(PKey, 'PKey')
+
+
def test_construction(self):
"""
- L{PKey} takes no arguments and returns a new L{PKeyType} instance.
+ L{PKey} takes no arguments and returns a new L{PKey} instance.
"""
self.assertRaises(TypeError, PKey, None)
key = PKey()
@@ -402,6 +547,21 @@
return name
+ def test_type(self):
+ """
+ The type of X509Name objects is L{X509NameType}.
+ """
+ self.assertIdentical(X509Name, X509NameType)
+ self.assertEqual(X509NameType.__name__, 'X509Name')
+ self.assertTrue(isinstance(X509NameType, type))
+
+ name = self._x509name()
+ self.assertTrue(
+ isinstance(name, X509NameType),
+ "%r is of type %r, should be %r" % (
+ name, type(name), X509NameType))
+
+
def test_attributes(self):
"""
L{X509NameType} instances have attributes for each standard (?)
@@ -613,6 +773,15 @@
return X509Req()
+ def test_type(self):
+ """
+ L{X509Req} and L{X509ReqType} refer to the same type object and can be
+ used to create instances of that type.
+ """
+ self.assertIdentical(X509Req, X509ReqType)
+ self.assertConsistentType(X509Req, 'X509Req')
+
+
def test_construction(self):
"""
L{X509Req} takes no arguments and returns an L{X509ReqType} instance.
@@ -669,6 +838,15 @@
return X509()
+ def test_type(self):
+ """
+ L{X509} and L{X509Type} refer to the same type object and can be used
+ to create instances of that type.
+ """
+ self.assertIdentical(X509, X509Type)
+ self.assertConsistentType(X509, 'X509')
+
+
def test_construction(self):
"""
L{X509} takes no arguments and returns an instance of L{X509Type}.
@@ -679,6 +857,10 @@
"%r is of type %r, should be %r" % (certificate,
type(certificate),
X509Type))
+ self.assertEqual(type(X509Type).__name__, 'type')
+ self.assertEqual(type(certificate).__name__, 'X509')
+ self.assertEqual(type(certificate), X509Type)
+ self.assertEqual(type(certificate), X509)
def test_serial_number(self):
@@ -1218,10 +1400,51 @@
+class PKCS7Tests(TestCase):
+ """
+ Tests for L{PKCS7Type}.
+ """
+ def test_type(self):
+ """
+ L{PKCS7Type} is a type object.
+ """
+ self.assertTrue(isinstance(PKCS7Type, type))
+ self.assertEqual(PKCS7Type.__name__, 'PKCS7')
+
+ # XXX This doesn't currently work.
+ # self.assertIdentical(PKCS7, PKCS7Type)
+
+
+
+class PKCS12Tests(TestCase):
+ """
+ Tests for L{PKCS12Type}.
+ """
+ def test_type(self):
+ """
+ L{PKCS12Type} is a type object.
+ """
+ self.assertTrue(isinstance(PKCS12Type, type))
+ self.assertEqual(PKCS12Type.__name__, 'PKCS12')
+
+ # XXX This doesn't currently work.
+ # self.assertIdentical(PKCS12, PKCS12Type)
+
+
+
class NetscapeSPKITests(TestCase):
"""
Tests for L{OpenSSL.crypto.NetscapeSPKI}.
"""
+ def test_type(self):
+ """
+ L{NetscapeSPKI} and L{NetscapeSPKIType} refer to the same type object
+ and can be used to create instances of that type.
+ """
+ self.assertIdentical(NetscapeSPKI, NetscapeSPKIType)
+ self.assertConsistentType(NetscapeSPKI, 'NetscapeSPKI')
+
+
def test_construction(self):
"""
L{NetscapeSPKI} returns an instance of L{NetscapeSPKIType}.
diff --git a/test/test_ssl.py b/test/test_ssl.py
index 9eb8946..5d386a9 100644
--- a/test/test_ssl.py
+++ b/test/test_ssl.py
@@ -6,14 +6,14 @@
from sys import platform
from socket import socket
-from os import makedirs, symlink
+from os import makedirs
from os.path import join
from unittest import main
from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey
-from OpenSSL.SSL import WantReadError, Context, Connection, Error
+from OpenSSL.SSL import WantReadError, Context, ContextType, Connection, ConnectionType, Error
from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
-from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
+from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE
from OpenSSL.test.util import TestCase
from OpenSSL.test.test_crypto import cleartextCertificatePEM, cleartextPrivateKeyPEM
@@ -34,8 +34,7 @@
def socket_pair():
"""
- Establish and return a pair of network sockets connected
- to each other.
+ Establish and return a pair of network sockets connected to each other.
"""
# Connect a pair of sockets
port = socket()
@@ -43,7 +42,7 @@
port.listen(1)
client = socket()
client.setblocking(False)
- client.connect_ex(port.getsockname())
+ client.connect_ex(("127.0.0.1", port.getsockname()[1]))
client.setblocking(True)
server = port.accept()[0]
@@ -78,6 +77,15 @@
self.assertRaises(ValueError, Context, 10)
+ def test_type(self):
+ """
+ L{Context} and L{ContextType} refer to the same type object and can be
+ used to create instances of that type.
+ """
+ self.assertIdentical(Context, ContextType)
+ self.assertConsistentType(Context, 'Context', TLSv1_METHOD)
+
+
def test_use_privatekey(self):
"""
L{Context.use_privatekey} takes an L{OpenSSL.crypto.PKey} instance.
@@ -216,49 +224,47 @@
"""
capath = self.mktemp()
makedirs(capath)
- cafile = join(capath, 'cert.pem')
+ # Hash value computed manually with c_rehash to avoid depending on
+ # c_rehash in the test suite.
+ cafile = join(capath, 'c7adac82.0')
fObj = file(cafile, 'w')
fObj.write(cleartextCertificatePEM)
fObj.close()
- # Hash value computed manually with c_rehash to avoid depending on
- # c_rehash in the test suite.
- symlink('cert.pem', join(capath, 'c7adac82.0'))
-
self._load_verify_locations_test(None, capath)
- def test_set_default_verify_paths(self):
- """
- L{Context.set_default_verify_paths} causes the platform-specific CA
- certificate locations to be used for verification purposes.
- """
- # Testing this requires a server with a certificate signed by one of
- # the CAs in the platform CA location. Getting one of those costs
- # money. Fortunately (or unfortunately, depending on your
- # perspective), it's easy to think of a public server on the
- # internet which has such a certificate. Connecting to the network
- # in a unit test is bad, but it's the only way I can think of to
- # really test this. -exarkun
+ if platform in ("darwin", "win32"):
+ "set_default_verify_paths appears not to work on OS X or Windows"
+ "See LP#404343 and LP#404344."
+ else:
+ def test_set_default_verify_paths(self):
+ """
+ L{Context.set_default_verify_paths} causes the platform-specific CA
+ certificate locations to be used for verification purposes.
+ """
+ # Testing this requires a server with a certificate signed by one of
+ # the CAs in the platform CA location. Getting one of those costs
+ # money. Fortunately (or unfortunately, depending on your
+ # perspective), it's easy to think of a public server on the
+ # internet which has such a certificate. Connecting to the network
+ # in a unit test is bad, but it's the only way I can think of to
+ # really test this. -exarkun
- # Arg, verisign.com doesn't speak TLSv1
- context = Context(SSLv3_METHOD)
- context.set_default_verify_paths()
- context.set_verify(
- VERIFY_PEER,
- lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
+ # Arg, verisign.com doesn't speak TLSv1
+ context = Context(SSLv3_METHOD)
+ context.set_default_verify_paths()
+ context.set_verify(
+ VERIFY_PEER,
+ lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
- client = socket()
- client.connect(('verisign.com', 443))
- clientSSL = Connection(context, client)
- clientSSL.set_connect_state()
- clientSSL.do_handshake()
- clientSSL.send('GET / HTTP/1.0\r\n\r\n')
- self.assertTrue(clientSSL.recv(1024))
- if platform == "darwin":
- test_set_default_verify_paths.todo = (
- "set_default_verify_paths appears not to work on OS X - a "
- "problem with the supplied OpenSSL, perhaps?")
+ client = socket()
+ client.connect(('verisign.com', 443))
+ clientSSL = Connection(context, client)
+ clientSSL.set_connect_state()
+ clientSSL.do_handshake()
+ clientSSL.send('GET / HTTP/1.0\r\n\r\n')
+ self.assertTrue(clientSSL.recv(1024))
def test_set_default_verify_paths_signature(self):
@@ -273,6 +279,34 @@
+class ConnectionTests(TestCase):
+ """
+ Unit tests for L{OpenSSL.SSL.Connection}.
+ """
+ def test_type(self):
+ """
+ L{Connection} and L{ConnectionType} refer to the same type object and
+ can be used to create instances of that type.
+ """
+ self.assertIdentical(Connection, ConnectionType)
+ ctx = Context(TLSv1_METHOD)
+ self.assertConsistentType(Connection, 'Connection', ctx, None)
+
+
+
+class ErrorTests(TestCase):
+ """
+ Unit tests for L{OpenSSL.SSL.Error}.
+ """
+ def test_type(self):
+ """
+ L{Error} is an exception type.
+ """
+ self.assertTrue(issubclass(Error, Exception))
+ self.assertEqual(Error.__name__, 'Error')
+
+
+
class ConstantsTests(TestCase):
"""
Tests for the values of constants exposed in L{OpenSSL.SSL}.
diff --git a/test/util.py b/test/util.py
index d3572db..d195d95 100644
--- a/test/util.py
+++ b/test/util.py
@@ -11,6 +11,7 @@
import os, os.path
from tempfile import mktemp
from unittest import TestCase
+import sys
from OpenSSL.crypto import Error, _exception_from_error_queue
@@ -88,10 +89,10 @@
except exception, inst:
return inst
except:
- raise self.failureException('%s raised instead of %s:\n %s'
+ raise self.failureException('%s raised instead of %s'
% (sys.exc_info()[0],
exception.__name__,
- failure.Failure().getTraceback()))
+ ))
else:
raise self.failureException('%s not raised (%r returned)'
% (exception.__name__, result))
@@ -117,3 +118,22 @@
def assertFalse(self, *a, **kw):
return self.failIf(*a, **kw)
+
+
+ # Other stuff
+ def assertConsistentType(self, theType, name, *constructionArgs):
+ """
+ Perform various assertions about C{theType} to ensure that it is a
+ well-defined type. This is useful for extension types, where it's
+ pretty easy to do something wacky. If something about the type is
+ unusual, an exception will be raised.
+
+ @param theType: The type object about which to make assertions.
+ @param name: A string giving the name of the type.
+ @param constructionArgs: Positional arguments to use with C{theType} to
+ create an instance of it.
+ """
+ self.assertEqual(theType.__name__, name)
+ self.assertTrue(isinstance(theType, type))
+ instance = theType(*constructionArgs)
+ self.assertIdentical(type(instance), theType)