Commit a4c2a5c9 authored by Antoine Pitrou's avatar Antoine Pitrou

Untabify Modules/_ssl.c

parent 91165c0b
...@@ -19,14 +19,14 @@ ...@@ -19,14 +19,14 @@
#ifdef WITH_THREAD #ifdef WITH_THREAD
#include "pythread.h" #include "pythread.h"
#define PySSL_BEGIN_ALLOW_THREADS { \ #define PySSL_BEGIN_ALLOW_THREADS { \
PyThreadState *_save = NULL; \ PyThreadState *_save = NULL; \
if (_ssl_locks_count>0) {_save = PyEval_SaveThread();} if (_ssl_locks_count>0) {_save = PyEval_SaveThread();}
#define PySSL_BLOCK_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save)}; #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_UNBLOCK_THREADS if (_ssl_locks_count>0){_save = PyEval_SaveThread()};
#define PySSL_END_ALLOW_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \ #define PySSL_END_ALLOW_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \
} }
#else /* no WITH_THREAD */ #else /* no WITH_THREAD */
#define PySSL_BEGIN_ALLOW_THREADS #define PySSL_BEGIN_ALLOW_THREADS
#define PySSL_BLOCK_THREADS #define PySSL_BLOCK_THREADS
...@@ -36,36 +36,36 @@ ...@@ -36,36 +36,36 @@
#endif #endif
enum py_ssl_error { enum py_ssl_error {
/* these mirror ssl.h */ /* these mirror ssl.h */
PY_SSL_ERROR_NONE, PY_SSL_ERROR_NONE,
PY_SSL_ERROR_SSL, PY_SSL_ERROR_SSL,
PY_SSL_ERROR_WANT_READ, PY_SSL_ERROR_WANT_READ,
PY_SSL_ERROR_WANT_WRITE, PY_SSL_ERROR_WANT_WRITE,
PY_SSL_ERROR_WANT_X509_LOOKUP, PY_SSL_ERROR_WANT_X509_LOOKUP,
PY_SSL_ERROR_SYSCALL, /* look at error stack/return value/errno */ PY_SSL_ERROR_SYSCALL, /* look at error stack/return value/errno */
PY_SSL_ERROR_ZERO_RETURN, PY_SSL_ERROR_ZERO_RETURN,
PY_SSL_ERROR_WANT_CONNECT, PY_SSL_ERROR_WANT_CONNECT,
/* start of non ssl.h errorcodes */ /* start of non ssl.h errorcodes */
PY_SSL_ERROR_EOF, /* special case of SSL_ERROR_SYSCALL */ PY_SSL_ERROR_EOF, /* special case of SSL_ERROR_SYSCALL */
PY_SSL_ERROR_INVALID_ERROR_CODE PY_SSL_ERROR_INVALID_ERROR_CODE
}; };
enum py_ssl_server_or_client { enum py_ssl_server_or_client {
PY_SSL_CLIENT, PY_SSL_CLIENT,
PY_SSL_SERVER PY_SSL_SERVER
}; };
enum py_ssl_cert_requirements { enum py_ssl_cert_requirements {
PY_SSL_CERT_NONE, PY_SSL_CERT_NONE,
PY_SSL_CERT_OPTIONAL, PY_SSL_CERT_OPTIONAL,
PY_SSL_CERT_REQUIRED PY_SSL_CERT_REQUIRED
}; };
enum py_ssl_version { enum py_ssl_version {
PY_SSL_VERSION_SSL2, PY_SSL_VERSION_SSL2,
PY_SSL_VERSION_SSL3, PY_SSL_VERSION_SSL3,
PY_SSL_VERSION_SSL23, PY_SSL_VERSION_SSL23,
PY_SSL_VERSION_TLS1 PY_SSL_VERSION_TLS1
}; };
/* Include symbols from _socket module */ /* Include symbols from _socket module */
...@@ -111,14 +111,14 @@ static unsigned int _ssl_locks_count = 0; ...@@ -111,14 +111,14 @@ static unsigned int _ssl_locks_count = 0;
#endif #endif
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PySocketSockObject *Socket; /* Socket on which we're layered */ PySocketSockObject *Socket; /* Socket on which we're layered */
SSL_CTX* ctx; SSL_CTX* ctx;
SSL* ssl; SSL* ssl;
X509* peer_cert; X509* peer_cert;
char server[X509_NAME_MAXLEN]; char server[X509_NAME_MAXLEN];
char issuer[X509_NAME_MAXLEN]; char issuer[X509_NAME_MAXLEN];
int shutdown_seen_zero; int shutdown_seen_zero;
} PySSLObject; } PySSLObject;
...@@ -126,19 +126,19 @@ static PyTypeObject PySSL_Type; ...@@ -126,19 +126,19 @@ static PyTypeObject PySSL_Type;
static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args);
static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args);
static int check_socket_and_wait_for_timeout(PySocketSockObject *s, static int check_socket_and_wait_for_timeout(PySocketSockObject *s,
int writing); int writing);
static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args); static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args);
static PyObject *PySSL_cipher(PySSLObject *self); static PyObject *PySSL_cipher(PySSLObject *self);
#define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type) #define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type)
typedef enum { typedef enum {
SOCKET_IS_NONBLOCKING, SOCKET_IS_NONBLOCKING,
SOCKET_IS_BLOCKING, SOCKET_IS_BLOCKING,
SOCKET_HAS_TIMED_OUT, SOCKET_HAS_TIMED_OUT,
SOCKET_HAS_BEEN_CLOSED, SOCKET_HAS_BEEN_CLOSED,
SOCKET_TOO_LARGE_FOR_SELECT, SOCKET_TOO_LARGE_FOR_SELECT,
SOCKET_OPERATION_OK SOCKET_OPERATION_OK
} timeout_state; } timeout_state;
/* Wrap error strings with filename and line # */ /* Wrap error strings with filename and line # */
...@@ -155,294 +155,294 @@ typedef enum { ...@@ -155,294 +155,294 @@ typedef enum {
static PyObject * static PyObject *
PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno) PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno)
{ {
PyObject *v; PyObject *v;
char buf[2048]; char buf[2048];
char *errstr; char *errstr;
int err; int err;
enum py_ssl_error p = PY_SSL_ERROR_NONE; enum py_ssl_error p = PY_SSL_ERROR_NONE;
assert(ret <= 0); assert(ret <= 0);
if (obj->ssl != NULL) { if (obj->ssl != NULL) {
err = SSL_get_error(obj->ssl, ret); err = SSL_get_error(obj->ssl, ret);
switch (err) { switch (err) {
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
errstr = "TLS/SSL connection has been closed"; errstr = "TLS/SSL connection has been closed";
p = PY_SSL_ERROR_ZERO_RETURN; p = PY_SSL_ERROR_ZERO_RETURN;
break; break;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
errstr = "The operation did not complete (read)"; errstr = "The operation did not complete (read)";
p = PY_SSL_ERROR_WANT_READ; p = PY_SSL_ERROR_WANT_READ;
break; break;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
p = PY_SSL_ERROR_WANT_WRITE; p = PY_SSL_ERROR_WANT_WRITE;
errstr = "The operation did not complete (write)"; errstr = "The operation did not complete (write)";
break; break;
case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_WANT_X509_LOOKUP:
p = PY_SSL_ERROR_WANT_X509_LOOKUP; p = PY_SSL_ERROR_WANT_X509_LOOKUP;
errstr = errstr =
"The operation did not complete (X509 lookup)"; "The operation did not complete (X509 lookup)";
break; break;
case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_CONNECT:
p = PY_SSL_ERROR_WANT_CONNECT; p = PY_SSL_ERROR_WANT_CONNECT;
errstr = "The operation did not complete (connect)"; errstr = "The operation did not complete (connect)";
break; break;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
{ {
unsigned long e = ERR_get_error(); unsigned long e = ERR_get_error();
if (e == 0) { if (e == 0) {
if (ret == 0 || !obj->Socket) { if (ret == 0 || !obj->Socket) {
p = PY_SSL_ERROR_EOF; p = PY_SSL_ERROR_EOF;
errstr = errstr =
"EOF occurred in violation of protocol"; "EOF occurred in violation of protocol";
} else if (ret == -1) { } else if (ret == -1) {
/* underlying BIO reported an I/O error */ /* underlying BIO reported an I/O error */
return obj->Socket->errorhandler(); return obj->Socket->errorhandler();
} else { /* possible? */ } else { /* possible? */
p = PY_SSL_ERROR_SYSCALL; p = PY_SSL_ERROR_SYSCALL;
errstr = "Some I/O error occurred"; errstr = "Some I/O error occurred";
} }
} else { } else {
p = PY_SSL_ERROR_SYSCALL; p = PY_SSL_ERROR_SYSCALL;
/* XXX Protected by global interpreter lock */ /* XXX Protected by global interpreter lock */
errstr = ERR_error_string(e, NULL); errstr = ERR_error_string(e, NULL);
} }
break; break;
} }
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
{ {
unsigned long e = ERR_get_error(); unsigned long e = ERR_get_error();
p = PY_SSL_ERROR_SSL; p = PY_SSL_ERROR_SSL;
if (e != 0) if (e != 0)
/* XXX Protected by global interpreter lock */ /* XXX Protected by global interpreter lock */
errstr = ERR_error_string(e, NULL); errstr = ERR_error_string(e, NULL);
else { /* possible? */ else { /* possible? */
errstr = errstr =
"A failure in the SSL library occurred"; "A failure in the SSL library occurred";
} }
break; break;
} }
default: default:
p = PY_SSL_ERROR_INVALID_ERROR_CODE; p = PY_SSL_ERROR_INVALID_ERROR_CODE;
errstr = "Invalid error code"; errstr = "Invalid error code";
} }
} else { } else {
errstr = ERR_error_string(ERR_peek_last_error(), NULL); errstr = ERR_error_string(ERR_peek_last_error(), NULL);
} }
PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr); PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
v = Py_BuildValue("(is)", p, buf); v = Py_BuildValue("(is)", p, buf);
if (v != NULL) { if (v != NULL) {
PyErr_SetObject(PySSLErrorObject, v); PyErr_SetObject(PySSLErrorObject, v);
Py_DECREF(v); Py_DECREF(v);
} }
return NULL; return NULL;
} }
static PyObject * static PyObject *
_setSSLError (char *errstr, int errcode, char *filename, int lineno) { _setSSLError (char *errstr, int errcode, char *filename, int lineno) {
char buf[2048]; char buf[2048];
PyObject *v; PyObject *v;
if (errstr == NULL) { if (errstr == NULL) {
errcode = ERR_peek_last_error(); errcode = ERR_peek_last_error();
errstr = ERR_error_string(errcode, NULL); errstr = ERR_error_string(errcode, NULL);
} }
PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr); PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
v = Py_BuildValue("(is)", errcode, buf); v = Py_BuildValue("(is)", errcode, buf);
if (v != NULL) { if (v != NULL) {
PyErr_SetObject(PySSLErrorObject, v); PyErr_SetObject(PySSLErrorObject, v);
Py_DECREF(v); Py_DECREF(v);
} }
return NULL; return NULL;
} }
static PySSLObject * static PySSLObject *
newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file, newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
enum py_ssl_server_or_client socket_type, enum py_ssl_server_or_client socket_type,
enum py_ssl_cert_requirements certreq, enum py_ssl_cert_requirements certreq,
enum py_ssl_version proto_version, enum py_ssl_version proto_version,
char *cacerts_file, char *ciphers) char *cacerts_file, char *ciphers)
{ {
PySSLObject *self; PySSLObject *self;
char *errstr = NULL; char *errstr = NULL;
int ret; int ret;
int verification_mode; int verification_mode;
self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
if (self == NULL) if (self == NULL)
return NULL; return NULL;
memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN); memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN);
memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN);
self->peer_cert = NULL; self->peer_cert = NULL;
self->ssl = NULL; self->ssl = NULL;
self->ctx = NULL; self->ctx = NULL;
self->Socket = NULL; self->Socket = NULL;
/* Make sure the SSL error state is initialized */ /* Make sure the SSL error state is initialized */
(void) ERR_get_state(); (void) ERR_get_state();
ERR_clear_error(); ERR_clear_error();
if ((key_file && !cert_file) || (!key_file && cert_file)) { if ((key_file && !cert_file) || (!key_file && cert_file)) {
errstr = ERRSTR("Both the key & certificate files " errstr = ERRSTR("Both the key & certificate files "
"must be specified"); "must be specified");
goto fail; goto fail;
} }
if ((socket_type == PY_SSL_SERVER) && if ((socket_type == PY_SSL_SERVER) &&
((key_file == NULL) || (cert_file == NULL))) { ((key_file == NULL) || (cert_file == NULL))) {
errstr = ERRSTR("Both the key & certificate files " errstr = ERRSTR("Both the key & certificate files "
"must be specified for server-side operation"); "must be specified for server-side operation");
goto fail; goto fail;
} }
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
if (proto_version == PY_SSL_VERSION_TLS1) if (proto_version == PY_SSL_VERSION_TLS1)
self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */ self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */
else if (proto_version == PY_SSL_VERSION_SSL3) else if (proto_version == PY_SSL_VERSION_SSL3)
self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */ self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */
else if (proto_version == PY_SSL_VERSION_SSL2) else if (proto_version == PY_SSL_VERSION_SSL2)
self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */
else if (proto_version == PY_SSL_VERSION_SSL23) else if (proto_version == PY_SSL_VERSION_SSL23)
self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if (self->ctx == NULL) { if (self->ctx == NULL) {
errstr = ERRSTR("Invalid SSL protocol variant specified."); errstr = ERRSTR("Invalid SSL protocol variant specified.");
goto fail; goto fail;
} }
if (ciphers != NULL) { if (ciphers != NULL) {
ret = SSL_CTX_set_cipher_list(self->ctx, ciphers); ret = SSL_CTX_set_cipher_list(self->ctx, ciphers);
if (ret == 0) { if (ret == 0) {
errstr = ERRSTR("No cipher can be selected."); errstr = ERRSTR("No cipher can be selected.");
goto fail; goto fail;
} }
} }
if (certreq != PY_SSL_CERT_NONE) { if (certreq != PY_SSL_CERT_NONE) {
if (cacerts_file == NULL) { if (cacerts_file == NULL) {
errstr = ERRSTR("No root certificates specified for " errstr = ERRSTR("No root certificates specified for "
"verification of other-side certificates."); "verification of other-side certificates.");
goto fail; goto fail;
} else { } else {
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
ret = SSL_CTX_load_verify_locations(self->ctx, ret = SSL_CTX_load_verify_locations(self->ctx,
cacerts_file, cacerts_file,
NULL); NULL);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if (ret != 1) { if (ret != 1) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
goto fail; goto fail;
} }
} }
} }
if (key_file) { if (key_file) {
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
SSL_FILETYPE_PEM); SSL_FILETYPE_PEM);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if (ret != 1) { if (ret != 1) {
_setSSLError(NULL, ret, __FILE__, __LINE__); _setSSLError(NULL, ret, __FILE__, __LINE__);
goto fail; goto fail;
} }
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
ret = SSL_CTX_use_certificate_chain_file(self->ctx, ret = SSL_CTX_use_certificate_chain_file(self->ctx,
cert_file); cert_file);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if (ret != 1) { if (ret != 1) {
/* /*
fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n", fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
ret, ERR_peek_error(), ERR_peek_last_error(), cert_file); ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
*/ */
if (ERR_peek_last_error() != 0) { if (ERR_peek_last_error() != 0) {
_setSSLError(NULL, ret, __FILE__, __LINE__); _setSSLError(NULL, ret, __FILE__, __LINE__);
goto fail; goto fail;
} }
} }
} }
/* ssl compatibility */ /* ssl compatibility */
SSL_CTX_set_options(self->ctx, SSL_OP_ALL); SSL_CTX_set_options(self->ctx, SSL_OP_ALL);
verification_mode = SSL_VERIFY_NONE; verification_mode = SSL_VERIFY_NONE;
if (certreq == PY_SSL_CERT_OPTIONAL) if (certreq == PY_SSL_CERT_OPTIONAL)
verification_mode = SSL_VERIFY_PEER; verification_mode = SSL_VERIFY_PEER;
else if (certreq == PY_SSL_CERT_REQUIRED) else if (certreq == PY_SSL_CERT_REQUIRED)
verification_mode = (SSL_VERIFY_PEER | verification_mode = (SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT); SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
SSL_CTX_set_verify(self->ctx, verification_mode, SSL_CTX_set_verify(self->ctx, verification_mode,
NULL); /* set verify lvl */ NULL); /* set verify lvl */
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
self->ssl = SSL_new(self->ctx); /* New ssl struct */ self->ssl = SSL_new(self->ctx); /* New ssl struct */
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */
#ifdef SSL_MODE_AUTO_RETRY #ifdef SSL_MODE_AUTO_RETRY
SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY);
#endif #endif
/* If the socket is in non-blocking mode or timeout mode, set the BIO /* If the socket is in non-blocking mode or timeout mode, set the BIO
* to non-blocking mode (blocking is the default) * to non-blocking mode (blocking is the default)
*/ */
if (Sock->sock_timeout >= 0.0) { if (Sock->sock_timeout >= 0.0) {
/* Set both the read and write BIO's to non-blocking mode */ /* Set both the read and write BIO's to non-blocking mode */
BIO_set_nbio(SSL_get_rbio(self->ssl), 1); BIO_set_nbio(SSL_get_rbio(self->ssl), 1);
BIO_set_nbio(SSL_get_wbio(self->ssl), 1); BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
} }
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
if (socket_type == PY_SSL_CLIENT) if (socket_type == PY_SSL_CLIENT)
SSL_set_connect_state(self->ssl); SSL_set_connect_state(self->ssl);
else else
SSL_set_accept_state(self->ssl); SSL_set_accept_state(self->ssl);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
self->Socket = Sock; self->Socket = Sock;
Py_INCREF(self->Socket); Py_INCREF(self->Socket);
return self; return self;
fail: fail:
if (errstr) if (errstr)
PyErr_SetString(PySSLErrorObject, errstr); PyErr_SetString(PySSLErrorObject, errstr);
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
} }
static PyObject * static PyObject *
PySSL_sslwrap(PyObject *self, PyObject *args) PySSL_sslwrap(PyObject *self, PyObject *args)
{ {
PySocketSockObject *Sock; PySocketSockObject *Sock;
int server_side = 0; int server_side = 0;
int verification_mode = PY_SSL_CERT_NONE; int verification_mode = PY_SSL_CERT_NONE;
int protocol = PY_SSL_VERSION_SSL23; int protocol = PY_SSL_VERSION_SSL23;
char *key_file = NULL; char *key_file = NULL;
char *cert_file = NULL; char *cert_file = NULL;
char *cacerts_file = NULL; char *cacerts_file = NULL;
char *ciphers = NULL; char *ciphers = NULL;
if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap", if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap",
PySocketModule.Sock_Type, PySocketModule.Sock_Type,
&Sock, &Sock,
&server_side, &server_side,
&key_file, &cert_file, &key_file, &cert_file,
&verification_mode, &protocol, &verification_mode, &protocol,
&cacerts_file, &ciphers)) &cacerts_file, &ciphers))
return NULL; return NULL;
/* /*
fprintf(stderr, fprintf(stderr,
"server_side is %d, keyfile %p, certfile %p, verify_mode %d, " "server_side is %d, keyfile %p, certfile %p, verify_mode %d, "
"protocol %d, certs %p\n", "protocol %d, certs %p\n",
server_side, key_file, cert_file, verification_mode, server_side, key_file, cert_file, verification_mode,
protocol, cacerts_file); protocol, cacerts_file);
*/ */
return (PyObject *) newPySSLObject(Sock, key_file, cert_file, return (PyObject *) newPySSLObject(Sock, key_file, cert_file,
server_side, verification_mode, server_side, verification_mode,
protocol, cacerts_file, protocol, cacerts_file,
ciphers); ciphers);
} }
PyDoc_STRVAR(ssl_doc, PyDoc_STRVAR(ssl_doc,
...@@ -453,577 +453,577 @@ PyDoc_STRVAR(ssl_doc, ...@@ -453,577 +453,577 @@ PyDoc_STRVAR(ssl_doc,
static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) static PyObject *PySSL_SSLdo_handshake(PySSLObject *self)
{ {
int ret; int ret;
int err; int err;
int sockstate, nonblocking; int sockstate, nonblocking;
/* just in case the blocking state of the socket has been changed */ /* just in case the blocking state of the socket has been changed */
nonblocking = (self->Socket->sock_timeout >= 0.0); nonblocking = (self->Socket->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
/* Actually negotiate SSL connection */ /* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */ /* XXX If SSL_do_handshake() returns 0, it's also a failure. */
do { do {
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
ret = SSL_do_handshake(self->ssl); ret = SSL_do_handshake(self->ssl);
err = SSL_get_error(self->ssl, ret); err = SSL_get_error(self->ssl, ret);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if(PyErr_CheckSignals()) { if(PyErr_CheckSignals()) {
return NULL; return NULL;
} }
if (err == SSL_ERROR_WANT_READ) { if (err == SSL_ERROR_WANT_READ) {
sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
} else if (err == SSL_ERROR_WANT_WRITE) { } else if (err == SSL_ERROR_WANT_WRITE) {
sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
} else { } else {
sockstate = SOCKET_OPERATION_OK; sockstate = SOCKET_OPERATION_OK;
} }
if (sockstate == SOCKET_HAS_TIMED_OUT) { if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
ERRSTR("The handshake operation timed out")); ERRSTR("The handshake operation timed out"));
return NULL; return NULL;
} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
ERRSTR("Underlying socket has been closed.")); ERRSTR("Underlying socket has been closed."));
return NULL; return NULL;
} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
ERRSTR("Underlying socket too large for select().")); ERRSTR("Underlying socket too large for select()."));
return NULL; return NULL;
} else if (sockstate == SOCKET_IS_NONBLOCKING) { } else if (sockstate == SOCKET_IS_NONBLOCKING) {
break; break;
} }
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
if (ret < 1) if (ret < 1)
return PySSL_SetError(self, ret, __FILE__, __LINE__); return PySSL_SetError(self, ret, __FILE__, __LINE__);
self->ssl->debug = 1; self->ssl->debug = 1;
if (self->peer_cert) if (self->peer_cert)
X509_free (self->peer_cert); X509_free (self->peer_cert);
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
if ((self->peer_cert = SSL_get_peer_certificate(self->ssl))) { if ((self->peer_cert = SSL_get_peer_certificate(self->ssl))) {
X509_NAME_oneline(X509_get_subject_name(self->peer_cert), X509_NAME_oneline(X509_get_subject_name(self->peer_cert),
self->server, X509_NAME_MAXLEN); self->server, X509_NAME_MAXLEN);
X509_NAME_oneline(X509_get_issuer_name(self->peer_cert), X509_NAME_oneline(X509_get_issuer_name(self->peer_cert),
self->issuer, X509_NAME_MAXLEN); self->issuer, X509_NAME_MAXLEN);
} }
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static PyObject * static PyObject *
PySSL_server(PySSLObject *self) PySSL_server(PySSLObject *self)
{ {
return PyString_FromString(self->server); return PyString_FromString(self->server);
} }
static PyObject * static PyObject *
PySSL_issuer(PySSLObject *self) PySSL_issuer(PySSLObject *self)
{ {
return PyString_FromString(self->issuer); return PyString_FromString(self->issuer);
} }
static PyObject * static PyObject *
_create_tuple_for_attribute (ASN1_OBJECT *name, ASN1_STRING *value) { _create_tuple_for_attribute (ASN1_OBJECT *name, ASN1_STRING *value) {
char namebuf[X509_NAME_MAXLEN]; char namebuf[X509_NAME_MAXLEN];
int buflen; int buflen;
PyObject *name_obj; PyObject *name_obj;
PyObject *value_obj; PyObject *value_obj;
PyObject *attr; PyObject *attr;
unsigned char *valuebuf = NULL; unsigned char *valuebuf = NULL;
buflen = OBJ_obj2txt(namebuf, sizeof(namebuf), name, 0); buflen = OBJ_obj2txt(namebuf, sizeof(namebuf), name, 0);
if (buflen < 0) { if (buflen < 0) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
goto fail; goto fail;
} }
name_obj = PyString_FromStringAndSize(namebuf, buflen); name_obj = PyString_FromStringAndSize(namebuf, buflen);
if (name_obj == NULL) if (name_obj == NULL)
goto fail; goto fail;
buflen = ASN1_STRING_to_UTF8(&valuebuf, value); buflen = ASN1_STRING_to_UTF8(&valuebuf, value);
if (buflen < 0) { if (buflen < 0) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
Py_DECREF(name_obj); Py_DECREF(name_obj);
goto fail; goto fail;
} }
value_obj = PyUnicode_DecodeUTF8((char *) valuebuf, value_obj = PyUnicode_DecodeUTF8((char *) valuebuf,
buflen, "strict"); buflen, "strict");
OPENSSL_free(valuebuf); OPENSSL_free(valuebuf);
if (value_obj == NULL) { if (value_obj == NULL) {
Py_DECREF(name_obj); Py_DECREF(name_obj);
goto fail; goto fail;
} }
attr = PyTuple_New(2); attr = PyTuple_New(2);
if (attr == NULL) { if (attr == NULL) {
Py_DECREF(name_obj); Py_DECREF(name_obj);
Py_DECREF(value_obj); Py_DECREF(value_obj);
goto fail; goto fail;
} }
PyTuple_SET_ITEM(attr, 0, name_obj); PyTuple_SET_ITEM(attr, 0, name_obj);
PyTuple_SET_ITEM(attr, 1, value_obj); PyTuple_SET_ITEM(attr, 1, value_obj);
return attr; return attr;
fail: fail:
return NULL; return NULL;
} }
static PyObject * static PyObject *
_create_tuple_for_X509_NAME (X509_NAME *xname) _create_tuple_for_X509_NAME (X509_NAME *xname)
{ {
PyObject *dn = NULL; /* tuple which represents the "distinguished name" */ PyObject *dn = NULL; /* tuple which represents the "distinguished name" */
PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */ PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */
PyObject *rdnt; PyObject *rdnt;
PyObject *attr = NULL; /* tuple to hold an attribute */ PyObject *attr = NULL; /* tuple to hold an attribute */
int entry_count = X509_NAME_entry_count(xname); int entry_count = X509_NAME_entry_count(xname);
X509_NAME_ENTRY *entry; X509_NAME_ENTRY *entry;
ASN1_OBJECT *name; ASN1_OBJECT *name;
ASN1_STRING *value; ASN1_STRING *value;
int index_counter; int index_counter;
int rdn_level = -1; int rdn_level = -1;
int retcode; int retcode;
dn = PyList_New(0); dn = PyList_New(0);
if (dn == NULL) if (dn == NULL)
return NULL; return NULL;
/* now create another tuple to hold the top-level RDN */ /* now create another tuple to hold the top-level RDN */
rdn = PyList_New(0); rdn = PyList_New(0);
if (rdn == NULL) if (rdn == NULL)
goto fail0; goto fail0;
for (index_counter = 0; for (index_counter = 0;
index_counter < entry_count; index_counter < entry_count;
index_counter++) index_counter++)
{ {
entry = X509_NAME_get_entry(xname, index_counter); entry = X509_NAME_get_entry(xname, index_counter);
/* check to see if we've gotten to a new RDN */ /* check to see if we've gotten to a new RDN */
if (rdn_level >= 0) { if (rdn_level >= 0) {
if (rdn_level != entry->set) { if (rdn_level != entry->set) {
/* yes, new RDN */ /* yes, new RDN */
/* add old RDN to DN */ /* add old RDN to DN */
rdnt = PyList_AsTuple(rdn); rdnt = PyList_AsTuple(rdn);
Py_DECREF(rdn); Py_DECREF(rdn);
if (rdnt == NULL) if (rdnt == NULL)
goto fail0; goto fail0;
retcode = PyList_Append(dn, rdnt); retcode = PyList_Append(dn, rdnt);
Py_DECREF(rdnt); Py_DECREF(rdnt);
if (retcode < 0) if (retcode < 0)
goto fail0; goto fail0;
/* create new RDN */ /* create new RDN */
rdn = PyList_New(0); rdn = PyList_New(0);
if (rdn == NULL) if (rdn == NULL)
goto fail0; goto fail0;
} }
} }
rdn_level = entry->set; rdn_level = entry->set;
/* now add this attribute to the current RDN */ /* now add this attribute to the current RDN */
name = X509_NAME_ENTRY_get_object(entry); name = X509_NAME_ENTRY_get_object(entry);
value = X509_NAME_ENTRY_get_data(entry); value = X509_NAME_ENTRY_get_data(entry);
attr = _create_tuple_for_attribute(name, value); attr = _create_tuple_for_attribute(name, value);
/* /*
fprintf(stderr, "RDN level %d, attribute %s: %s\n", fprintf(stderr, "RDN level %d, attribute %s: %s\n",
entry->set, entry->set,
PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)), PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)),
PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1))); PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1)));
*/ */
if (attr == NULL) if (attr == NULL)
goto fail1; goto fail1;
retcode = PyList_Append(rdn, attr); retcode = PyList_Append(rdn, attr);
Py_DECREF(attr); Py_DECREF(attr);
if (retcode < 0) if (retcode < 0)
goto fail1; goto fail1;
} }
/* now, there's typically a dangling RDN */ /* now, there's typically a dangling RDN */
if ((rdn != NULL) && (PyList_Size(rdn) > 0)) { if ((rdn != NULL) && (PyList_Size(rdn) > 0)) {
rdnt = PyList_AsTuple(rdn); rdnt = PyList_AsTuple(rdn);
Py_DECREF(rdn); Py_DECREF(rdn);
if (rdnt == NULL) if (rdnt == NULL)
goto fail0; goto fail0;
retcode = PyList_Append(dn, rdnt); retcode = PyList_Append(dn, rdnt);
Py_DECREF(rdnt); Py_DECREF(rdnt);
if (retcode < 0) if (retcode < 0)
goto fail0; goto fail0;
} }
/* convert list to tuple */ /* convert list to tuple */
rdnt = PyList_AsTuple(dn); rdnt = PyList_AsTuple(dn);
Py_DECREF(dn); Py_DECREF(dn);
if (rdnt == NULL) if (rdnt == NULL)
return NULL; return NULL;
return rdnt; return rdnt;
fail1: fail1:
Py_XDECREF(rdn); Py_XDECREF(rdn);
fail0: fail0:
Py_XDECREF(dn); Py_XDECREF(dn);
return NULL; return NULL;
} }
static PyObject * static PyObject *
_get_peer_alt_names (X509 *certificate) { _get_peer_alt_names (X509 *certificate) {
/* this code follows the procedure outlined in /* this code follows the procedure outlined in
OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print() OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print()
function to extract the STACK_OF(GENERAL_NAME), function to extract the STACK_OF(GENERAL_NAME),
then iterates through the stack to add the then iterates through the stack to add the
names. */ names. */
int i, j; int i, j;
PyObject *peer_alt_names = Py_None; PyObject *peer_alt_names = Py_None;
PyObject *v, *t; PyObject *v, *t;
X509_EXTENSION *ext = NULL; X509_EXTENSION *ext = NULL;
GENERAL_NAMES *names = NULL; GENERAL_NAMES *names = NULL;
GENERAL_NAME *name; GENERAL_NAME *name;
X509V3_EXT_METHOD *method; X509V3_EXT_METHOD *method;
BIO *biobuf = NULL; BIO *biobuf = NULL;
char buf[2048]; char buf[2048];
char *vptr; char *vptr;
int len; int len;
/* Issue #2973: ASN1_item_d2i() API changed in OpenSSL 0.9.6m */ /* Issue #2973: ASN1_item_d2i() API changed in OpenSSL 0.9.6m */
#if OPENSSL_VERSION_NUMBER >= 0x009060dfL #if OPENSSL_VERSION_NUMBER >= 0x009060dfL
const unsigned char *p; const unsigned char *p;
#else #else
unsigned char *p; unsigned char *p;
#endif #endif
if (certificate == NULL) if (certificate == NULL)
return peer_alt_names; return peer_alt_names;
/* get a memory buffer */ /* get a memory buffer */
biobuf = BIO_new(BIO_s_mem()); biobuf = BIO_new(BIO_s_mem());
i = 0; i = 0;
while ((i = X509_get_ext_by_NID( while ((i = X509_get_ext_by_NID(
certificate, NID_subject_alt_name, i)) >= 0) { certificate, NID_subject_alt_name, i)) >= 0) {
if (peer_alt_names == Py_None) { if (peer_alt_names == Py_None) {
peer_alt_names = PyList_New(0); peer_alt_names = PyList_New(0);
if (peer_alt_names == NULL) if (peer_alt_names == NULL)
goto fail; goto fail;
} }
/* now decode the altName */ /* now decode the altName */
ext = X509_get_ext(certificate, i); ext = X509_get_ext(certificate, i);
if(!(method = X509V3_EXT_get(ext))) { if(!(method = X509V3_EXT_get(ext))) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
ERRSTR("No method for internalizing subjectAltName!")); ERRSTR("No method for internalizing subjectAltName!"));
goto fail; goto fail;
} }
p = ext->value->data; p = ext->value->data;
if (method->it) if (method->it)
names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL,
&p, &p,
ext->value->length, ext->value->length,
ASN1_ITEM_ptr(method->it))); ASN1_ITEM_ptr(method->it)));
else else
names = (GENERAL_NAMES*) (method->d2i(NULL, names = (GENERAL_NAMES*) (method->d2i(NULL,
&p, &p,
ext->value->length)); ext->value->length));
for(j = 0; j < sk_GENERAL_NAME_num(names); j++) { for(j = 0; j < sk_GENERAL_NAME_num(names); j++) {
/* get a rendering of each name in the set of names */ /* get a rendering of each name in the set of names */
name = sk_GENERAL_NAME_value(names, j); name = sk_GENERAL_NAME_value(names, j);
if (name->type == GEN_DIRNAME) { if (name->type == GEN_DIRNAME) {
/* we special-case DirName as a tuple of tuples of attributes */ /* we special-case DirName as a tuple of tuples of attributes */
t = PyTuple_New(2); t = PyTuple_New(2);
if (t == NULL) { if (t == NULL) {
goto fail; goto fail;
} }
v = PyString_FromString("DirName"); v = PyString_FromString("DirName");
if (v == NULL) { if (v == NULL) {
Py_DECREF(t); Py_DECREF(t);
goto fail; goto fail;
} }
PyTuple_SET_ITEM(t, 0, v); PyTuple_SET_ITEM(t, 0, v);
v = _create_tuple_for_X509_NAME (name->d.dirn); v = _create_tuple_for_X509_NAME (name->d.dirn);
if (v == NULL) { if (v == NULL) {
Py_DECREF(t); Py_DECREF(t);
goto fail; goto fail;
} }
PyTuple_SET_ITEM(t, 1, v); PyTuple_SET_ITEM(t, 1, v);
} else { } else {
/* for everything else, we use the OpenSSL print form */ /* for everything else, we use the OpenSSL print form */
(void) BIO_reset(biobuf); (void) BIO_reset(biobuf);
GENERAL_NAME_print(biobuf, name); GENERAL_NAME_print(biobuf, name);
len = BIO_gets(biobuf, buf, sizeof(buf)-1); len = BIO_gets(biobuf, buf, sizeof(buf)-1);
if (len < 0) { if (len < 0) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
goto fail; goto fail;
} }
vptr = strchr(buf, ':'); vptr = strchr(buf, ':');
if (vptr == NULL) if (vptr == NULL)
goto fail; goto fail;
t = PyTuple_New(2); t = PyTuple_New(2);
if (t == NULL) if (t == NULL)
goto fail; goto fail;
v = PyString_FromStringAndSize(buf, (vptr - buf)); v = PyString_FromStringAndSize(buf, (vptr - buf));
if (v == NULL) { if (v == NULL) {
Py_DECREF(t); Py_DECREF(t);
goto fail; goto fail;
} }
PyTuple_SET_ITEM(t, 0, v); PyTuple_SET_ITEM(t, 0, v);
v = PyString_FromStringAndSize((vptr + 1), (len - (vptr - buf + 1))); v = PyString_FromStringAndSize((vptr + 1), (len - (vptr - buf + 1)));
if (v == NULL) { if (v == NULL) {
Py_DECREF(t); Py_DECREF(t);
goto fail; goto fail;
} }
PyTuple_SET_ITEM(t, 1, v); PyTuple_SET_ITEM(t, 1, v);
} }
/* and add that rendering to the list */ /* and add that rendering to the list */
if (PyList_Append(peer_alt_names, t) < 0) { if (PyList_Append(peer_alt_names, t) < 0) {
Py_DECREF(t); Py_DECREF(t);
goto fail; goto fail;
} }
Py_DECREF(t); Py_DECREF(t);
} }
} }
BIO_free(biobuf); BIO_free(biobuf);
if (peer_alt_names != Py_None) { if (peer_alt_names != Py_None) {
v = PyList_AsTuple(peer_alt_names); v = PyList_AsTuple(peer_alt_names);
Py_DECREF(peer_alt_names); Py_DECREF(peer_alt_names);
return v; return v;
} else { } else {
return peer_alt_names; return peer_alt_names;
} }
fail: fail:
if (biobuf != NULL) if (biobuf != NULL)
BIO_free(biobuf); BIO_free(biobuf);
if (peer_alt_names != Py_None) { if (peer_alt_names != Py_None) {
Py_XDECREF(peer_alt_names); Py_XDECREF(peer_alt_names);
} }
return NULL; return NULL;
} }
static PyObject * static PyObject *
_decode_certificate (X509 *certificate, int verbose) { _decode_certificate (X509 *certificate, int verbose) {
PyObject *retval = NULL; PyObject *retval = NULL;
BIO *biobuf = NULL; BIO *biobuf = NULL;
PyObject *peer; PyObject *peer;
PyObject *peer_alt_names = NULL; PyObject *peer_alt_names = NULL;
PyObject *issuer; PyObject *issuer;
PyObject *version; PyObject *version;
PyObject *sn_obj; PyObject *sn_obj;
ASN1_INTEGER *serialNumber; ASN1_INTEGER *serialNumber;
char buf[2048]; char buf[2048];
int len; int len;
ASN1_TIME *notBefore, *notAfter; ASN1_TIME *notBefore, *notAfter;
PyObject *pnotBefore, *pnotAfter; PyObject *pnotBefore, *pnotAfter;
retval = PyDict_New(); retval = PyDict_New();
if (retval == NULL) if (retval == NULL)
return NULL; return NULL;
peer = _create_tuple_for_X509_NAME( peer = _create_tuple_for_X509_NAME(
X509_get_subject_name(certificate)); X509_get_subject_name(certificate));
if (peer == NULL) if (peer == NULL)
goto fail0; goto fail0;
if (PyDict_SetItemString(retval, (const char *) "subject", peer) < 0) { if (PyDict_SetItemString(retval, (const char *) "subject", peer) < 0) {
Py_DECREF(peer); Py_DECREF(peer);
goto fail0; goto fail0;
} }
Py_DECREF(peer); Py_DECREF(peer);
if (verbose) { if (verbose) {
issuer = _create_tuple_for_X509_NAME( issuer = _create_tuple_for_X509_NAME(
X509_get_issuer_name(certificate)); X509_get_issuer_name(certificate));
if (issuer == NULL) if (issuer == NULL)
goto fail0; goto fail0;
if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) { if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) {
Py_DECREF(issuer); Py_DECREF(issuer);
goto fail0; goto fail0;
} }
Py_DECREF(issuer); Py_DECREF(issuer);
version = PyInt_FromLong(X509_get_version(certificate) + 1); version = PyInt_FromLong(X509_get_version(certificate) + 1);
if (PyDict_SetItemString(retval, "version", version) < 0) { if (PyDict_SetItemString(retval, "version", version) < 0) {
Py_DECREF(version); Py_DECREF(version);
goto fail0; goto fail0;
} }
Py_DECREF(version); Py_DECREF(version);
} }
/* get a memory buffer */ /* get a memory buffer */
biobuf = BIO_new(BIO_s_mem()); biobuf = BIO_new(BIO_s_mem());
if (verbose) { if (verbose) {
(void) BIO_reset(biobuf); (void) BIO_reset(biobuf);
serialNumber = X509_get_serialNumber(certificate); serialNumber = X509_get_serialNumber(certificate);
/* should not exceed 20 octets, 160 bits, so buf is big enough */ /* should not exceed 20 octets, 160 bits, so buf is big enough */
i2a_ASN1_INTEGER(biobuf, serialNumber); i2a_ASN1_INTEGER(biobuf, serialNumber);
len = BIO_gets(biobuf, buf, sizeof(buf)-1); len = BIO_gets(biobuf, buf, sizeof(buf)-1);
if (len < 0) { if (len < 0) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
goto fail1; goto fail1;
} }
sn_obj = PyString_FromStringAndSize(buf, len); sn_obj = PyString_FromStringAndSize(buf, len);
if (sn_obj == NULL) if (sn_obj == NULL)
goto fail1; goto fail1;
if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) { if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) {
Py_DECREF(sn_obj); Py_DECREF(sn_obj);
goto fail1; goto fail1;
} }
Py_DECREF(sn_obj); Py_DECREF(sn_obj);
(void) BIO_reset(biobuf); (void) BIO_reset(biobuf);
notBefore = X509_get_notBefore(certificate); notBefore = X509_get_notBefore(certificate);
ASN1_TIME_print(biobuf, notBefore); ASN1_TIME_print(biobuf, notBefore);
len = BIO_gets(biobuf, buf, sizeof(buf)-1); len = BIO_gets(biobuf, buf, sizeof(buf)-1);
if (len < 0) { if (len < 0) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
goto fail1; goto fail1;
} }
pnotBefore = PyString_FromStringAndSize(buf, len); pnotBefore = PyString_FromStringAndSize(buf, len);
if (pnotBefore == NULL) if (pnotBefore == NULL)
goto fail1; goto fail1;
if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) { if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) {
Py_DECREF(pnotBefore); Py_DECREF(pnotBefore);
goto fail1; goto fail1;
} }
Py_DECREF(pnotBefore); Py_DECREF(pnotBefore);
} }
(void) BIO_reset(biobuf); (void) BIO_reset(biobuf);
notAfter = X509_get_notAfter(certificate); notAfter = X509_get_notAfter(certificate);
ASN1_TIME_print(biobuf, notAfter); ASN1_TIME_print(biobuf, notAfter);
len = BIO_gets(biobuf, buf, sizeof(buf)-1); len = BIO_gets(biobuf, buf, sizeof(buf)-1);
if (len < 0) { if (len < 0) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
goto fail1; goto fail1;
} }
pnotAfter = PyString_FromStringAndSize(buf, len); pnotAfter = PyString_FromStringAndSize(buf, len);
if (pnotAfter == NULL) if (pnotAfter == NULL)
goto fail1; goto fail1;
if (PyDict_SetItemString(retval, "notAfter", pnotAfter) < 0) { if (PyDict_SetItemString(retval, "notAfter", pnotAfter) < 0) {
Py_DECREF(pnotAfter); Py_DECREF(pnotAfter);
goto fail1; goto fail1;
} }
Py_DECREF(pnotAfter); Py_DECREF(pnotAfter);
/* Now look for subjectAltName */ /* Now look for subjectAltName */
peer_alt_names = _get_peer_alt_names(certificate); peer_alt_names = _get_peer_alt_names(certificate);
if (peer_alt_names == NULL) if (peer_alt_names == NULL)
goto fail1; goto fail1;
else if (peer_alt_names != Py_None) { else if (peer_alt_names != Py_None) {
if (PyDict_SetItemString(retval, "subjectAltName", if (PyDict_SetItemString(retval, "subjectAltName",
peer_alt_names) < 0) { peer_alt_names) < 0) {
Py_DECREF(peer_alt_names); Py_DECREF(peer_alt_names);
goto fail1; goto fail1;
} }
Py_DECREF(peer_alt_names); Py_DECREF(peer_alt_names);
} }
BIO_free(biobuf); BIO_free(biobuf);
return retval; return retval;
fail1: fail1:
if (biobuf != NULL) if (biobuf != NULL)
BIO_free(biobuf); BIO_free(biobuf);
fail0: fail0:
Py_XDECREF(retval); Py_XDECREF(retval);
return NULL; return NULL;
} }
static PyObject * static PyObject *
PySSL_test_decode_certificate (PyObject *mod, PyObject *args) { PySSL_test_decode_certificate (PyObject *mod, PyObject *args) {
PyObject *retval = NULL; PyObject *retval = NULL;
char *filename = NULL; char *filename = NULL;
X509 *x=NULL; X509 *x=NULL;
BIO *cert; BIO *cert;
int verbose = 1; int verbose = 1;
if (!PyArg_ParseTuple(args, "s|i:test_decode_certificate", &filename, &verbose)) if (!PyArg_ParseTuple(args, "s|i:test_decode_certificate", &filename, &verbose))
return NULL; return NULL;
if ((cert=BIO_new(BIO_s_file())) == NULL) { if ((cert=BIO_new(BIO_s_file())) == NULL) {
PyErr_SetString(PySSLErrorObject, "Can't malloc memory to read file"); PyErr_SetString(PySSLErrorObject, "Can't malloc memory to read file");
goto fail0; goto fail0;
} }
if (BIO_read_filename(cert,filename) <= 0) { if (BIO_read_filename(cert,filename) <= 0) {
PyErr_SetString(PySSLErrorObject, "Can't open file"); PyErr_SetString(PySSLErrorObject, "Can't open file");
goto fail0; goto fail0;
} }
x = PEM_read_bio_X509_AUX(cert,NULL, NULL, NULL); x = PEM_read_bio_X509_AUX(cert,NULL, NULL, NULL);
if (x == NULL) { if (x == NULL) {
PyErr_SetString(PySSLErrorObject, "Error decoding PEM-encoded file"); PyErr_SetString(PySSLErrorObject, "Error decoding PEM-encoded file");
goto fail0; goto fail0;
} }
retval = _decode_certificate(x, verbose); retval = _decode_certificate(x, verbose);
fail0: fail0:
if (cert != NULL) BIO_free(cert); if (cert != NULL) BIO_free(cert);
return retval; return retval;
} }
static PyObject * static PyObject *
PySSL_peercert(PySSLObject *self, PyObject *args) PySSL_peercert(PySSLObject *self, PyObject *args)
{ {
PyObject *retval = NULL; PyObject *retval = NULL;
int len; int len;
int verification; int verification;
PyObject *binary_mode = Py_None; PyObject *binary_mode = Py_None;
if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode)) if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode))
return NULL; return NULL;
if (!self->peer_cert) if (!self->peer_cert)
Py_RETURN_NONE; Py_RETURN_NONE;
if (PyObject_IsTrue(binary_mode)) { if (PyObject_IsTrue(binary_mode)) {
/* return cert in DER-encoded format */ /* return cert in DER-encoded format */
unsigned char *bytes_buf = NULL; unsigned char *bytes_buf = NULL;
bytes_buf = NULL; bytes_buf = NULL;
len = i2d_X509(self->peer_cert, &bytes_buf); len = i2d_X509(self->peer_cert, &bytes_buf);
if (len < 0) { if (len < 0) {
PySSL_SetError(self, len, __FILE__, __LINE__); PySSL_SetError(self, len, __FILE__, __LINE__);
return NULL; return NULL;
} }
retval = PyString_FromStringAndSize((const char *) bytes_buf, len); retval = PyString_FromStringAndSize((const char *) bytes_buf, len);
OPENSSL_free(bytes_buf); OPENSSL_free(bytes_buf);
return retval; return retval;
} else { } else {
verification = SSL_CTX_get_verify_mode(self->ctx); verification = SSL_CTX_get_verify_mode(self->ctx);
if ((verification & SSL_VERIFY_PEER) == 0) if ((verification & SSL_VERIFY_PEER) == 0)
return PyDict_New(); return PyDict_New();
else else
return _decode_certificate (self->peer_cert, 0); return _decode_certificate (self->peer_cert, 0);
} }
} }
PyDoc_STRVAR(PySSL_peercert_doc, PyDoc_STRVAR(PySSL_peercert_doc,
...@@ -1040,60 +1040,60 @@ return the certificate even if it wasn't validated."); ...@@ -1040,60 +1040,60 @@ return the certificate even if it wasn't validated.");
static PyObject *PySSL_cipher (PySSLObject *self) { static PyObject *PySSL_cipher (PySSLObject *self) {
PyObject *retval, *v; PyObject *retval, *v;
SSL_CIPHER *current; SSL_CIPHER *current;
char *cipher_name; char *cipher_name;
char *cipher_protocol; char *cipher_protocol;
if (self->ssl == NULL) if (self->ssl == NULL)
return Py_None; return Py_None;
current = SSL_get_current_cipher(self->ssl); current = SSL_get_current_cipher(self->ssl);
if (current == NULL) if (current == NULL)
return Py_None; return Py_None;
retval = PyTuple_New(3); retval = PyTuple_New(3);
if (retval == NULL) if (retval == NULL)
return NULL; return NULL;
cipher_name = (char *) SSL_CIPHER_get_name(current); cipher_name = (char *) SSL_CIPHER_get_name(current);
if (cipher_name == NULL) { if (cipher_name == NULL) {
PyTuple_SET_ITEM(retval, 0, Py_None); PyTuple_SET_ITEM(retval, 0, Py_None);
} else { } else {
v = PyString_FromString(cipher_name); v = PyString_FromString(cipher_name);
if (v == NULL) if (v == NULL)
goto fail0; goto fail0;
PyTuple_SET_ITEM(retval, 0, v); PyTuple_SET_ITEM(retval, 0, v);
} }
cipher_protocol = SSL_CIPHER_get_version(current); cipher_protocol = SSL_CIPHER_get_version(current);
if (cipher_protocol == NULL) { if (cipher_protocol == NULL) {
PyTuple_SET_ITEM(retval, 1, Py_None); PyTuple_SET_ITEM(retval, 1, Py_None);
} else { } else {
v = PyString_FromString(cipher_protocol); v = PyString_FromString(cipher_protocol);
if (v == NULL) if (v == NULL)
goto fail0; goto fail0;
PyTuple_SET_ITEM(retval, 1, v); PyTuple_SET_ITEM(retval, 1, v);
} }
v = PyInt_FromLong(SSL_CIPHER_get_bits(current, NULL)); v = PyInt_FromLong(SSL_CIPHER_get_bits(current, NULL));
if (v == NULL) if (v == NULL)
goto fail0; goto fail0;
PyTuple_SET_ITEM(retval, 2, v); PyTuple_SET_ITEM(retval, 2, v);
return retval; return retval;
fail0: fail0:
Py_DECREF(retval); Py_DECREF(retval);
return NULL; return NULL;
} }
static void PySSL_dealloc(PySSLObject *self) static void PySSL_dealloc(PySSLObject *self)
{ {
if (self->peer_cert) /* Possible not to have one? */ if (self->peer_cert) /* Possible not to have one? */
X509_free (self->peer_cert); X509_free (self->peer_cert);
if (self->ssl) if (self->ssl)
SSL_free(self->ssl); SSL_free(self->ssl);
if (self->ctx) if (self->ctx)
SSL_CTX_free(self->ctx); SSL_CTX_free(self->ctx);
Py_XDECREF(self->Socket); Py_XDECREF(self->Socket);
PyObject_Del(self); PyObject_Del(self);
} }
/* If the socket has a timeout, do a select()/poll() on the socket. /* If the socket has a timeout, do a select()/poll() on the socket.
...@@ -1104,137 +1104,137 @@ static void PySSL_dealloc(PySSLObject *self) ...@@ -1104,137 +1104,137 @@ static void PySSL_dealloc(PySSLObject *self)
static int static int
check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing) check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
{ {
fd_set fds; fd_set fds;
struct timeval tv; struct timeval tv;
int rc; int rc;
/* Nothing to do unless we're in timeout mode (not non-blocking) */ /* Nothing to do unless we're in timeout mode (not non-blocking) */
if (s->sock_timeout < 0.0) if (s->sock_timeout < 0.0)
return SOCKET_IS_BLOCKING; return SOCKET_IS_BLOCKING;
else if (s->sock_timeout == 0.0) else if (s->sock_timeout == 0.0)
return SOCKET_IS_NONBLOCKING; return SOCKET_IS_NONBLOCKING;
/* Guard against closed socket */ /* Guard against closed socket */
if (s->sock_fd < 0) if (s->sock_fd < 0)
return SOCKET_HAS_BEEN_CLOSED; return SOCKET_HAS_BEEN_CLOSED;
/* Prefer poll, if available, since you can poll() any fd /* Prefer poll, if available, since you can poll() any fd
* which can't be done with select(). */ * which can't be done with select(). */
#ifdef HAVE_POLL #ifdef HAVE_POLL
{ {
struct pollfd pollfd; struct pollfd pollfd;
int timeout; int timeout;
pollfd.fd = s->sock_fd; pollfd.fd = s->sock_fd;
pollfd.events = writing ? POLLOUT : POLLIN; pollfd.events = writing ? POLLOUT : POLLIN;
/* s->sock_timeout is in seconds, timeout in ms */ /* s->sock_timeout is in seconds, timeout in ms */
timeout = (int)(s->sock_timeout * 1000 + 0.5); timeout = (int)(s->sock_timeout * 1000 + 0.5);
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
rc = poll(&pollfd, 1, timeout); rc = poll(&pollfd, 1, timeout);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
goto normal_return; goto normal_return;
} }
#endif #endif
/* Guard against socket too large for select*/ /* Guard against socket too large for select*/
#ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE #ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE
if (s->sock_fd >= FD_SETSIZE) if (s->sock_fd >= FD_SETSIZE)
return SOCKET_TOO_LARGE_FOR_SELECT; return SOCKET_TOO_LARGE_FOR_SELECT;
#endif #endif
/* Construct the arguments to select */ /* Construct the arguments to select */
tv.tv_sec = (int)s->sock_timeout; tv.tv_sec = (int)s->sock_timeout;
tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(s->sock_fd, &fds); FD_SET(s->sock_fd, &fds);
/* See if the socket is ready */ /* See if the socket is ready */
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
if (writing) if (writing)
rc = select(s->sock_fd+1, NULL, &fds, NULL, &tv); rc = select(s->sock_fd+1, NULL, &fds, NULL, &tv);
else else
rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv); rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
#ifdef HAVE_POLL #ifdef HAVE_POLL
normal_return: normal_return:
#endif #endif
/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
(when we are able to write or when there's something to read) */ (when we are able to write or when there's something to read) */
return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK;
} }
static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args)
{ {
Py_buffer buf; Py_buffer buf;
int len; int len;
int sockstate; int sockstate;
int err; int err;
int nonblocking; int nonblocking;
if (!PyArg_ParseTuple(args, "s*:write", &buf)) if (!PyArg_ParseTuple(args, "s*:write", &buf))
return NULL; return NULL;
/* just in case the blocking state of the socket has been changed */ /* just in case the blocking state of the socket has been changed */
nonblocking = (self->Socket->sock_timeout >= 0.0); nonblocking = (self->Socket->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
if (sockstate == SOCKET_HAS_TIMED_OUT) { if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"The write operation timed out"); "The write operation timed out");
goto error; goto error;
} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"Underlying socket has been closed."); "Underlying socket has been closed.");
goto error; goto error;
} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"Underlying socket too large for select()."); "Underlying socket too large for select().");
goto error; goto error;
} }
do { do {
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
len = SSL_write(self->ssl, buf.buf, buf.len); len = SSL_write(self->ssl, buf.buf, buf.len);
err = SSL_get_error(self->ssl, len); err = SSL_get_error(self->ssl, len);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if (PyErr_CheckSignals()) { if (PyErr_CheckSignals()) {
goto error; goto error;
} }
if (err == SSL_ERROR_WANT_READ) { if (err == SSL_ERROR_WANT_READ) {
sockstate = sockstate =
check_socket_and_wait_for_timeout(self->Socket, 0); check_socket_and_wait_for_timeout(self->Socket, 0);
} else if (err == SSL_ERROR_WANT_WRITE) { } else if (err == SSL_ERROR_WANT_WRITE) {
sockstate = sockstate =
check_socket_and_wait_for_timeout(self->Socket, 1); check_socket_and_wait_for_timeout(self->Socket, 1);
} else { } else {
sockstate = SOCKET_OPERATION_OK; sockstate = SOCKET_OPERATION_OK;
} }
if (sockstate == SOCKET_HAS_TIMED_OUT) { if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"The write operation timed out"); "The write operation timed out");
goto error; goto error;
} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"Underlying socket has been closed."); "Underlying socket has been closed.");
goto error; goto error;
} else if (sockstate == SOCKET_IS_NONBLOCKING) { } else if (sockstate == SOCKET_IS_NONBLOCKING) {
break; break;
} }
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
PyBuffer_Release(&buf); PyBuffer_Release(&buf);
if (len > 0) if (len > 0)
return PyInt_FromLong(len); return PyInt_FromLong(len);
else else
return PySSL_SetError(self, len, __FILE__, __LINE__); return PySSL_SetError(self, len, __FILE__, __LINE__);
error: error:
PyBuffer_Release(&buf); PyBuffer_Release(&buf);
return NULL; return NULL;
} }
PyDoc_STRVAR(PySSL_SSLwrite_doc, PyDoc_STRVAR(PySSL_SSLwrite_doc,
...@@ -1245,15 +1245,15 @@ of bytes written."); ...@@ -1245,15 +1245,15 @@ of bytes written.");
static PyObject *PySSL_SSLpending(PySSLObject *self) static PyObject *PySSL_SSLpending(PySSLObject *self)
{ {
int count = 0; int count = 0;
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
count = SSL_pending(self->ssl); count = SSL_pending(self->ssl);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if (count < 0) if (count < 0)
return PySSL_SetError(self, count, __FILE__, __LINE__); return PySSL_SetError(self, count, __FILE__, __LINE__);
else else
return PyInt_FromLong(count); return PyInt_FromLong(count);
} }
PyDoc_STRVAR(PySSL_SSLpending_doc, PyDoc_STRVAR(PySSL_SSLpending_doc,
...@@ -1264,96 +1264,96 @@ pending on the connection.\n"); ...@@ -1264,96 +1264,96 @@ pending on the connection.\n");
static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
{ {
PyObject *buf; PyObject *buf;
int count = 0; int count = 0;
int len = 1024; int len = 1024;
int sockstate; int sockstate;
int err; int err;
int nonblocking; int nonblocking;
if (!PyArg_ParseTuple(args, "|i:read", &len)) if (!PyArg_ParseTuple(args, "|i:read", &len))
return NULL; return NULL;
if (!(buf = PyString_FromStringAndSize((char *) 0, len))) if (!(buf = PyString_FromStringAndSize((char *) 0, len)))
return NULL; return NULL;
/* just in case the blocking state of the socket has been changed */ /* just in case the blocking state of the socket has been changed */
nonblocking = (self->Socket->sock_timeout >= 0.0); nonblocking = (self->Socket->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
/* first check if there are bytes ready to be read */ /* first check if there are bytes ready to be read */
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
count = SSL_pending(self->ssl); count = SSL_pending(self->ssl);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if (!count) { if (!count) {
sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
if (sockstate == SOCKET_HAS_TIMED_OUT) { if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"The read operation timed out"); "The read operation timed out");
Py_DECREF(buf); Py_DECREF(buf);
return NULL; return NULL;
} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"Underlying socket too large for select()."); "Underlying socket too large for select().");
Py_DECREF(buf); Py_DECREF(buf);
return NULL; return NULL;
} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
if (SSL_get_shutdown(self->ssl) != if (SSL_get_shutdown(self->ssl) !=
SSL_RECEIVED_SHUTDOWN) SSL_RECEIVED_SHUTDOWN)
{ {
Py_DECREF(buf); Py_DECREF(buf);
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"Socket closed without SSL shutdown handshake"); "Socket closed without SSL shutdown handshake");
return NULL; return NULL;
} else { } else {
/* should contain a zero-length string */ /* should contain a zero-length string */
_PyString_Resize(&buf, 0); _PyString_Resize(&buf, 0);
return buf; return buf;
} }
} }
} }
do { do {
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
count = SSL_read(self->ssl, PyString_AsString(buf), len); count = SSL_read(self->ssl, PyString_AsString(buf), len);
err = SSL_get_error(self->ssl, count); err = SSL_get_error(self->ssl, count);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
if(PyErr_CheckSignals()) { if(PyErr_CheckSignals()) {
Py_DECREF(buf); Py_DECREF(buf);
return NULL; return NULL;
} }
if (err == SSL_ERROR_WANT_READ) { if (err == SSL_ERROR_WANT_READ) {
sockstate = sockstate =
check_socket_and_wait_for_timeout(self->Socket, 0); check_socket_and_wait_for_timeout(self->Socket, 0);
} else if (err == SSL_ERROR_WANT_WRITE) { } else if (err == SSL_ERROR_WANT_WRITE) {
sockstate = sockstate =
check_socket_and_wait_for_timeout(self->Socket, 1); check_socket_and_wait_for_timeout(self->Socket, 1);
} else if ((err == SSL_ERROR_ZERO_RETURN) && } else if ((err == SSL_ERROR_ZERO_RETURN) &&
(SSL_get_shutdown(self->ssl) == (SSL_get_shutdown(self->ssl) ==
SSL_RECEIVED_SHUTDOWN)) SSL_RECEIVED_SHUTDOWN))
{ {
_PyString_Resize(&buf, 0); _PyString_Resize(&buf, 0);
return buf; return buf;
} else { } else {
sockstate = SOCKET_OPERATION_OK; sockstate = SOCKET_OPERATION_OK;
} }
if (sockstate == SOCKET_HAS_TIMED_OUT) { if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"The read operation timed out"); "The read operation timed out");
Py_DECREF(buf); Py_DECREF(buf);
return NULL; return NULL;
} else if (sockstate == SOCKET_IS_NONBLOCKING) { } else if (sockstate == SOCKET_IS_NONBLOCKING) {
break; break;
} }
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
if (count <= 0) { if (count <= 0) {
Py_DECREF(buf); Py_DECREF(buf);
return PySSL_SetError(self, count, __FILE__, __LINE__); return PySSL_SetError(self, count, __FILE__, __LINE__);
} }
if (count != len) if (count != len)
_PyString_Resize(&buf, count); _PyString_Resize(&buf, count);
return buf; return buf;
} }
PyDoc_STRVAR(PySSL_SSLread_doc, PyDoc_STRVAR(PySSL_SSLread_doc,
...@@ -1363,82 +1363,82 @@ Read up to len bytes from the SSL socket."); ...@@ -1363,82 +1363,82 @@ Read up to len bytes from the SSL socket.");
static PyObject *PySSL_SSLshutdown(PySSLObject *self) static PyObject *PySSL_SSLshutdown(PySSLObject *self)
{ {
int err, ssl_err, sockstate, nonblocking; int err, ssl_err, sockstate, nonblocking;
int zeros = 0; int zeros = 0;
/* Guard against closed socket */ /* Guard against closed socket */
if (self->Socket->sock_fd < 0) { if (self->Socket->sock_fd < 0) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"Underlying socket has been closed."); "Underlying socket has been closed.");
return NULL; return NULL;
} }
/* Just in case the blocking state of the socket has been changed */ /* Just in case the blocking state of the socket has been changed */
nonblocking = (self->Socket->sock_timeout >= 0.0); nonblocking = (self->Socket->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
while (1) { while (1) {
PySSL_BEGIN_ALLOW_THREADS PySSL_BEGIN_ALLOW_THREADS
/* Disable read-ahead so that unwrap can work correctly. /* Disable read-ahead so that unwrap can work correctly.
* Otherwise OpenSSL might read in too much data, * Otherwise OpenSSL might read in too much data,
* eating clear text data that happens to be * eating clear text data that happens to be
* transmitted after the SSL shutdown. * transmitted after the SSL shutdown.
* Should be safe to call repeatedly everytime this * Should be safe to call repeatedly everytime this
* function is used and the shutdown_seen_zero != 0 * function is used and the shutdown_seen_zero != 0
* condition is met. * condition is met.
*/ */
if (self->shutdown_seen_zero) if (self->shutdown_seen_zero)
SSL_set_read_ahead(self->ssl, 0); SSL_set_read_ahead(self->ssl, 0);
err = SSL_shutdown(self->ssl); err = SSL_shutdown(self->ssl);
PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */ /* If err == 1, a secure shutdown with SSL_shutdown() is complete */
if (err > 0) if (err > 0)
break; break;
if (err == 0) { if (err == 0) {
/* Don't loop endlessly; instead preserve legacy /* Don't loop endlessly; instead preserve legacy
behaviour of trying SSL_shutdown() only twice. behaviour of trying SSL_shutdown() only twice.
This looks necessary for OpenSSL < 0.9.8m */ This looks necessary for OpenSSL < 0.9.8m */
if (++zeros > 1) if (++zeros > 1)
break; break;
/* Shutdown was sent, now try receiving */ /* Shutdown was sent, now try receiving */
self->shutdown_seen_zero = 1; self->shutdown_seen_zero = 1;
continue; continue;
} }
/* Possibly retry shutdown until timeout or failure */ /* Possibly retry shutdown until timeout or failure */
ssl_err = SSL_get_error(self->ssl, err); ssl_err = SSL_get_error(self->ssl, err);
if (ssl_err == SSL_ERROR_WANT_READ) if (ssl_err == SSL_ERROR_WANT_READ)
sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
else if (ssl_err == SSL_ERROR_WANT_WRITE) else if (ssl_err == SSL_ERROR_WANT_WRITE)
sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
else else
break; break;
if (sockstate == SOCKET_HAS_TIMED_OUT) { if (sockstate == SOCKET_HAS_TIMED_OUT) {
if (ssl_err == SSL_ERROR_WANT_READ) if (ssl_err == SSL_ERROR_WANT_READ)
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"The read operation timed out"); "The read operation timed out");
else else
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"The write operation timed out"); "The write operation timed out");
return NULL; return NULL;
} }
else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"Underlying socket too large for select()."); "Underlying socket too large for select().");
return NULL; return NULL;
} }
else if (sockstate != SOCKET_OPERATION_OK) else if (sockstate != SOCKET_OPERATION_OK)
/* Retain the SSL error code */ /* Retain the SSL error code */
break; break;
} }
if (err < 0) if (err < 0)
return PySSL_SetError(self, err, __FILE__, __LINE__); return PySSL_SetError(self, err, __FILE__, __LINE__);
else { else {
Py_INCREF(self->Socket); Py_INCREF(self->Socket);
return (PyObject *) (self->Socket); return (PyObject *) (self->Socket);
} }
} }
PyDoc_STRVAR(PySSL_SSLshutdown_doc, PyDoc_STRVAR(PySSL_SSLshutdown_doc,
...@@ -1448,44 +1448,44 @@ Does the SSL shutdown handshake with the remote end, and returns\n\ ...@@ -1448,44 +1448,44 @@ Does the SSL shutdown handshake with the remote end, and returns\n\
the underlying socket object."); the underlying socket object.");
static PyMethodDef PySSLMethods[] = { static PyMethodDef PySSLMethods[] = {
{"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS}, {"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS},
{"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, {"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS,
PySSL_SSLwrite_doc}, PySSL_SSLwrite_doc},
{"read", (PyCFunction)PySSL_SSLread, METH_VARARGS, {"read", (PyCFunction)PySSL_SSLread, METH_VARARGS,
PySSL_SSLread_doc}, PySSL_SSLread_doc},
{"pending", (PyCFunction)PySSL_SSLpending, METH_NOARGS, {"pending", (PyCFunction)PySSL_SSLpending, METH_NOARGS,
PySSL_SSLpending_doc}, PySSL_SSLpending_doc},
{"server", (PyCFunction)PySSL_server, METH_NOARGS}, {"server", (PyCFunction)PySSL_server, METH_NOARGS},
{"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS}, {"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS},
{"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS,
PySSL_peercert_doc}, PySSL_peercert_doc},
{"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS},
{"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS,
PySSL_SSLshutdown_doc}, PySSL_SSLshutdown_doc},
{NULL, NULL} {NULL, NULL}
}; };
static PyObject *PySSL_getattr(PySSLObject *self, char *name) static PyObject *PySSL_getattr(PySSLObject *self, char *name)
{ {
return Py_FindMethod(PySSLMethods, (PyObject *)self, name); return Py_FindMethod(PySSLMethods, (PyObject *)self, name);
} }
static PyTypeObject PySSL_Type = { static PyTypeObject PySSL_Type = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"ssl.SSLContext", /*tp_name*/ "ssl.SSLContext", /*tp_name*/
sizeof(PySSLObject), /*tp_basicsize*/ sizeof(PySSLObject), /*tp_basicsize*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
/* methods */ /* methods */
(destructor)PySSL_dealloc, /*tp_dealloc*/ (destructor)PySSL_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
(getattrfunc)PySSL_getattr, /*tp_getattr*/ (getattrfunc)PySSL_getattr, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
0, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
0, /*tp_hash*/ 0, /*tp_hash*/
}; };
#ifdef HAVE_OPENSSL_RAND #ifdef HAVE_OPENSSL_RAND
...@@ -1499,7 +1499,7 @@ PySSL_RAND_add(PyObject *self, PyObject *args) ...@@ -1499,7 +1499,7 @@ PySSL_RAND_add(PyObject *self, PyObject *args)
double entropy; double entropy;
if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy))
return NULL; return NULL;
RAND_add(buf, len, entropy); RAND_add(buf, len, entropy);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
...@@ -1530,15 +1530,15 @@ PySSL_RAND_egd(PyObject *self, PyObject *arg) ...@@ -1530,15 +1530,15 @@ PySSL_RAND_egd(PyObject *self, PyObject *arg)
int bytes; int bytes;
if (!PyString_Check(arg)) if (!PyString_Check(arg))
return PyErr_Format(PyExc_TypeError, return PyErr_Format(PyExc_TypeError,
"RAND_egd() expected string, found %s", "RAND_egd() expected string, found %s",
Py_TYPE(arg)->tp_name); Py_TYPE(arg)->tp_name);
bytes = RAND_egd(PyString_AS_STRING(arg)); bytes = RAND_egd(PyString_AS_STRING(arg));
if (bytes == -1) { if (bytes == -1) {
PyErr_SetString(PySSLErrorObject, PyErr_SetString(PySSLErrorObject,
"EGD connection failed or EGD did not return " "EGD connection failed or EGD did not return "
"enough data to seed the PRNG"); "enough data to seed the PRNG");
return NULL; return NULL;
} }
return PyInt_FromLong(bytes); return PyInt_FromLong(bytes);
} }
...@@ -1555,19 +1555,19 @@ fails or if it does provide enough data to seed PRNG."); ...@@ -1555,19 +1555,19 @@ fails or if it does provide enough data to seed PRNG.");
/* List of functions exported by this module. */ /* List of functions exported by this module. */
static PyMethodDef PySSL_methods[] = { static PyMethodDef PySSL_methods[] = {
{"sslwrap", PySSL_sslwrap, {"sslwrap", PySSL_sslwrap,
METH_VARARGS, ssl_doc}, METH_VARARGS, ssl_doc},
{"_test_decode_cert", PySSL_test_decode_certificate, {"_test_decode_cert", PySSL_test_decode_certificate,
METH_VARARGS}, METH_VARARGS},
#ifdef HAVE_OPENSSL_RAND #ifdef HAVE_OPENSSL_RAND
{"RAND_add", PySSL_RAND_add, METH_VARARGS, {"RAND_add", PySSL_RAND_add, METH_VARARGS,
PySSL_RAND_add_doc}, PySSL_RAND_add_doc},
{"RAND_egd", PySSL_RAND_egd, METH_O, {"RAND_egd", PySSL_RAND_egd, METH_O,
PySSL_RAND_egd_doc}, PySSL_RAND_egd_doc},
{"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS, {"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS,
PySSL_RAND_status_doc}, PySSL_RAND_status_doc},
#endif #endif
{NULL, NULL} /* Sentinel */ {NULL, NULL} /* Sentinel */
}; };
...@@ -1579,64 +1579,64 @@ static PyMethodDef PySSL_methods[] = { ...@@ -1579,64 +1579,64 @@ static PyMethodDef PySSL_methods[] = {
static PyThread_type_lock *_ssl_locks = NULL; static PyThread_type_lock *_ssl_locks = NULL;
static unsigned long _ssl_thread_id_function (void) { static unsigned long _ssl_thread_id_function (void) {
return PyThread_get_thread_ident(); return PyThread_get_thread_ident();
} }
static void _ssl_thread_locking_function (int mode, int n, const char *file, int line) { 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 /* this function is needed to perform locking on shared data
structures. (Note that OpenSSL uses a number of global data structures. (Note that OpenSSL uses a number of global data
structures that will be implicitly shared whenever multiple threads structures that will be implicitly shared whenever multiple threads
use OpenSSL.) Multi-threaded applications will crash at random if use OpenSSL.) Multi-threaded applications will crash at random if
it is not set. it is not set.
locking_function() must be able to handle up to CRYPTO_num_locks() 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 different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
releases it otherwise. releases it otherwise.
file and line are the file number of the function setting the file and line are the file number of the function setting the
lock. They can be useful for debugging. lock. They can be useful for debugging.
*/ */
if ((_ssl_locks == NULL) || if ((_ssl_locks == NULL) ||
(n < 0) || ((unsigned)n >= _ssl_locks_count)) (n < 0) || ((unsigned)n >= _ssl_locks_count))
return; return;
if (mode & CRYPTO_LOCK) { if (mode & CRYPTO_LOCK) {
PyThread_acquire_lock(_ssl_locks[n], 1); PyThread_acquire_lock(_ssl_locks[n], 1);
} else { } else {
PyThread_release_lock(_ssl_locks[n]); PyThread_release_lock(_ssl_locks[n]);
} }
} }
static int _setup_ssl_threads(void) { static int _setup_ssl_threads(void) {
unsigned int i; unsigned int i;
if (_ssl_locks == NULL) { if (_ssl_locks == NULL) {
_ssl_locks_count = CRYPTO_num_locks(); _ssl_locks_count = CRYPTO_num_locks();
_ssl_locks = (PyThread_type_lock *) _ssl_locks = (PyThread_type_lock *)
malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); malloc(sizeof(PyThread_type_lock) * _ssl_locks_count);
if (_ssl_locks == NULL) if (_ssl_locks == NULL)
return 0; return 0;
memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count);
for (i = 0; i < _ssl_locks_count; i++) { for (i = 0; i < _ssl_locks_count; i++) {
_ssl_locks[i] = PyThread_allocate_lock(); _ssl_locks[i] = PyThread_allocate_lock();
if (_ssl_locks[i] == NULL) { if (_ssl_locks[i] == NULL) {
unsigned int j; unsigned int j;
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
PyThread_free_lock(_ssl_locks[j]); PyThread_free_lock(_ssl_locks[j]);
} }
free(_ssl_locks); free(_ssl_locks);
return 0; return 0;
} }
} }
CRYPTO_set_locking_callback(_ssl_thread_locking_function); CRYPTO_set_locking_callback(_ssl_thread_locking_function);
CRYPTO_set_id_callback(_ssl_thread_id_function); CRYPTO_set_id_callback(_ssl_thread_id_function);
} }
return 1; return 1;
} }
#endif /* def HAVE_THREAD */ #endif /* def HAVE_THREAD */
PyDoc_STRVAR(module_doc, PyDoc_STRVAR(module_doc,
"Implementation module for SSL socket operations. See the socket module\n\ "Implementation module for SSL socket operations. See the socket module\n\
...@@ -1645,103 +1645,103 @@ for documentation."); ...@@ -1645,103 +1645,103 @@ for documentation.");
PyMODINIT_FUNC PyMODINIT_FUNC
init_ssl(void) init_ssl(void)
{ {
PyObject *m, *d, *r; PyObject *m, *d, *r;
unsigned long libver; unsigned long libver;
unsigned int major, minor, fix, patch, status; unsigned int major, minor, fix, patch, status;
Py_TYPE(&PySSL_Type) = &PyType_Type; Py_TYPE(&PySSL_Type) = &PyType_Type;
m = Py_InitModule3("_ssl", PySSL_methods, module_doc); m = Py_InitModule3("_ssl", PySSL_methods, module_doc);
if (m == NULL) if (m == NULL)
return; return;
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
/* Load _socket module and its C API */ /* Load _socket module and its C API */
if (PySocketModule_ImportModuleAndAPI()) if (PySocketModule_ImportModuleAndAPI())
return; return;
/* Init OpenSSL */ /* Init OpenSSL */
SSL_load_error_strings(); SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
#ifdef WITH_THREAD #ifdef WITH_THREAD
/* note that this will start threading if not already started */ /* note that this will start threading if not already started */
if (!_setup_ssl_threads()) { if (!_setup_ssl_threads()) {
return; return;
} }
#endif #endif
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
/* Add symbols to module dict */ /* Add symbols to module dict */
PySSLErrorObject = PyErr_NewException("ssl.SSLError", PySSLErrorObject = PyErr_NewException("ssl.SSLError",
PySocketModule.error, PySocketModule.error,
NULL); NULL);
if (PySSLErrorObject == NULL) if (PySSLErrorObject == NULL)
return; return;
if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0) if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0)
return; return;
if (PyDict_SetItemString(d, "SSLType", if (PyDict_SetItemString(d, "SSLType",
(PyObject *)&PySSL_Type) != 0) (PyObject *)&PySSL_Type) != 0)
return; return;
PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN",
PY_SSL_ERROR_ZERO_RETURN); PY_SSL_ERROR_ZERO_RETURN);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ", PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ",
PY_SSL_ERROR_WANT_READ); PY_SSL_ERROR_WANT_READ);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE", PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE",
PY_SSL_ERROR_WANT_WRITE); PY_SSL_ERROR_WANT_WRITE);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP", PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP",
PY_SSL_ERROR_WANT_X509_LOOKUP); PY_SSL_ERROR_WANT_X509_LOOKUP);
PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL", PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL",
PY_SSL_ERROR_SYSCALL); PY_SSL_ERROR_SYSCALL);
PyModule_AddIntConstant(m, "SSL_ERROR_SSL", PyModule_AddIntConstant(m, "SSL_ERROR_SSL",
PY_SSL_ERROR_SSL); PY_SSL_ERROR_SSL);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_CONNECT", PyModule_AddIntConstant(m, "SSL_ERROR_WANT_CONNECT",
PY_SSL_ERROR_WANT_CONNECT); PY_SSL_ERROR_WANT_CONNECT);
/* non ssl.h errorcodes */ /* non ssl.h errorcodes */
PyModule_AddIntConstant(m, "SSL_ERROR_EOF", PyModule_AddIntConstant(m, "SSL_ERROR_EOF",
PY_SSL_ERROR_EOF); PY_SSL_ERROR_EOF);
PyModule_AddIntConstant(m, "SSL_ERROR_INVALID_ERROR_CODE", PyModule_AddIntConstant(m, "SSL_ERROR_INVALID_ERROR_CODE",
PY_SSL_ERROR_INVALID_ERROR_CODE); PY_SSL_ERROR_INVALID_ERROR_CODE);
/* cert requirements */ /* cert requirements */
PyModule_AddIntConstant(m, "CERT_NONE", PyModule_AddIntConstant(m, "CERT_NONE",
PY_SSL_CERT_NONE); PY_SSL_CERT_NONE);
PyModule_AddIntConstant(m, "CERT_OPTIONAL", PyModule_AddIntConstant(m, "CERT_OPTIONAL",
PY_SSL_CERT_OPTIONAL); PY_SSL_CERT_OPTIONAL);
PyModule_AddIntConstant(m, "CERT_REQUIRED", PyModule_AddIntConstant(m, "CERT_REQUIRED",
PY_SSL_CERT_REQUIRED); PY_SSL_CERT_REQUIRED);
/* protocol versions */ /* protocol versions */
PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", PyModule_AddIntConstant(m, "PROTOCOL_SSLv2",
PY_SSL_VERSION_SSL2); PY_SSL_VERSION_SSL2);
PyModule_AddIntConstant(m, "PROTOCOL_SSLv3", PyModule_AddIntConstant(m, "PROTOCOL_SSLv3",
PY_SSL_VERSION_SSL3); PY_SSL_VERSION_SSL3);
PyModule_AddIntConstant(m, "PROTOCOL_SSLv23", PyModule_AddIntConstant(m, "PROTOCOL_SSLv23",
PY_SSL_VERSION_SSL23); PY_SSL_VERSION_SSL23);
PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", PyModule_AddIntConstant(m, "PROTOCOL_TLSv1",
PY_SSL_VERSION_TLS1); PY_SSL_VERSION_TLS1);
/* OpenSSL version */ /* OpenSSL version */
/* SSLeay() gives us the version of the library linked against, /* SSLeay() gives us the version of the library linked against,
which could be different from the headers version. which could be different from the headers version.
*/ */
libver = SSLeay(); libver = SSLeay();
r = PyLong_FromUnsignedLong(libver); r = PyLong_FromUnsignedLong(libver);
if (r == NULL) if (r == NULL)
return; return;
if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r))
return; return;
status = libver & 0xF; status = libver & 0xF;
libver >>= 4; libver >>= 4;
patch = libver & 0xFF; patch = libver & 0xFF;
libver >>= 8; libver >>= 8;
fix = libver & 0xFF; fix = libver & 0xFF;
libver >>= 8; libver >>= 8;
minor = libver & 0xFF; minor = libver & 0xFF;
libver >>= 8; libver >>= 8;
major = libver & 0xFF; major = libver & 0xFF;
r = Py_BuildValue("IIIII", major, minor, fix, patch, status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status);
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r))
return; return;
r = PyString_FromString(SSLeay_version(SSLEAY_VERSION)); r = PyString_FromString(SSLeay_version(SSLEAY_VERSION));
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r))
return; return;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment