summaryrefslogtreecommitdiffstats
path: root/Modules/_ssl.c
diff options
context:
space:
mode:
authorThomas Wouters <thomas@python.org>2007-09-19 03:06:30 (GMT)
committerThomas Wouters <thomas@python.org>2007-09-19 03:06:30 (GMT)
commit1b7f891f416830d0c46ca1c9e1bfe62f05cda655 (patch)
treefc092d34bebe4223a3026d1992bf17cc0ea2b2b0 /Modules/_ssl.c
parent782d6b44a1cc003106bac3a310d3e4ac3768adbd (diff)
downloadcpython-1b7f891f416830d0c46ca1c9e1bfe62f05cda655.zip
cpython-1b7f891f416830d0c46ca1c9e1bfe62f05cda655.tar.gz
cpython-1b7f891f416830d0c46ca1c9e1bfe62f05cda655.tar.bz2
Merged revisions 58095-58132,58136-58148,58151-58197 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r58096 | brett.cannon | 2007-09-10 23:38:27 +0200 (Mon, 10 Sep 2007) | 4 lines Fix a possible segfault from recursing too deep to get the repr of a list. Closes issue #1096. ........ r58097 | bill.janssen | 2007-09-10 23:51:02 +0200 (Mon, 10 Sep 2007) | 33 lines More work on SSL support. * Much expanded test suite: All protocols tested against all other protocols. All protocols tested with all certificate options. Tests for bad key and bad cert. Test of STARTTLS functionality. Test of RAND_* functions. * Fixes for threading/malloc bug. * Issue 1065 fixed: sslsocket class renamed to SSLSocket. sslerror class renamed to SSLError. Function "wrap_socket" now used to wrap an existing socket. * Issue 1583946 finally fixed: Support for subjectAltName added. Subject name now returned as proper DN list of RDNs. * SSLError exported from socket as "sslerror". * RAND_* functions properly exported from ssl.py. * Documentation improved: Example of how to create a self-signed certificate. Better indexing. ........ r58098 | guido.van.rossum | 2007-09-11 00:02:25 +0200 (Tue, 11 Sep 2007) | 9 lines Patch # 1140 (my code, approved by Effbot). Make sure the type of the return value of re.sub(x, y, z) is the type of y+x (i.e. unicode if either is unicode, str if they are both str) even if there are no substitutions or if x==z (which triggered various special cases in join_list()). Could be backported to 2.5; no need to port to 3.0. ........ r58099 | guido.van.rossum | 2007-09-11 00:36:02 +0200 (Tue, 11 Sep 2007) | 8 lines Patch # 1026 by Benjamin Aranguren (with Alex Martelli): Backport abc.py and isinstance/issubclass overloading to 2.6. I had to backport test_typechecks.py myself, and make one small change to abc.py to avoid duplicate work when x.__class__ and type(x) are the same. ........ r58100 | bill.janssen | 2007-09-11 01:41:24 +0200 (Tue, 11 Sep 2007) | 3 lines A better way of finding an open port to test with. ........ r58101 | bill.janssen | 2007-09-11 03:09:19 +0200 (Tue, 11 Sep 2007) | 4 lines Make sure test_ssl doesn't reference the ssl module in a context where it can't be imported. ........ r58102 | bill.janssen | 2007-09-11 04:42:07 +0200 (Tue, 11 Sep 2007) | 3 lines Fix some documentation bugs. ........ r58103 | nick.coghlan | 2007-09-11 16:01:18 +0200 (Tue, 11 Sep 2007) | 1 line Always use the -E flag when spawning subprocesses in test_cmd_line (Issue 1056) ........ r58106 | thomas.heller | 2007-09-11 21:17:48 +0200 (Tue, 11 Sep 2007) | 3 lines Disable some tests that fail on the 'ppc Debian unstable' buildbot to find out if they cause the segfault on the 'alpha Debian' machine. ........ r58108 | brett.cannon | 2007-09-11 23:02:28 +0200 (Tue, 11 Sep 2007) | 6 lines Generators had their throw() method allowing string exceptions. That's a no-no. Fixes issue #1147. Need to fix 2.5 to raise a proper warning if a string exception is passed in. ........ r58112 | georg.brandl | 2007-09-12 20:03:51 +0200 (Wed, 12 Sep 2007) | 3 lines New documentation page for the bdb module. (This doesn't need to be merged to Py3k.) ........ r58114 | georg.brandl | 2007-09-12 20:05:57 +0200 (Wed, 12 Sep 2007) | 2 lines Bug #1152: use non-deprecated name in example. ........ r58115 | georg.brandl | 2007-09-12 20:08:33 +0200 (Wed, 12 Sep 2007) | 2 lines Fix #1122: wrong return type documented for various _Size() functions. ........ r58117 | georg.brandl | 2007-09-12 20:10:56 +0200 (Wed, 12 Sep 2007) | 2 lines Fix #1139: PyFile_Encoding really is PyFile_SetEncoding. ........ r58119 | georg.brandl | 2007-09-12 20:29:18 +0200 (Wed, 12 Sep 2007) | 2 lines bug #1154: release memory allocated by "es" PyArg_ParseTuple format specifier. ........ r58121 | bill.janssen | 2007-09-12 20:52:05 +0200 (Wed, 12 Sep 2007) | 1 line root certificate for https://svn.python.org/, used in test_ssl ........ r58122 | georg.brandl | 2007-09-12 21:00:07 +0200 (Wed, 12 Sep 2007) | 3 lines Bug #1153: repr.repr() now doesn't require set and dictionary items to be orderable to properly represent them. ........ r58125 | georg.brandl | 2007-09-12 21:29:28 +0200 (Wed, 12 Sep 2007) | 4 lines #1120: put explicit version in the shebang lines of pydoc, idle and smtpd.py scripts that are installed by setup.py. That way, they work when only "make altinstall" is used. ........ r58139 | mark.summerfield | 2007-09-13 16:54:30 +0200 (Thu, 13 Sep 2007) | 9 lines Replaced variable o with obj in operator.rst because o is easy to confuse. Added a note about Python 3's collections.Mapping etc., above section that describes isMappingType() etc. Added xrefs between os, os.path, fileinput, and open(). ........ r58143 | facundo.batista | 2007-09-13 20:13:15 +0200 (Thu, 13 Sep 2007) | 7 lines Merged the decimal-branch (revisions 54886 to 58140). Decimal is now fully updated to the latests Decimal Specification (v1.66) and the latests test cases (v2.56). Thanks to Mark Dickinson for all his help during this process. ........ r58145 | facundo.batista | 2007-09-13 20:42:09 +0200 (Thu, 13 Sep 2007) | 7 lines Put the parameter watchexp back in (changed watchexp from an int to a bool). Also second argument to watchexp is now converted to Decimal, just as with all the other two-argument operations. Thanks Mark Dickinson. ........ r58147 | andrew.kuchling | 2007-09-14 00:49:34 +0200 (Fri, 14 Sep 2007) | 1 line Add various items ........ r58148 | andrew.kuchling | 2007-09-14 00:50:10 +0200 (Fri, 14 Sep 2007) | 1 line Make target unique ........ r58154 | facundo.batista | 2007-09-14 20:58:34 +0200 (Fri, 14 Sep 2007) | 3 lines Included the new functions, and new descriptions. ........ r58155 | thomas.heller | 2007-09-14 21:40:35 +0200 (Fri, 14 Sep 2007) | 2 lines ctypes.util.find_library uses dump(1) instead of objdump(1) on Solaris. Fixes issue #1777530; will backport to release25-maint. ........ r58159 | facundo.batista | 2007-09-14 23:29:52 +0200 (Fri, 14 Sep 2007) | 3 lines Some additions (examples and a bit on the tutorial). ........ r58160 | georg.brandl | 2007-09-15 18:53:36 +0200 (Sat, 15 Sep 2007) | 2 lines Remove bdb from the "undocumented modules" list. ........ r58164 | bill.janssen | 2007-09-17 00:06:00 +0200 (Mon, 17 Sep 2007) | 15 lines Add support for asyncore server-side SSL support. This requires adding the 'makefile' method to ssl.SSLSocket, and importing the requisite fakefile class from socket.py, and making the appropriate changes to it to make it use the SSL connection. Added sample HTTPS server to test_ssl.py, and test that uses it. Change SSL tests to use https://svn.python.org/, instead of www.sf.net and pop.gmail.com. Added utility function to ssl module, get_server_certificate, to wrap up the several things to be done to pull a certificate from a remote server. ........ r58173 | bill.janssen | 2007-09-17 01:16:46 +0200 (Mon, 17 Sep 2007) | 1 line use binary mode when reading files for testAsyncore to make Windows happy ........ r58175 | raymond.hettinger | 2007-09-17 02:55:00 +0200 (Mon, 17 Sep 2007) | 7 lines Sync-up named tuples with the latest version of the ASPN recipe. Allows optional commas in the field-name spec (help when named tuples are used in conjuction with sql queries). Adds the __fields__ attribute for introspection and to support conversion to dictionary form. Adds a __replace__() method similar to str.replace() but using a named field as a target. Clean-up spelling and presentation in doc-strings. ........ r58176 | brett.cannon | 2007-09-17 05:28:34 +0200 (Mon, 17 Sep 2007) | 5 lines Add a bunch of GIL release/acquire points in tp_print implementations and for PyObject_Print(). Closes issue #1164. ........ r58177 | sean.reifschneider | 2007-09-17 07:45:04 +0200 (Mon, 17 Sep 2007) | 2 lines issue1597011: Fix for bz2 module corner-case error due to error checking bug. ........ r58180 | facundo.batista | 2007-09-17 18:26:50 +0200 (Mon, 17 Sep 2007) | 3 lines Decimal is updated, :) ........ r58181 | facundo.batista | 2007-09-17 19:30:13 +0200 (Mon, 17 Sep 2007) | 5 lines The methods always return Decimal classes, even if they're executed through a subclass (thanks Mark Dickinson). Added a bit of testing for this. ........ r58183 | sean.reifschneider | 2007-09-17 22:53:21 +0200 (Mon, 17 Sep 2007) | 2 lines issue1082: Fixing platform and system for Vista. ........ r58185 | andrew.kuchling | 2007-09-18 03:36:16 +0200 (Tue, 18 Sep 2007) | 1 line Add item; sort properly ........ r58186 | raymond.hettinger | 2007-09-18 05:33:19 +0200 (Tue, 18 Sep 2007) | 1 line Handle corner cased on 0-tuples and 1-tuples. Add verbose option so people can see how it works. ........ r58192 | georg.brandl | 2007-09-18 09:24:40 +0200 (Tue, 18 Sep 2007) | 2 lines A bit of reordering, also show more subheadings in the lang ref index. ........ r58193 | facundo.batista | 2007-09-18 18:53:18 +0200 (Tue, 18 Sep 2007) | 4 lines Speed up of the various division operations (remainder, divide, divideint and divmod). Thanks Mark Dickinson. ........ r58197 | raymond.hettinger | 2007-09-19 00:18:02 +0200 (Wed, 19 Sep 2007) | 1 line Cleanup docs for NamedTuple. ........
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r--Modules/_ssl.c846
1 files changed, 671 insertions, 175 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index ae0c34a..b680c41 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -1,14 +1,38 @@
/* SSL socket module
SSL support based on patches by Brian E Gallew and Laszlo Kovacs.
+ Re-worked a bit by Bill Janssen to add server-side support and
+ certificate decoding.
- This module is imported by socket.py. It should *not* be used
+ This module is imported by ssl.py. It should *not* be used
directly.
+ XXX should partial writes be enabled, SSL_MODE_ENABLE_PARTIAL_WRITE?
+
+ XXX what about SSL_MODE_AUTO_RETRY
*/
#include "Python.h"
+#ifdef WITH_THREAD
+#include "pythread.h"
+#define PySSL_BEGIN_ALLOW_THREADS { \
+ PyThreadState *_save; \
+ if (_ssl_locks_count>0) {_save = PyEval_SaveThread();}
+#define PySSL_BLOCK_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save)};
+#define PySSL_UNBLOCK_THREADS if (_ssl_locks_count>0){_save = PyEval_SaveThread()};
+#define PySSL_END_ALLOW_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \
+ }
+
+#else /* no WITH_THREAD */
+
+#define PySSL_BEGIN_ALLOW_THREADS
+#define PySSL_BLOCK_THREADS
+#define PySSL_UNBLOCK_THREADS
+#define PySSL_END_ALLOW_THREADS
+
+#endif
+
enum py_ssl_error {
/* these mirror ssl.h */
PY_SSL_ERROR_NONE,
@@ -55,6 +79,7 @@ enum py_ssl_version {
#include "openssl/rsa.h"
#include "openssl/crypto.h"
#include "openssl/x509.h"
+#include "openssl/x509v3.h"
#include "openssl/pem.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
@@ -63,6 +88,15 @@ enum py_ssl_version {
/* SSL error object */
static PyObject *PySSLErrorObject;
+#ifdef WITH_THREAD
+
+/* serves as a flag to see whether we've initialized the SSL thread support. */
+/* 0 means no, greater than 0 means yes */
+
+static unsigned int _ssl_locks_count = 0;
+
+#endif /* def WITH_THREAD */
+
/* SSL socket object */
#define X509_NAME_MAXLEN 256
@@ -90,8 +124,8 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args);
static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args);
static int check_socket_and_wait_for_timeout(PySocketSockObject *s,
int writing);
-static PyObject *PySSL_peercert(PySSLObject *self);
-
+static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args);
+static PyObject *PySSL_cipher(PySSLObject *self);
#define PySSLObject_Check(v) (Py_Type(v) == &PySSL_Type)
@@ -126,7 +160,7 @@ PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno)
assert(ret <= 0);
- if ((obj != NULL) && (obj->ssl != NULL)) {
+ if (obj->ssl != NULL) {
err = SSL_get_error(obj->ssl, ret);
switch (err) {
@@ -202,6 +236,25 @@ PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno)
return NULL;
}
+static PyObject *
+_setSSLError (char *errstr, int errcode, char *filename, int lineno) {
+
+ char buf[2048];
+ PyObject *v;
+
+ if (errstr == NULL) {
+ errcode = ERR_peek_last_error();
+ errstr = ERR_error_string(errcode, NULL);
+ }
+ PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
+ v = Py_BuildValue("(is)", errcode, buf);
+ if (v != NULL) {
+ PyErr_SetObject(PySSLErrorObject, v);
+ Py_DECREF(v);
+ }
+ return NULL;
+}
+
static PySSLObject *
newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
enum py_ssl_server_or_client socket_type,
@@ -226,6 +279,10 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
self->ctx = NULL;
self->Socket = NULL;
+ /* Make sure the SSL error state is initialized */
+ (void) ERR_get_state();
+ ERR_clear_error();
+
if ((key_file && !cert_file) || (!key_file && cert_file)) {
errstr = ERRSTR("Both the key & certificate files "
"must be specified");
@@ -239,16 +296,16 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
goto fail;
}
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
if (proto_version == PY_SSL_VERSION_TLS1)
self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */
else if (proto_version == PY_SSL_VERSION_SSL3)
self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */
else if (proto_version == PY_SSL_VERSION_SSL2)
self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */
- else
+ else if (proto_version == PY_SSL_VERSION_SSL23)
self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
if (self->ctx == NULL) {
errstr = ERRSTR("Invalid SSL protocol variant specified.");
@@ -261,39 +318,46 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
"verification of other-side certificates.");
goto fail;
} else {
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
ret = SSL_CTX_load_verify_locations(self->ctx,
cacerts_file,
NULL);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
if (ret != 1) {
- PySSL_SetError(NULL, 0, __FILE__, __LINE__);
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
goto fail;
}
}
}
if (key_file) {
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
SSL_FILETYPE_PEM);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
if (ret != 1) {
- PySSL_SetError(NULL, 0, __FILE__, __LINE__);
+ _setSSLError(NULL, ret, __FILE__, __LINE__);
goto fail;
}
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
ret = SSL_CTX_use_certificate_chain_file(self->ctx,
- cert_file);
- Py_END_ALLOW_THREADS
+ cert_file);
+ PySSL_END_ALLOW_THREADS
if (ret != 1) {
- PySSL_SetError(NULL, 0, __FILE__, __LINE__);
- goto fail;
+ /*
+ fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
+ ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
+ */
+ if (ERR_peek_last_error() != 0) {
+ _setSSLError(NULL, ret, __FILE__, __LINE__);
+ goto fail;
+ }
}
- /* ssl compatibility */
- SSL_CTX_set_options(self->ctx, SSL_OP_ALL);
}
+ /* ssl compatibility */
+ SSL_CTX_set_options(self->ctx, SSL_OP_ALL);
+
verification_mode = SSL_VERIFY_NONE;
if (certreq == PY_SSL_CERT_OPTIONAL)
verification_mode = SSL_VERIFY_PEER;
@@ -303,9 +367,9 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
SSL_CTX_set_verify(self->ctx, verification_mode,
NULL); /* set verify lvl */
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
self->ssl = SSL_new(self->ctx); /* New ssl struct */
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */
/* If the socket is in non-blocking mode or timeout mode, set the BIO
@@ -317,24 +381,24 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
}
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
if (socket_type == PY_SSL_CLIENT)
SSL_set_connect_state(self->ssl);
else
SSL_set_accept_state(self->ssl);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
/* Actually negotiate SSL connection */
/* XXX If SSL_connect() returns 0, it's also a failure. */
sockstate = 0;
do {
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
if (socket_type == PY_SSL_CLIENT)
ret = SSL_connect(self->ssl);
else
ret = SSL_accept(self->ssl);
err = SSL_get_error(self->ssl, ret);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
if(PyErr_CheckSignals()) {
goto fail;
}
@@ -367,14 +431,14 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
}
self->ssl->debug = 1;
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
if ((self->peer_cert = SSL_get_peer_certificate(self->ssl))) {
X509_NAME_oneline(X509_get_subject_name(self->peer_cert),
self->server, X509_NAME_MAXLEN);
X509_NAME_oneline(X509_get_issuer_name(self->peer_cert),
self->issuer, X509_NAME_MAXLEN);
}
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
self->Socket = Sock;
Py_INCREF(self->Socket);
return self;
@@ -437,96 +501,313 @@ PySSL_issuer(PySSLObject *self)
}
static PyObject *
+_create_tuple_for_attribute (ASN1_OBJECT *name, ASN1_STRING *value) {
+
+ char namebuf[X509_NAME_MAXLEN];
+ int buflen;
+ PyObject *name_obj;
+ PyObject *value_obj;
+ PyObject *attr;
+ unsigned char *valuebuf = NULL;
+
+ buflen = OBJ_obj2txt(namebuf, sizeof(namebuf), name, 0);
+ if (buflen < 0) {
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ goto fail;
+ }
+ name_obj = PyString_FromStringAndSize(namebuf, buflen);
+ if (name_obj == NULL)
+ goto fail;
+
+ buflen = ASN1_STRING_to_UTF8(&valuebuf, value);
+ if (buflen < 0) {
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ Py_DECREF(name_obj);
+ goto fail;
+ }
+ value_obj = PyUnicode_DecodeUTF8((char *) valuebuf,
+ buflen, "strict");
+ OPENSSL_free(valuebuf);
+ if (value_obj == NULL) {
+ Py_DECREF(name_obj);
+ goto fail;
+ }
+ attr = PyTuple_New(2);
+ if (attr == NULL) {
+ Py_DECREF(name_obj);
+ Py_DECREF(value_obj);
+ goto fail;
+ }
+ PyTuple_SET_ITEM(attr, 0, name_obj);
+ PyTuple_SET_ITEM(attr, 1, value_obj);
+ return attr;
+
+ fail:
+ return NULL;
+}
+
+static PyObject *
_create_tuple_for_X509_NAME (X509_NAME *xname)
{
- PyObject *pt = NULL;
- PyObject *entry_tuple = NULL;
+ PyObject *dn = NULL; /* tuple which represents the "distinguished name" */
+ PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */
+ PyObject *rdnt;
+ PyObject *attr = NULL; /* tuple to hold an attribute */
int entry_count = X509_NAME_entry_count(xname);
+ X509_NAME_ENTRY *entry;
+ ASN1_OBJECT *name;
+ ASN1_STRING *value;
int index_counter;
+ int rdn_level = -1;
+ int retcode;
- pt = PyTuple_New(entry_count);
- if (pt == NULL)
+ dn = PyList_New(0);
+ if (dn == NULL)
return NULL;
+ /* now create another tuple to hold the top-level RDN */
+ rdn = PyList_New(0);
+ if (rdn == NULL)
+ goto fail0;
for (index_counter = 0;
- index_counter < X509_NAME_entry_count(xname);
+ index_counter < entry_count;
index_counter++)
{
- char namebuf[X509_NAME_MAXLEN];
- int buflen;
- PyObject *name_obj;
- ASN1_STRING *value;
- PyObject *value_obj;
- unsigned char *valuebuf = NULL;
-
- X509_NAME_ENTRY *entry = X509_NAME_get_entry(xname,
- index_counter);
-
- ASN1_OBJECT *name = X509_NAME_ENTRY_get_object(entry);
- buflen = OBJ_obj2txt(namebuf, sizeof(namebuf), name, 0);
- if (buflen < 0)
- goto fail0;
- name_obj = PyString_FromStringAndSize(namebuf, buflen);
- if (name_obj == NULL)
- goto fail0;
+ entry = X509_NAME_get_entry(xname, index_counter);
+
+ /* check to see if we've gotten to a new RDN */
+ if (rdn_level >= 0) {
+ if (rdn_level != entry->set) {
+ /* yes, new RDN */
+ /* add old RDN to DN */
+ rdnt = PyList_AsTuple(rdn);
+ Py_DECREF(rdn);
+ if (rdnt == NULL)
+ goto fail0;
+ retcode = PyList_Append(dn, rdnt);
+ Py_DECREF(rdnt);
+ if (retcode < 0)
+ goto fail0;
+ /* create new RDN */
+ rdn = PyList_New(0);
+ if (rdn == NULL)
+ goto fail0;
+ }
+ }
+ rdn_level = entry->set;
+ /* now add this attribute to the current RDN */
+ name = X509_NAME_ENTRY_get_object(entry);
value = X509_NAME_ENTRY_get_data(entry);
- buflen = ASN1_STRING_to_UTF8(&valuebuf, value);
- if (buflen < 0) {
- Py_DECREF(name_obj);
+ attr = _create_tuple_for_attribute(name, value);
+ /*
+ fprintf(stderr, "RDN level %d, attribute %s: %s\n",
+ entry->set,
+ PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)),
+ PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1)));
+ */
+ if (attr == NULL)
+ goto fail1;
+ retcode = PyList_Append(rdn, attr);
+ Py_DECREF(attr);
+ if (retcode < 0)
+ goto fail1;
+ }
+ /* now, there's typically a dangling RDN */
+ if ((rdn != NULL) && (PyList_Size(rdn) > 0)) {
+ rdnt = PyList_AsTuple(rdn);
+ Py_DECREF(rdn);
+ if (rdnt == NULL)
goto fail0;
- }
- value_obj = PyUnicode_DecodeUTF8((char *) valuebuf,
- buflen, "strict");
- OPENSSL_free(valuebuf);
- if (value_obj == NULL) {
- Py_DECREF(name_obj);
+ retcode = PyList_Append(dn, rdnt);
+ Py_DECREF(rdnt);
+ if (retcode < 0)
goto fail0;
+ }
+
+ /* convert list to tuple */
+ rdnt = PyList_AsTuple(dn);
+ Py_DECREF(dn);
+ if (rdnt == NULL)
+ return NULL;
+ return rdnt;
+
+ fail1:
+ Py_XDECREF(rdn);
+
+ fail0:
+ Py_XDECREF(dn);
+ return NULL;
+}
+
+static PyObject *
+_get_peer_alt_names (X509 *certificate) {
+
+ /* this code follows the procedure outlined in
+ OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print()
+ function to extract the STACK_OF(GENERAL_NAME),
+ then iterates through the stack to add the
+ names. */
+
+ int i, j;
+ PyObject *peer_alt_names = Py_None;
+ PyObject *v, *t;
+ X509_EXTENSION *ext = NULL;
+ GENERAL_NAMES *names = NULL;
+ GENERAL_NAME *name;
+ X509V3_EXT_METHOD *method;
+ BIO *biobuf = NULL;
+ char buf[2048];
+ char *vptr;
+ int len;
+ unsigned char *p;
+
+ if (certificate == NULL)
+ return peer_alt_names;
+
+ /* get a memory buffer */
+ biobuf = BIO_new(BIO_s_mem());
+
+ i = 0;
+ while ((i = X509_get_ext_by_NID(
+ certificate, NID_subject_alt_name, i)) >= 0) {
+
+ if (peer_alt_names == Py_None) {
+ peer_alt_names = PyList_New(0);
+ if (peer_alt_names == NULL)
+ goto fail;
}
- entry_tuple = PyTuple_New(2);
- if (entry_tuple == NULL) {
- Py_DECREF(name_obj);
- Py_DECREF(value_obj);
- goto fail0;
+
+ /* now decode the altName */
+ ext = X509_get_ext(certificate, i);
+ if(!(method = X509V3_EXT_get(ext))) {
+ PyErr_SetString(PySSLErrorObject,
+ ERRSTR("No method for internalizing subjectAltName!"));
+ goto fail;
+ }
+
+ p = ext->value->data;
+ if(method->it)
+ names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL,
+ &p,
+ ext->value->length,
+ ASN1_ITEM_ptr(method->it)));
+ else
+ names = (GENERAL_NAMES*) (method->d2i(NULL,
+ &p,
+ ext->value->length));
+
+ for(j = 0; j < sk_GENERAL_NAME_num(names); j++) {
+
+ /* get a rendering of each name in the set of names */
+
+ name = sk_GENERAL_NAME_value(names, j);
+ if (name->type == GEN_DIRNAME) {
+
+ /* we special-case DirName as a tuple of tuples of attributes */
+
+ t = PyTuple_New(2);
+ if (t == NULL) {
+ goto fail;
+ }
+
+ v = PyString_FromString("DirName");
+ if (v == NULL) {
+ Py_DECREF(t);
+ goto fail;
+ }
+ PyTuple_SET_ITEM(t, 0, v);
+
+ v = _create_tuple_for_X509_NAME (name->d.dirn);
+ if (v == NULL) {
+ Py_DECREF(t);
+ goto fail;
+ }
+ PyTuple_SET_ITEM(t, 1, v);
+
+ } else {
+
+ /* for everything else, we use the OpenSSL print form */
+
+ (void) BIO_reset(biobuf);
+ GENERAL_NAME_print(biobuf, name);
+ len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+ if (len < 0) {
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ goto fail;
+ }
+ vptr = strchr(buf, ':');
+ if (vptr == NULL)
+ goto fail;
+ t = PyTuple_New(2);
+ if (t == NULL)
+ goto fail;
+ v = PyString_FromStringAndSize(buf, (vptr - buf));
+ if (v == NULL) {
+ Py_DECREF(t);
+ goto fail;
+ }
+ PyTuple_SET_ITEM(t, 0, v);
+ v = PyString_FromStringAndSize((vptr + 1), (len - (vptr - buf + 1)));
+ if (v == NULL) {
+ Py_DECREF(t);
+ goto fail;
+ }
+ PyTuple_SET_ITEM(t, 1, v);
+ }
+
+ /* and add that rendering to the list */
+
+ if (PyList_Append(peer_alt_names, t) < 0) {
+ Py_DECREF(t);
+ goto fail;
+ }
+ Py_DECREF(t);
}
- PyTuple_SET_ITEM(entry_tuple, 0, name_obj);
- PyTuple_SET_ITEM(entry_tuple, 1, value_obj);
- PyTuple_SET_ITEM(pt, index_counter, entry_tuple);
}
- return pt;
+ BIO_free(biobuf);
+ if (peer_alt_names != Py_None) {
+ v = PyList_AsTuple(peer_alt_names);
+ Py_DECREF(peer_alt_names);
+ return v;
+ } else {
+ return peer_alt_names;
+ }
+
+
+ fail:
+ if (biobuf != NULL)
+ BIO_free(biobuf);
+
+ if (peer_alt_names != Py_None) {
+ Py_XDECREF(peer_alt_names);
+ }
- fail0:
- Py_XDECREF(pt);
return NULL;
}
static PyObject *
-PySSL_peercert(PySSLObject *self)
-{
+_decode_certificate (X509 *certificate, int verbose) {
+
PyObject *retval = NULL;
BIO *biobuf = NULL;
PyObject *peer;
+ PyObject *peer_alt_names = NULL;
PyObject *issuer;
PyObject *version;
+ PyObject *sn_obj;
+ ASN1_INTEGER *serialNumber;
char buf[2048];
int len;
ASN1_TIME *notBefore, *notAfter;
PyObject *pnotBefore, *pnotAfter;
- int verification;
-
- if (!self->peer_cert)
- Py_RETURN_NONE;
retval = PyDict_New();
if (retval == NULL)
return NULL;
- verification = SSL_CTX_get_verify_mode(self->ctx);
- if ((verification & SSL_VERIFY_PEER) == 0)
- return retval;
-
peer = _create_tuple_for_X509_NAME(
- X509_get_subject_name(self->peer_cert));
+ X509_get_subject_name(certificate));
if (peer == NULL)
goto fail0;
if (PyDict_SetItemString(retval, (const char *) "subject", peer) < 0) {
@@ -535,51 +816,98 @@ PySSL_peercert(PySSLObject *self)
}
Py_DECREF(peer);
- issuer = _create_tuple_for_X509_NAME(
- X509_get_issuer_name(self->peer_cert));
- if (issuer == NULL)
- goto fail0;
- if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) {
+ if (verbose) {
+ issuer = _create_tuple_for_X509_NAME(
+ X509_get_issuer_name(certificate));
+ if (issuer == NULL)
+ goto fail0;
+ if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) {
+ Py_DECREF(issuer);
+ goto fail0;
+ }
Py_DECREF(issuer);
- goto fail0;
- }
- Py_DECREF(issuer);
-
- version = PyInt_FromLong(X509_get_version(self->peer_cert));
- if (PyDict_SetItemString(retval, "version", version) < 0) {
+
+ version = PyInt_FromLong(X509_get_version(certificate) + 1);
+ if (PyDict_SetItemString(retval, "version", version) < 0) {
+ Py_DECREF(version);
+ goto fail0;
+ }
Py_DECREF(version);
- goto fail0;
}
- Py_DECREF(version);
-
+
/* get a memory buffer */
biobuf = BIO_new(BIO_s_mem());
-
- notBefore = X509_get_notBefore(self->peer_cert);
- ASN1_TIME_print(biobuf, notBefore);
- len = BIO_gets(biobuf, buf, sizeof(buf)-1);
- pnotBefore = PyString_FromStringAndSize(buf, len);
- if (pnotBefore == NULL)
- goto fail1;
- if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) {
+
+ if (verbose) {
+
+ (void) BIO_reset(biobuf);
+ serialNumber = X509_get_serialNumber(certificate);
+ /* should not exceed 20 octets, 160 bits, so buf is big enough */
+ i2a_ASN1_INTEGER(biobuf, serialNumber);
+ len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+ if (len < 0) {
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ goto fail1;
+ }
+ sn_obj = PyString_FromStringAndSize(buf, len);
+ if (sn_obj == NULL)
+ goto fail1;
+ if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) {
+ Py_DECREF(sn_obj);
+ goto fail1;
+ }
+ Py_DECREF(sn_obj);
+
+ (void) BIO_reset(biobuf);
+ notBefore = X509_get_notBefore(certificate);
+ ASN1_TIME_print(biobuf, notBefore);
+ len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+ if (len < 0) {
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ goto fail1;
+ }
+ pnotBefore = PyString_FromStringAndSize(buf, len);
+ if (pnotBefore == NULL)
+ goto fail1;
+ if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) {
+ Py_DECREF(pnotBefore);
+ goto fail1;
+ }
Py_DECREF(pnotBefore);
- goto fail1;
}
- Py_DECREF(pnotBefore);
(void) BIO_reset(biobuf);
- notAfter = X509_get_notAfter(self->peer_cert);
+ notAfter = X509_get_notAfter(certificate);
ASN1_TIME_print(biobuf, notAfter);
len = BIO_gets(biobuf, buf, sizeof(buf)-1);
- BIO_free(biobuf);
+ if (len < 0) {
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ goto fail1;
+ }
pnotAfter = PyString_FromStringAndSize(buf, len);
if (pnotAfter == NULL)
- goto fail0;
+ goto fail1;
if (PyDict_SetItemString(retval, "notAfter", pnotAfter) < 0) {
Py_DECREF(pnotAfter);
- goto fail0;
+ goto fail1;
}
Py_DECREF(pnotAfter);
+
+ /* Now look for subjectAltName */
+
+ peer_alt_names = _get_peer_alt_names(certificate);
+ if (peer_alt_names == NULL)
+ goto fail1;
+ else if (peer_alt_names != Py_None) {
+ if (PyDict_SetItemString(retval, "subjectAltName",
+ peer_alt_names) < 0) {
+ Py_DECREF(peer_alt_names);
+ goto fail1;
+ }
+ Py_DECREF(peer_alt_names);
+ }
+
+ BIO_free(biobuf);
return retval;
fail1:
@@ -590,6 +918,141 @@ PySSL_peercert(PySSLObject *self)
return NULL;
}
+
+static PyObject *
+PySSL_test_decode_certificate (PyObject *mod, PyObject *args) {
+
+ PyObject *retval = NULL;
+ char *filename = NULL;
+ X509 *x=NULL;
+ BIO *cert;
+ int verbose = 1;
+
+ if (!PyArg_ParseTuple(args, "s|i:test_decode_certificate", &filename, &verbose))
+ return NULL;
+
+ if ((cert=BIO_new(BIO_s_file())) == NULL) {
+ PyErr_SetString(PySSLErrorObject, "Can't malloc memory to read file");
+ goto fail0;
+ }
+
+ if (BIO_read_filename(cert,filename) <= 0) {
+ PyErr_SetString(PySSLErrorObject, "Can't open file");
+ goto fail0;
+ }
+
+ x = PEM_read_bio_X509_AUX(cert,NULL, NULL, NULL);
+ if (x == NULL) {
+ PyErr_SetString(PySSLErrorObject, "Error decoding PEM-encoded file");
+ goto fail0;
+ }
+
+ retval = _decode_certificate(x, verbose);
+
+ fail0:
+
+ if (cert != NULL) BIO_free(cert);
+ return retval;
+}
+
+
+static PyObject *
+PySSL_peercert(PySSLObject *self, PyObject *args)
+{
+ PyObject *retval = NULL;
+ int len;
+ int verification;
+ PyObject *binary_mode = Py_None;
+
+ if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode))
+ return NULL;
+
+ if (!self->peer_cert)
+ Py_RETURN_NONE;
+
+ if (PyObject_IsTrue(binary_mode)) {
+ /* return cert in DER-encoded format */
+
+ unsigned char *bytes_buf = NULL;
+
+ bytes_buf = NULL;
+ len = i2d_X509(self->peer_cert, &bytes_buf);
+ if (len < 0) {
+ PySSL_SetError(self, len, __FILE__, __LINE__);
+ return NULL;
+ }
+ retval = PyString_FromStringAndSize((const char *) bytes_buf, len);
+ OPENSSL_free(bytes_buf);
+ return retval;
+
+ } else {
+
+ verification = SSL_CTX_get_verify_mode(self->ctx);
+ if ((verification & SSL_VERIFY_PEER) == 0)
+ return PyDict_New();
+ else
+ return _decode_certificate (self->peer_cert, 0);
+ }
+}
+
+PyDoc_STRVAR(PySSL_peercert_doc,
+"peer_certificate([der=False]) -> certificate\n\
+\n\
+Returns the certificate for the peer. If no certificate was provided,\n\
+returns None. If a certificate was provided, but not validated, returns\n\
+an empty dictionary. Otherwise returns a dict containing information\n\
+about the peer certificate.\n\
+\n\
+If the optional argument is True, returns a DER-encoded copy of the\n\
+peer certificate, or None if no certificate was provided. This will\n\
+return the certificate even if it wasn't validated.");
+
+static PyObject *PySSL_cipher (PySSLObject *self) {
+
+ PyObject *retval, *v;
+ SSL_CIPHER *current;
+ char *cipher_name;
+ char *cipher_protocol;
+
+ if (self->ssl == NULL)
+ return Py_None;
+ current = SSL_get_current_cipher(self->ssl);
+ if (current == NULL)
+ return Py_None;
+
+ retval = PyTuple_New(3);
+ if (retval == NULL)
+ return NULL;
+
+ cipher_name = (char *) SSL_CIPHER_get_name(current);
+ if (cipher_name == NULL) {
+ PyTuple_SET_ITEM(retval, 0, Py_None);
+ } else {
+ v = PyString_FromString(cipher_name);
+ if (v == NULL)
+ goto fail0;
+ PyTuple_SET_ITEM(retval, 0, v);
+ }
+ cipher_protocol = SSL_CIPHER_get_version(current);
+ if (cipher_protocol == NULL) {
+ PyTuple_SET_ITEM(retval, 1, Py_None);
+ } else {
+ v = PyString_FromString(cipher_protocol);
+ if (v == NULL)
+ goto fail0;
+ PyTuple_SET_ITEM(retval, 1, v);
+ }
+ v = PyInt_FromLong(SSL_CIPHER_get_bits(current, NULL));
+ if (v == NULL)
+ goto fail0;
+ PyTuple_SET_ITEM(retval, 2, v);
+ return retval;
+
+ fail0:
+ Py_DECREF(retval);
+ return NULL;
+}
+
static void PySSL_dealloc(PySSLObject *self)
{
if (self->peer_cert) /* Possible not to have one? */
@@ -636,9 +1099,9 @@ check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
/* s->sock_timeout is in seconds, timeout in ms */
timeout = (int)(s->sock_timeout * 1000 + 0.5);
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
rc = poll(&pollfd, 1, timeout);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
goto normal_return;
}
@@ -657,12 +1120,12 @@ check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
FD_SET(s->sock_fd, &fds);
/* See if the socket is ready */
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
if (writing)
rc = select(s->sock_fd+1, NULL, &fds, NULL, &tv);
else
rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
normal_return:
/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
@@ -697,10 +1160,10 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args)
}
do {
err = 0;
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
len = SSL_write(self->ssl, data, count);
err = SSL_get_error(self->ssl, len);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
if(PyErr_CheckSignals()) {
return NULL;
}
@@ -752,9 +1215,9 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
return NULL;
/* first check if there are bytes ready to be read */
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
count = SSL_pending(self->ssl);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
if (!count) {
sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
@@ -769,26 +1232,17 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
Py_DECREF(buf);
return NULL;
} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
- if (SSL_get_shutdown(self->ssl) !=
- SSL_RECEIVED_SHUTDOWN)
- {
- Py_DECREF(buf);
- PyErr_SetString(PySSLErrorObject,
- "Socket closed without SSL shutdown handshake");
- return NULL;
- } else {
- /* should contain a zero-length string */
- _PyString_Resize(&buf, 0);
- return buf;
- }
+ /* should contain a zero-length string */
+ _PyString_Resize(&buf, 0);
+ return buf;
}
}
do {
err = 0;
- Py_BEGIN_ALLOW_THREADS
+ PySSL_BEGIN_ALLOW_THREADS
count = SSL_read(self->ssl, PyBytes_AS_STRING(buf), len);
err = SSL_get_error(self->ssl, count);
- Py_END_ALLOW_THREADS
+ PySSL_END_ALLOW_THREADS
if(PyErr_CheckSignals()) {
Py_DECREF(buf);
return NULL;
@@ -834,49 +1288,16 @@ PyDoc_STRVAR(PySSL_SSLread_doc,
\n\
Read up to len bytes from the SSL socket.");
-static PyObject *PySSL_SSLshutdown(PySSLObject *self, PyObject *args)
-{
- int err;
-
- /* Guard against closed socket */
- if (self->Socket->sock_fd < 0) {
- PyErr_SetString(PySSLErrorObject,
- "Underlying socket has been closed.");
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- err = SSL_shutdown(self->ssl);
- if (err == 0) {
- /* we need to call it again to finish the shutdown */
- err = SSL_shutdown(self->ssl);
- }
- Py_END_ALLOW_THREADS
-
- if (err < 0)
- return PySSL_SetError(self, err, __FILE__, __LINE__);
- else {
- Py_INCREF(self->Socket);
- return (PyObject *) (self->Socket);
- }
-}
-
-PyDoc_STRVAR(PySSL_SSLshutdown_doc,
-"shutdown(s) -> socket\n\
-\n\
-Does the SSL shutdown handshake with the remote end, and returns\n\
-the underlying socket object.");
-
static PyMethodDef PySSLMethods[] = {
{"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS,
- PySSL_SSLwrite_doc},
+ PySSL_SSLwrite_doc},
{"read", (PyCFunction)PySSL_SSLread, METH_VARARGS,
- PySSL_SSLread_doc},
+ PySSL_SSLread_doc},
{"server", (PyCFunction)PySSL_server, METH_NOARGS},
{"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS},
- {"peer_certificate", (PyCFunction)PySSL_peercert, METH_NOARGS},
- {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS,
- PySSL_SSLshutdown_doc},
+ {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS,
+ PySSL_peercert_doc},
+ {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS},
{NULL, NULL}
};
@@ -924,7 +1345,7 @@ PyDoc_STRVAR(PySSL_RAND_add_doc,
"RAND_add(string, entropy)\n\
\n\
Mix string into the OpenSSL PRNG state. entropy (a float) is a lower\n\
-bound on the entropy contained in string.");
+bound on the entropy contained in string. See RFC 1750.");
static PyObject *
PySSL_RAND_status(PyObject *self)
@@ -961,9 +1382,9 @@ PySSL_RAND_egd(PyObject *self, PyObject *arg)
PyDoc_STRVAR(PySSL_RAND_egd_doc,
"RAND_egd(path) -> bytes\n\
\n\
-Queries the entropy gather daemon (EGD) on socket path. Returns number\n\
-of bytes read. Raises ssl.sslerror if connection to EGD fails or\n\
-if it does provide enough data to seed PRNG.");
+Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\
+Returns number of bytes read. Raises SSLError if connection to EGD\n\
+fails or if it does provide enough data to seed PRNG.");
#endif
@@ -972,6 +1393,8 @@ if it does provide enough data to seed PRNG.");
static PyMethodDef PySSL_methods[] = {
{"sslwrap", PySSL_sslwrap,
METH_VARARGS, ssl_doc},
+ {"_test_decode_cert", PySSL_test_decode_certificate,
+ METH_VARARGS},
#ifdef HAVE_OPENSSL_RAND
{"RAND_add", PySSL_RAND_add, METH_VARARGS,
PySSL_RAND_add_doc},
@@ -984,6 +1407,73 @@ static PyMethodDef PySSL_methods[] = {
};
+#ifdef WITH_THREAD
+
+/* an implementation of OpenSSL threading operations in terms
+ of the Python C thread library */
+
+static PyThread_type_lock *_ssl_locks = NULL;
+
+static unsigned long _ssl_thread_id_function (void) {
+ return PyThread_get_thread_ident();
+}
+
+static void _ssl_thread_locking_function (int mode, int n, const char *file, int line) {
+ /* this function is needed to perform locking on shared data
+ structures. (Note that OpenSSL uses a number of global data
+ structures that will be implicitly shared whenever multiple threads
+ use OpenSSL.) Multi-threaded applications will crash at random if
+ it is not set.
+
+ locking_function() must be able to handle up to CRYPTO_num_locks()
+ different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
+ releases it otherwise.
+
+ file and line are the file number of the function setting the
+ lock. They can be useful for debugging.
+ */
+
+ if ((_ssl_locks == NULL) ||
+ (n < 0) || (n >= _ssl_locks_count))
+ return;
+
+ if (mode & CRYPTO_LOCK) {
+ PyThread_acquire_lock(_ssl_locks[n], 1);
+ } else {
+ PyThread_release_lock(_ssl_locks[n]);
+ }
+}
+
+static int _setup_ssl_threads(void) {
+
+ int i;
+
+ if (_ssl_locks == NULL) {
+ _ssl_locks_count = CRYPTO_num_locks();
+ _ssl_locks = (PyThread_type_lock *)
+ malloc(sizeof(PyThread_type_lock) * _ssl_locks_count);
+ if (_ssl_locks == NULL)
+ return 0;
+ memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count);
+ for (i = 0; i < _ssl_locks_count; i++) {
+ _ssl_locks[i] = PyThread_allocate_lock();
+ if (_ssl_locks[i] == NULL) {
+ int j;
+ for (j = 0; j < i; j++) {
+ PyThread_free_lock(_ssl_locks[j]);
+ }
+ free(_ssl_locks);
+ return 0;
+ }
+ }
+ CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+ CRYPTO_set_id_callback(_ssl_thread_id_function);
+ }
+ return 1;
+}
+
+#endif /* def HAVE_THREAD */
+
PyDoc_STRVAR(module_doc,
"Implementation module for SSL socket operations. See the socket module\n\
for documentation.");
@@ -1006,15 +1496,21 @@ init_ssl(void)
/* Init OpenSSL */
SSL_load_error_strings();
+#ifdef WITH_THREAD
+ /* note that this will start threading if not already started */
+ if (!_setup_ssl_threads()) {
+ return;
+ }
+#endif
SSLeay_add_ssl_algorithms();
/* Add symbols to module dict */
- PySSLErrorObject = PyErr_NewException("ssl.sslerror",
+ PySSLErrorObject = PyErr_NewException("ssl.SSLError",
PySocketModule.error,
NULL);
if (PySSLErrorObject == NULL)
return;
- if (PyDict_SetItemString(d, "sslerror", PySSLErrorObject) != 0)
+ if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0)
return;
if (PyDict_SetItemString(d, "SSLType",
(PyObject *)&PySSL_Type) != 0)