You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
13082 lines
512 KiB
13082 lines
512 KiB
# HG changeset patch |
|
# User Benjamin Peterson <benjamin@python.org> |
|
# Date 1408562090 18000 |
|
# Node ID 221a1f9155e2a8b4d12015261b83a2ce3a0c62a2 |
|
# Parent c1edc4e43eb103254c5d96f1708542623fe08f17 |
|
backport many ssl features from Python 3 (closes #21308) |
|
|
|
A contribution of Alex Gaynor and David Reid with the generous support of |
|
Rackspace. May God have mercy on their souls. |
|
|
|
diff -up Python-2.7.5/Lib/ssl.py.rev Python-2.7.5/Lib/ssl.py |
|
--- Python-2.7.5/Lib/ssl.py.rev 2015-03-03 11:11:56.743921122 +0100 |
|
+++ Python-2.7.5/Lib/ssl.py 2015-03-03 11:18:11.829704572 +0100 |
|
@@ -89,6 +89,7 @@ else: |
|
|
|
from socket import socket, _fileobject, _delegate_methods, error as socket_error |
|
from socket import getnameinfo as _getnameinfo |
|
+from socket import SOL_SOCKET, SO_TYPE, SOCK_STREAM |
|
import base64 # for DER-to-PEM translation |
|
import errno |
|
|
|
@@ -108,6 +109,10 @@ class SSLSocket(socket): |
|
ssl_version=PROTOCOL_SSLv23, ca_certs=None, |
|
do_handshake_on_connect=True, |
|
suppress_ragged_eofs=True, ciphers=None): |
|
+ # Can't use sock.type as other flags (such as SOCK_NONBLOCK) get |
|
+ # mixed in. |
|
+ if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM: |
|
+ raise NotImplementedError("only stream sockets are supported") |
|
socket.__init__(self, _sock=sock._sock) |
|
# The initializer for socket overrides the methods send(), recv(), etc. |
|
# in the instancce, which we don't need -- but we want to provide the |
|
diff -up Python-2.7.5/Lib/test/test_ssl.py.rev Python-2.7.5/Lib/test/test_ssl.py |
|
diff -up Python-2.7.5/Modules/_ssl.c.rev Python-2.7.5/Modules/_ssl.c |
|
--- Python-2.7.5/Modules/_ssl.c.rev 2015-03-03 10:37:10.331849242 +0100 |
|
+++ Python-2.7.5/Modules/_ssl.c 2015-03-03 11:11:09.324442807 +0100 |
|
@@ -281,6 +281,7 @@ newPySSLObject(PySocketSockObject *Sock, |
|
self->ssl = NULL; |
|
self->ctx = NULL; |
|
self->Socket = NULL; |
|
+ self->shutdown_seen_zero = 0; |
|
|
|
/* Make sure the SSL error state is initialized */ |
|
(void) ERR_get_state(); |
|
@@ -686,7 +687,7 @@ _get_peer_alt_names (X509 *certificate) |
|
|
|
int i, j; |
|
PyObject *peer_alt_names = Py_None; |
|
- PyObject *v, *t; |
|
+ PyObject *v = NULL, *t; |
|
X509_EXTENSION *ext = NULL; |
|
GENERAL_NAMES *names = NULL; |
|
GENERAL_NAME *name; |
|
@@ -745,7 +746,7 @@ _get_peer_alt_names (X509 *certificate) |
|
ASN1_STRING *as = NULL; |
|
|
|
name = sk_GENERAL_NAME_value(names, j); |
|
- gntype = name-> type; |
|
+ gntype = name->type; |
|
switch (gntype) { |
|
case GEN_DIRNAME: |
|
|
|
@@ -781,15 +782,15 @@ _get_peer_alt_names (X509 *certificate) |
|
goto fail; |
|
switch (gntype) { |
|
case GEN_EMAIL: |
|
- v = PyUnicode_FromString("email"); |
|
+ v = PyString_FromString("email"); |
|
as = name->d.rfc822Name; |
|
break; |
|
case GEN_DNS: |
|
- v = PyUnicode_FromString("DNS"); |
|
+ v = PyString_FromString("DNS"); |
|
as = name->d.dNSName; |
|
break; |
|
case GEN_URI: |
|
- v = PyUnicode_FromString("URI"); |
|
+ v = PyString_FromString("URI"); |
|
as = name->d.uniformResourceIdentifier; |
|
break; |
|
} |
|
@@ -819,7 +820,7 @@ _get_peer_alt_names (X509 *certificate) |
|
break; |
|
default: |
|
if (PyErr_Warn(PyExc_RuntimeWarning, |
|
- "Unknown general name type") == -1) { |
|
+ "Unknown general name type") == -1) { |
|
goto fail; |
|
} |
|
break; |
|
@@ -849,7 +850,7 @@ _get_peer_alt_names (X509 *certificate) |
|
goto fail; |
|
} |
|
PyTuple_SET_ITEM(t, 1, v); |
|
- break; |
|
+ break; |
|
} |
|
|
|
/* and add that rendering to the list */ |
|
@@ -1248,6 +1249,12 @@ static PyObject *PySSL_SSLwrite(PySSLObj |
|
if (!PyArg_ParseTuple(args, "s*:write", &buf)) |
|
return NULL; |
|
|
|
+ if (buf.len > INT_MAX) { |
|
+ PyErr_Format(PyExc_OverflowError, |
|
+ "string longer than %d bytes", INT_MAX); |
|
+ goto error; |
|
+ } |
|
+ |
|
/* just in case the blocking state of the socket has been changed */ |
|
nonblocking = (self->Socket->sock_timeout >= 0.0); |
|
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); |
|
@@ -1269,7 +1276,7 @@ static PyObject *PySSL_SSLwrite(PySSLObj |
|
} |
|
do { |
|
PySSL_BEGIN_ALLOW_THREADS |
|
- len = SSL_write(self->ssl, buf.buf, buf.len); |
|
+ len = SSL_write(self->ssl, buf.buf, (int)buf.len); |
|
err = SSL_get_error(self->ssl, len); |
|
PySSL_END_ALLOW_THREADS |
|
if (PyErr_CheckSignals()) { |
|
@@ -1451,7 +1458,7 @@ static PyObject *PySSL_SSLshutdown(PySSL |
|
* Otherwise OpenSSL might read in too much data, |
|
* eating clear text data that happens to be |
|
* transmitted after the SSL shutdown. |
|
- * Should be safe to call repeatedly everytime this |
|
+ * Should be safe to call repeatedly every time this |
|
* function is used and the shutdown_seen_zero != 0 |
|
* condition is met. |
|
*/ |
|
@@ -1615,9 +1622,9 @@ PyDoc_STRVAR(PySSL_RAND_egd_doc, |
|
\n\ |
|
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."); |
|
+fails or if it does not provide enough data to seed PRNG."); |
|
|
|
-#endif |
|
+#endif /* HAVE_OPENSSL_RAND */ |
|
|
|
/* List of functions exported by this module. */ |
|
|
|
diff -up Python-2.7.5/Modules/_ssl.c.ssl2 Python-2.7.5/Modules/_ssl.c |
|
--- Python-2.7.5/Modules/_ssl.c.ssl2 2015-03-03 15:48:56.112889298 +0100 |
|
+++ Python-2.7.5/Modules/_ssl.c 2015-03-03 15:47:21.598870012 +0100 |
|
@@ -14,20 +14,26 @@ |
|
http://bugs.python.org/issue8108#msg102867 ? |
|
*/ |
|
|
|
+#define PY_SSIZE_T_CLEAN |
|
#include "Python.h" |
|
|
|
#ifdef WITH_THREAD |
|
#include "pythread.h" |
|
+#define PySSL_BEGIN_ALLOW_THREADS_S(save) \ |
|
+ do { if (_ssl_locks_count>0) { (save) = PyEval_SaveThread(); } } while (0) |
|
+#define PySSL_END_ALLOW_THREADS_S(save) \ |
|
+ do { if (_ssl_locks_count>0) { PyEval_RestoreThread(save); } } while (0) |
|
#define PySSL_BEGIN_ALLOW_THREADS { \ |
|
PyThreadState *_save = NULL; \ |
|
- 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);} \ |
|
- } |
|
+ PySSL_BEGIN_ALLOW_THREADS_S(_save); |
|
+#define PySSL_BLOCK_THREADS PySSL_END_ALLOW_THREADS_S(_save); |
|
+#define PySSL_UNBLOCK_THREADS PySSL_BEGIN_ALLOW_THREADS_S(_save); |
|
+#define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); } |
|
|
|
#else /* no WITH_THREAD */ |
|
|
|
+#define PySSL_BEGIN_ALLOW_THREADS_S(save) |
|
+#define PySSL_END_ALLOW_THREADS_S(save) |
|
#define PySSL_BEGIN_ALLOW_THREADS |
|
#define PySSL_BLOCK_THREADS |
|
#define PySSL_UNBLOCK_THREADS |
|
@@ -35,6 +41,68 @@ |
|
|
|
#endif |
|
|
|
+/* Include symbols from _socket module */ |
|
+#include "socketmodule.h" |
|
+ |
|
+#if defined(HAVE_POLL_H) |
|
+#include <poll.h> |
|
+#elif defined(HAVE_SYS_POLL_H) |
|
+#include <sys/poll.h> |
|
+#endif |
|
+ |
|
+/* Include OpenSSL header files */ |
|
+#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" |
|
+#include "openssl/rand.h" |
|
+ |
|
+/* SSL error object */ |
|
+static PyObject *PySSLErrorObject; |
|
+static PyObject *PySSLZeroReturnErrorObject; |
|
+static PyObject *PySSLWantReadErrorObject; |
|
+static PyObject *PySSLWantWriteErrorObject; |
|
+static PyObject *PySSLSyscallErrorObject; |
|
+static PyObject *PySSLEOFErrorObject; |
|
+ |
|
+/* Error mappings */ |
|
+static PyObject *err_codes_to_names; |
|
+static PyObject *err_names_to_codes; |
|
+static PyObject *lib_codes_to_names; |
|
+ |
|
+struct py_ssl_error_code { |
|
+ const char *mnemonic; |
|
+ int library, reason; |
|
+}; |
|
+struct py_ssl_library_code { |
|
+ const char *library; |
|
+ int code; |
|
+}; |
|
+ |
|
+/* Include generated data (error codes) */ |
|
+#include "_ssl_data.h" |
|
+ |
|
+/* Openssl comes with TLSv1.1 and TLSv1.2 between 1.0.0h and 1.0.1 |
|
+ http://www.openssl.org/news/changelog.html |
|
+ */ |
|
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L |
|
+# define HAVE_TLSv1_2 1 |
|
+#else |
|
+# define HAVE_TLSv1_2 0 |
|
+#endif |
|
+ |
|
+/* SNI support (client- and server-side) appeared in OpenSSL 1.0.0 and 0.9.8f |
|
+ * This includes the SSL_set_SSL_CTX() function. |
|
+ */ |
|
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
|
+# define HAVE_SNI 1 |
|
+#else |
|
+# define HAVE_SNI 0 |
|
+#endif |
|
+ |
|
enum py_ssl_error { |
|
/* these mirror ssl.h */ |
|
PY_SSL_ERROR_NONE, |
|
@@ -47,6 +115,7 @@ enum py_ssl_error { |
|
PY_SSL_ERROR_WANT_CONNECT, |
|
/* start of non ssl.h errorcodes */ |
|
PY_SSL_ERROR_EOF, /* special case of SSL_ERROR_SYSCALL */ |
|
+ PY_SSL_ERROR_NO_SOCKET, /* socket has been GC'd */ |
|
PY_SSL_ERROR_INVALID_ERROR_CODE |
|
}; |
|
|
|
@@ -62,35 +131,17 @@ enum py_ssl_cert_requirements { |
|
}; |
|
|
|
enum py_ssl_version { |
|
-#ifndef OPENSSL_NO_SSL2 |
|
PY_SSL_VERSION_SSL2, |
|
-#endif |
|
PY_SSL_VERSION_SSL3=1, |
|
PY_SSL_VERSION_SSL23, |
|
+#if HAVE_TLSv1_2 |
|
+ PY_SSL_VERSION_TLS1, |
|
+ PY_SSL_VERSION_TLS1_1, |
|
+ PY_SSL_VERSION_TLS1_2 |
|
+#else |
|
PY_SSL_VERSION_TLS1 |
|
-}; |
|
- |
|
-/* Include symbols from _socket module */ |
|
-#include "socketmodule.h" |
|
- |
|
-#if defined(HAVE_POLL_H) |
|
-#include <poll.h> |
|
-#elif defined(HAVE_SYS_POLL_H) |
|
-#include <sys/poll.h> |
|
#endif |
|
- |
|
-/* Include OpenSSL header files */ |
|
-#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" |
|
-#include "openssl/rand.h" |
|
- |
|
-/* SSL error object */ |
|
-static PyObject *PySSLErrorObject; |
|
+}; |
|
|
|
#ifdef WITH_THREAD |
|
|
|
@@ -112,27 +163,79 @@ static unsigned int _ssl_locks_count = 0 |
|
# undef HAVE_OPENSSL_RAND |
|
#endif |
|
|
|
+/* SSL_CTX_clear_options() and SSL_clear_options() were first added in |
|
+ * OpenSSL 0.9.8m but do not appear in some 0.9.9-dev versions such the |
|
+ * 0.9.9 from "May 2008" that NetBSD 5.0 uses. */ |
|
+#if OPENSSL_VERSION_NUMBER >= 0x009080dfL && OPENSSL_VERSION_NUMBER != 0x00909000L |
|
+# define HAVE_SSL_CTX_CLEAR_OPTIONS |
|
+#else |
|
+# undef HAVE_SSL_CTX_CLEAR_OPTIONS |
|
+#endif |
|
+ |
|
+/* In case of 'tls-unique' it will be 12 bytes for TLS, 36 bytes for |
|
+ * older SSL, but let's be safe */ |
|
+#define PySSL_CB_MAXLEN 128 |
|
+ |
|
+/* SSL_get_finished got added to OpenSSL in 0.9.5 */ |
|
+#if OPENSSL_VERSION_NUMBER >= 0x0090500fL |
|
+# define HAVE_OPENSSL_FINISHED 1 |
|
+#else |
|
+# define HAVE_OPENSSL_FINISHED 0 |
|
+#endif |
|
+ |
|
+/* ECDH support got added to OpenSSL in 0.9.8 */ |
|
+#if OPENSSL_VERSION_NUMBER < 0x0090800fL && !defined(OPENSSL_NO_ECDH) |
|
+# define OPENSSL_NO_ECDH |
|
+#endif |
|
+ |
|
+/* compression support got added to OpenSSL in 0.9.8 */ |
|
+#if OPENSSL_VERSION_NUMBER < 0x0090800fL && !defined(OPENSSL_NO_COMP) |
|
+# define OPENSSL_NO_COMP |
|
+#endif |
|
+ |
|
+/* X509_VERIFY_PARAM got added to OpenSSL in 0.9.8 */ |
|
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL |
|
+# define HAVE_OPENSSL_VERIFY_PARAM |
|
+#endif |
|
+ |
|
+ |
|
+typedef struct { |
|
+ PyObject_HEAD |
|
+ SSL_CTX *ctx; |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+ char *npn_protocols; |
|
+ int npn_protocols_len; |
|
+#endif |
|
+#ifndef OPENSSL_NO_TLSEXT |
|
+ PyObject *set_hostname; |
|
+#endif |
|
+ int check_hostname; |
|
+} PySSLContext; |
|
+ |
|
typedef struct { |
|
PyObject_HEAD |
|
- PySocketSockObject *Socket; /* Socket on which we're layered */ |
|
- SSL_CTX* ctx; |
|
- SSL* ssl; |
|
- X509* peer_cert; |
|
- char server[X509_NAME_MAXLEN]; |
|
- char issuer[X509_NAME_MAXLEN]; |
|
- int shutdown_seen_zero; |
|
- |
|
-} PySSLObject; |
|
- |
|
-static PyTypeObject PySSL_Type; |
|
-static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); |
|
-static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); |
|
+ PySocketSockObject *Socket; |
|
+ PyObject *ssl_sock; |
|
+ SSL *ssl; |
|
+ PySSLContext *ctx; /* weakref to SSL context */ |
|
+ X509 *peer_cert; |
|
+ char shutdown_seen_zero; |
|
+ char handshake_done; |
|
+ enum py_ssl_server_or_client socket_type; |
|
+} PySSLSocket; |
|
+ |
|
+static PyTypeObject PySSLContext_Type; |
|
+static PyTypeObject PySSLSocket_Type; |
|
+ |
|
+static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args); |
|
+static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args); |
|
static int check_socket_and_wait_for_timeout(PySocketSockObject *s, |
|
int writing); |
|
-static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args); |
|
-static PyObject *PySSL_cipher(PySSLObject *self); |
|
+static PyObject *PySSL_peercert(PySSLSocket *self, PyObject *args); |
|
+static PyObject *PySSL_cipher(PySSLSocket *self); |
|
|
|
-#define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type) |
|
+#define PySSLContext_Check(v) (Py_TYPE(v) == &PySSLContext_Type) |
|
+#define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type) |
|
|
|
typedef enum { |
|
SOCKET_IS_NONBLOCKING, |
|
@@ -149,36 +252,140 @@ typedef enum { |
|
#define ERRSTR1(x,y,z) (x ":" y ": " z) |
|
#define ERRSTR(x) ERRSTR1("_ssl.c", STRINGIFY2(__LINE__), x) |
|
|
|
-/* XXX It might be helpful to augment the error message generated |
|
- below with the name of the SSL function that generated the error. |
|
- I expect it's obvious most of the time. |
|
-*/ |
|
+ |
|
+/* |
|
+ * SSL errors. |
|
+ */ |
|
+ |
|
+PyDoc_STRVAR(SSLError_doc, |
|
+"An error occurred in the SSL implementation."); |
|
+ |
|
+PyDoc_STRVAR(SSLZeroReturnError_doc, |
|
+"SSL/TLS session closed cleanly."); |
|
+ |
|
+PyDoc_STRVAR(SSLWantReadError_doc, |
|
+"Non-blocking SSL socket needs to read more data\n" |
|
+"before the requested operation can be completed."); |
|
+ |
|
+PyDoc_STRVAR(SSLWantWriteError_doc, |
|
+"Non-blocking SSL socket needs to write more data\n" |
|
+"before the requested operation can be completed."); |
|
+ |
|
+PyDoc_STRVAR(SSLSyscallError_doc, |
|
+"System error when attempting SSL operation."); |
|
+ |
|
+PyDoc_STRVAR(SSLEOFError_doc, |
|
+"SSL/TLS connection terminated abruptly."); |
|
+ |
|
|
|
static PyObject * |
|
-PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno) |
|
+SSLError_str(PyEnvironmentErrorObject *self) |
|
{ |
|
- PyObject *v; |
|
- char buf[2048]; |
|
- char *errstr; |
|
+ if (self->strerror != NULL) { |
|
+ Py_INCREF(self->strerror); |
|
+ return self->strerror; |
|
+ } |
|
+ else |
|
+ return PyObject_Str(self->args); |
|
+} |
|
+ |
|
+static void |
|
+fill_and_set_sslerror(PyObject *type, int ssl_errno, const char *errstr, |
|
+ int lineno, unsigned long errcode) |
|
+{ |
|
+ PyObject *err_value = NULL, *reason_obj = NULL, *lib_obj = NULL; |
|
+ PyObject *init_value, *msg, *key; |
|
+ |
|
+ if (errcode != 0) { |
|
+ int lib, reason; |
|
+ |
|
+ lib = ERR_GET_LIB(errcode); |
|
+ reason = ERR_GET_REASON(errcode); |
|
+ key = Py_BuildValue("ii", lib, reason); |
|
+ if (key == NULL) |
|
+ goto fail; |
|
+ reason_obj = PyDict_GetItem(err_codes_to_names, key); |
|
+ Py_DECREF(key); |
|
+ if (reason_obj == NULL) { |
|
+ /* XXX if reason < 100, it might reflect a library number (!!) */ |
|
+ PyErr_Clear(); |
|
+ } |
|
+ key = PyLong_FromLong(lib); |
|
+ if (key == NULL) |
|
+ goto fail; |
|
+ lib_obj = PyDict_GetItem(lib_codes_to_names, key); |
|
+ Py_DECREF(key); |
|
+ if (lib_obj == NULL) { |
|
+ PyErr_Clear(); |
|
+ } |
|
+ if (errstr == NULL) |
|
+ errstr = ERR_reason_error_string(errcode); |
|
+ } |
|
+ if (errstr == NULL) |
|
+ errstr = "unknown error"; |
|
+ |
|
+ if (reason_obj && lib_obj) |
|
+ msg = PyUnicode_FromFormat("[%S: %S] %s (_ssl.c:%d)", |
|
+ lib_obj, reason_obj, errstr, lineno); |
|
+ else if (lib_obj) |
|
+ msg = PyUnicode_FromFormat("[%S] %s (_ssl.c:%d)", |
|
+ lib_obj, errstr, lineno); |
|
+ else |
|
+ msg = PyUnicode_FromFormat("%s (_ssl.c:%d)", errstr, lineno); |
|
+ if (msg == NULL) |
|
+ goto fail; |
|
+ |
|
+ init_value = Py_BuildValue("iN", ssl_errno, msg); |
|
+ if (init_value == NULL) |
|
+ goto fail; |
|
+ |
|
+ err_value = PyObject_CallObject(type, init_value); |
|
+ Py_DECREF(init_value); |
|
+ if (err_value == NULL) |
|
+ goto fail; |
|
+ |
|
+ if (reason_obj == NULL) |
|
+ reason_obj = Py_None; |
|
+ if (PyObject_SetAttrString(err_value, "reason", reason_obj)) |
|
+ goto fail; |
|
+ if (lib_obj == NULL) |
|
+ lib_obj = Py_None; |
|
+ if (PyObject_SetAttrString(err_value, "library", lib_obj)) |
|
+ goto fail; |
|
+ PyErr_SetObject(type, err_value); |
|
+fail: |
|
+ Py_XDECREF(err_value); |
|
+} |
|
+ |
|
+static PyObject * |
|
+PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno) |
|
+{ |
|
+ PyObject *type = PySSLErrorObject; |
|
+ char *errstr = NULL; |
|
int err; |
|
enum py_ssl_error p = PY_SSL_ERROR_NONE; |
|
+ unsigned long e = 0; |
|
|
|
assert(ret <= 0); |
|
+ e = ERR_peek_last_error(); |
|
|
|
if (obj->ssl != NULL) { |
|
err = SSL_get_error(obj->ssl, ret); |
|
|
|
switch (err) { |
|
case SSL_ERROR_ZERO_RETURN: |
|
- errstr = "TLS/SSL connection has been closed"; |
|
+ errstr = "TLS/SSL connection has been closed (EOF)"; |
|
+ type = PySSLZeroReturnErrorObject; |
|
p = PY_SSL_ERROR_ZERO_RETURN; |
|
break; |
|
case SSL_ERROR_WANT_READ: |
|
errstr = "The operation did not complete (read)"; |
|
+ type = PySSLWantReadErrorObject; |
|
p = PY_SSL_ERROR_WANT_READ; |
|
break; |
|
case SSL_ERROR_WANT_WRITE: |
|
p = PY_SSL_ERROR_WANT_WRITE; |
|
+ type = PySSLWantWriteErrorObject; |
|
errstr = "The operation did not complete (write)"; |
|
break; |
|
case SSL_ERROR_WANT_X509_LOOKUP: |
|
@@ -191,210 +398,109 @@ PySSL_SetError(PySSLObject *obj, int ret |
|
break; |
|
case SSL_ERROR_SYSCALL: |
|
{ |
|
- unsigned long e = ERR_get_error(); |
|
if (e == 0) { |
|
- if (ret == 0 || !obj->Socket) { |
|
+ PySocketSockObject *s = obj->Socket; |
|
+ if (ret == 0) { |
|
p = PY_SSL_ERROR_EOF; |
|
+ type = PySSLEOFErrorObject; |
|
errstr = "EOF occurred in violation of protocol"; |
|
} else if (ret == -1) { |
|
/* underlying BIO reported an I/O error */ |
|
+ Py_INCREF(s); |
|
ERR_clear_error(); |
|
- return obj->Socket->errorhandler(); |
|
+ s->errorhandler(); |
|
+ Py_DECREF(s); |
|
+ return NULL; |
|
} else { /* possible? */ |
|
p = PY_SSL_ERROR_SYSCALL; |
|
+ type = PySSLSyscallErrorObject; |
|
errstr = "Some I/O error occurred"; |
|
} |
|
} else { |
|
p = PY_SSL_ERROR_SYSCALL; |
|
- /* XXX Protected by global interpreter lock */ |
|
- errstr = ERR_error_string(e, NULL); |
|
} |
|
break; |
|
} |
|
case SSL_ERROR_SSL: |
|
{ |
|
- unsigned long e = ERR_get_error(); |
|
p = PY_SSL_ERROR_SSL; |
|
- if (e != 0) |
|
- /* XXX Protected by global interpreter lock */ |
|
- errstr = ERR_error_string(e, NULL); |
|
- else { /* possible? */ |
|
+ if (e == 0) |
|
+ /* possible? */ |
|
errstr = "A failure in the SSL library occurred"; |
|
- } |
|
break; |
|
} |
|
default: |
|
p = PY_SSL_ERROR_INVALID_ERROR_CODE; |
|
errstr = "Invalid error code"; |
|
} |
|
- } else { |
|
- errstr = ERR_error_string(ERR_peek_last_error(), NULL); |
|
} |
|
- PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr); |
|
+ fill_and_set_sslerror(type, p, errstr, lineno, e); |
|
ERR_clear_error(); |
|
- v = Py_BuildValue("(is)", p, buf); |
|
- if (v != NULL) { |
|
- PyErr_SetObject(PySSLErrorObject, v); |
|
- Py_DECREF(v); |
|
- } |
|
return NULL; |
|
} |
|
|
|
static PyObject * |
|
_setSSLError (char *errstr, int errcode, char *filename, int lineno) { |
|
|
|
- char buf[2048]; |
|
- PyObject *v; |
|
- |
|
- if (errstr == NULL) { |
|
+ 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); |
|
+ else |
|
+ errcode = 0; |
|
+ fill_and_set_sslerror(PySSLErrorObject, errcode, errstr, lineno, errcode); |
|
ERR_clear_error(); |
|
- 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, |
|
+/* |
|
+ * SSL objects |
|
+ */ |
|
+ |
|
+static PySSLSocket * |
|
+newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, |
|
enum py_ssl_server_or_client socket_type, |
|
- enum py_ssl_cert_requirements certreq, |
|
- enum py_ssl_version proto_version, |
|
- char *cacerts_file, char *ciphers) |
|
+ char *server_hostname, PyObject *ssl_sock) |
|
{ |
|
- PySSLObject *self; |
|
- char *errstr = NULL; |
|
- int ret; |
|
- int verification_mode; |
|
+ PySSLSocket *self; |
|
+ SSL_CTX *ctx = sslctx->ctx; |
|
+ long mode; |
|
|
|
- self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ |
|
+ self = PyObject_New(PySSLSocket, &PySSLSocket_Type); |
|
if (self == NULL) |
|
return NULL; |
|
- memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN); |
|
- memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); |
|
+ |
|
self->peer_cert = NULL; |
|
self->ssl = NULL; |
|
- self->ctx = NULL; |
|
self->Socket = NULL; |
|
+ self->ssl_sock = NULL; |
|
+ self->ctx = sslctx; |
|
self->shutdown_seen_zero = 0; |
|
+ self->handshake_done = 0; |
|
+ Py_INCREF(sslctx); |
|
|
|
/* 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"); |
|
- goto fail; |
|
- } |
|
- |
|
- if ((socket_type == PY_SSL_SERVER) && |
|
- ((key_file == NULL) || (cert_file == NULL))) { |
|
- errstr = ERRSTR("Both the key & certificate files " |
|
- "must be specified for server-side operation"); |
|
- goto fail; |
|
- } |
|
- |
|
- 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 */ |
|
-#ifndef OPENSSL_NO_SSL2 |
|
- else if (proto_version == PY_SSL_VERSION_SSL2) |
|
- self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ |
|
-#endif |
|
- else if (proto_version == PY_SSL_VERSION_SSL23) |
|
- self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ |
|
- PySSL_END_ALLOW_THREADS |
|
- |
|
- if (self->ctx == NULL) { |
|
- errstr = ERRSTR("Invalid SSL protocol variant specified."); |
|
- goto fail; |
|
- } |
|
- |
|
- if (ciphers != NULL) { |
|
- ret = SSL_CTX_set_cipher_list(self->ctx, ciphers); |
|
- if (ret == 0) { |
|
- errstr = ERRSTR("No cipher can be selected."); |
|
- goto fail; |
|
- } |
|
- } |
|
- |
|
- if (certreq != PY_SSL_CERT_NONE) { |
|
- if (cacerts_file == NULL) { |
|
- errstr = ERRSTR("No root certificates specified for " |
|
- "verification of other-side certificates."); |
|
- goto fail; |
|
- } else { |
|
- PySSL_BEGIN_ALLOW_THREADS |
|
- ret = SSL_CTX_load_verify_locations(self->ctx, |
|
- cacerts_file, |
|
- NULL); |
|
- PySSL_END_ALLOW_THREADS |
|
- if (ret != 1) { |
|
- _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
- goto fail; |
|
- } |
|
- } |
|
- } |
|
- if (key_file) { |
|
- PySSL_BEGIN_ALLOW_THREADS |
|
- ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, |
|
- SSL_FILETYPE_PEM); |
|
- PySSL_END_ALLOW_THREADS |
|
- if (ret != 1) { |
|
- _setSSLError(NULL, ret, __FILE__, __LINE__); |
|
- goto fail; |
|
- } |
|
- |
|
- PySSL_BEGIN_ALLOW_THREADS |
|
- ret = SSL_CTX_use_certificate_chain_file(self->ctx, |
|
- cert_file); |
|
- PySSL_END_ALLOW_THREADS |
|
- if (ret != 1) { |
|
- /* |
|
- 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_OP_DONT_INSERT_EMPTY_FRAGMENTS); |
|
- |
|
- verification_mode = SSL_VERIFY_NONE; |
|
- if (certreq == PY_SSL_CERT_OPTIONAL) |
|
- verification_mode = SSL_VERIFY_PEER; |
|
- else if (certreq == PY_SSL_CERT_REQUIRED) |
|
- verification_mode = (SSL_VERIFY_PEER | |
|
- SSL_VERIFY_FAIL_IF_NO_PEER_CERT); |
|
- SSL_CTX_set_verify(self->ctx, verification_mode, |
|
- NULL); /* set verify lvl */ |
|
- |
|
PySSL_BEGIN_ALLOW_THREADS |
|
- self->ssl = SSL_new(self->ctx); /* New ssl struct */ |
|
+ self->ssl = SSL_new(ctx); |
|
PySSL_END_ALLOW_THREADS |
|
- SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ |
|
+ SSL_set_app_data(self->ssl,self); |
|
+ SSL_set_fd(self->ssl, Py_SAFE_DOWNCAST(sock->sock_fd, SOCKET_T, int)); |
|
+ mode = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; |
|
#ifdef SSL_MODE_AUTO_RETRY |
|
- SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); |
|
+ mode |= SSL_MODE_AUTO_RETRY; |
|
+#endif |
|
+ SSL_set_mode(self->ssl, mode); |
|
+ |
|
+#if HAVE_SNI |
|
+ if (server_hostname != NULL) |
|
+ SSL_set_tlsext_host_name(self->ssl, server_hostname); |
|
#endif |
|
|
|
/* If the socket is in non-blocking mode or timeout mode, set the BIO |
|
* to non-blocking mode (blocking is the default) |
|
*/ |
|
- if (Sock->sock_timeout >= 0.0) { |
|
- /* Set both the read and write BIO's to non-blocking mode */ |
|
+ if (sock->sock_timeout >= 0.0) { |
|
BIO_set_nbio(SSL_get_rbio(self->ssl), 1); |
|
BIO_set_nbio(SSL_get_wbio(self->ssl), 1); |
|
} |
|
@@ -406,65 +512,31 @@ newPySSLObject(PySocketSockObject *Sock, |
|
SSL_set_accept_state(self->ssl); |
|
PySSL_END_ALLOW_THREADS |
|
|
|
- self->Socket = Sock; |
|
+ self->socket_type = socket_type; |
|
+ self->Socket = sock; |
|
Py_INCREF(self->Socket); |
|
+ self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL); |
|
+ if (self->ssl_sock == NULL) { |
|
+ Py_DECREF(self); |
|
+ return NULL; |
|
+ } |
|
return self; |
|
- fail: |
|
- if (errstr) |
|
- PyErr_SetString(PySSLErrorObject, errstr); |
|
- Py_DECREF(self); |
|
- return NULL; |
|
} |
|
|
|
-static PyObject * |
|
-PySSL_sslwrap(PyObject *self, PyObject *args) |
|
-{ |
|
- PySocketSockObject *Sock; |
|
- int server_side = 0; |
|
- int verification_mode = PY_SSL_CERT_NONE; |
|
- int protocol = PY_SSL_VERSION_SSL23; |
|
- char *key_file = NULL; |
|
- char *cert_file = NULL; |
|
- char *cacerts_file = NULL; |
|
- char *ciphers = NULL; |
|
- |
|
- if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap", |
|
- PySocketModule.Sock_Type, |
|
- &Sock, |
|
- &server_side, |
|
- &key_file, &cert_file, |
|
- &verification_mode, &protocol, |
|
- &cacerts_file, &ciphers)) |
|
- return NULL; |
|
- |
|
- /* |
|
- fprintf(stderr, |
|
- "server_side is %d, keyfile %p, certfile %p, verify_mode %d, " |
|
- "protocol %d, certs %p\n", |
|
- server_side, key_file, cert_file, verification_mode, |
|
- protocol, cacerts_file); |
|
- */ |
|
- |
|
- return (PyObject *) newPySSLObject(Sock, key_file, cert_file, |
|
- server_side, verification_mode, |
|
- protocol, cacerts_file, |
|
- ciphers); |
|
-} |
|
- |
|
-PyDoc_STRVAR(ssl_doc, |
|
-"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n" |
|
-" cacertsfile, ciphers]) -> sslobject"); |
|
|
|
/* SSL object methods */ |
|
|
|
-static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) |
|
+static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self) |
|
{ |
|
int ret; |
|
int err; |
|
int sockstate, nonblocking; |
|
+ PySocketSockObject *sock = self->Socket; |
|
+ |
|
+ Py_INCREF(sock); |
|
|
|
/* just in case the blocking state of the socket has been changed */ |
|
- nonblocking = (self->Socket->sock_timeout >= 0.0); |
|
+ nonblocking = (sock->sock_timeout >= 0.0); |
|
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); |
|
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); |
|
|
|
@@ -475,60 +547,48 @@ static PyObject *PySSL_SSLdo_handshake(P |
|
ret = SSL_do_handshake(self->ssl); |
|
err = SSL_get_error(self->ssl, ret); |
|
PySSL_END_ALLOW_THREADS |
|
- if(PyErr_CheckSignals()) { |
|
- return NULL; |
|
- } |
|
+ if (PyErr_CheckSignals()) |
|
+ goto error; |
|
if (err == SSL_ERROR_WANT_READ) { |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 0); |
|
} else if (err == SSL_ERROR_WANT_WRITE) { |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 1); |
|
} else { |
|
sockstate = SOCKET_OPERATION_OK; |
|
} |
|
if (sockstate == SOCKET_HAS_TIMED_OUT) { |
|
PyErr_SetString(PySSLErrorObject, |
|
ERRSTR("The handshake operation timed out")); |
|
- return NULL; |
|
+ goto error; |
|
} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { |
|
PyErr_SetString(PySSLErrorObject, |
|
ERRSTR("Underlying socket has been closed.")); |
|
- return NULL; |
|
+ goto error; |
|
} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { |
|
PyErr_SetString(PySSLErrorObject, |
|
ERRSTR("Underlying socket too large for select().")); |
|
- return NULL; |
|
+ goto error; |
|
} else if (sockstate == SOCKET_IS_NONBLOCKING) { |
|
break; |
|
} |
|
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); |
|
+ Py_DECREF(sock); |
|
if (ret < 1) |
|
return PySSL_SetError(self, ret, __FILE__, __LINE__); |
|
|
|
if (self->peer_cert) |
|
X509_free (self->peer_cert); |
|
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); |
|
- } |
|
+ self->peer_cert = SSL_get_peer_certificate(self->ssl); |
|
PySSL_END_ALLOW_THREADS |
|
+ self->handshake_done = 1; |
|
|
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
-} |
|
- |
|
-static PyObject * |
|
-PySSL_server(PySSLObject *self) |
|
-{ |
|
- return PyString_FromString(self->server); |
|
-} |
|
|
|
-static PyObject * |
|
-PySSL_issuer(PySSLObject *self) |
|
-{ |
|
- return PyString_FromString(self->issuer); |
|
+error: |
|
+ Py_DECREF(sock); |
|
+ return NULL; |
|
} |
|
|
|
static PyObject * |
|
@@ -634,8 +694,8 @@ _create_tuple_for_X509_NAME (X509_NAME * |
|
/* |
|
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))); |
|
+ PyBytes_AS_STRING(PyTuple_GET_ITEM(attr, 0)), |
|
+ PyBytes_AS_STRING(PyTuple_GET_ITEM(attr, 1))); |
|
*/ |
|
if (attr == NULL) |
|
goto fail1; |
|
@@ -722,21 +782,24 @@ _get_peer_alt_names (X509 *certificate) |
|
/* 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!")); |
|
+ 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))); |
|
+ 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)); |
|
+ names = (GENERAL_NAMES*) |
|
+ (method->d2i(NULL, |
|
+ &p, |
|
+ ext->value->length)); |
|
|
|
for(j = 0; j < sk_GENERAL_NAME_num(names); j++) { |
|
|
|
@@ -885,7 +948,127 @@ _get_peer_alt_names (X509 *certificate) |
|
} |
|
|
|
static PyObject * |
|
-_decode_certificate (X509 *certificate, int verbose) { |
|
+_get_aia_uri(X509 *certificate, int nid) { |
|
+ PyObject *lst = NULL, *ostr = NULL; |
|
+ int i, result; |
|
+ AUTHORITY_INFO_ACCESS *info; |
|
+ |
|
+ info = X509_get_ext_d2i(certificate, NID_info_access, NULL, NULL); |
|
+ if ((info == NULL) || (sk_ACCESS_DESCRIPTION_num(info) == 0)) { |
|
+ return Py_None; |
|
+ } |
|
+ |
|
+ if ((lst = PyList_New(0)) == NULL) { |
|
+ goto fail; |
|
+ } |
|
+ |
|
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) { |
|
+ ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i); |
|
+ ASN1_IA5STRING *uri; |
|
+ |
|
+ if ((OBJ_obj2nid(ad->method) != nid) || |
|
+ (ad->location->type != GEN_URI)) { |
|
+ continue; |
|
+ } |
|
+ uri = ad->location->d.uniformResourceIdentifier; |
|
+ ostr = PyUnicode_FromStringAndSize((char *)uri->data, |
|
+ uri->length); |
|
+ if (ostr == NULL) { |
|
+ goto fail; |
|
+ } |
|
+ result = PyList_Append(lst, ostr); |
|
+ Py_DECREF(ostr); |
|
+ if (result < 0) { |
|
+ goto fail; |
|
+ } |
|
+ } |
|
+ AUTHORITY_INFO_ACCESS_free(info); |
|
+ |
|
+ /* convert to tuple or None */ |
|
+ if (PyList_Size(lst) == 0) { |
|
+ Py_DECREF(lst); |
|
+ return Py_None; |
|
+ } else { |
|
+ PyObject *tup; |
|
+ tup = PyList_AsTuple(lst); |
|
+ Py_DECREF(lst); |
|
+ return tup; |
|
+ } |
|
+ |
|
+ fail: |
|
+ AUTHORITY_INFO_ACCESS_free(info); |
|
+ Py_XDECREF(lst); |
|
+ return NULL; |
|
+} |
|
+ |
|
+static PyObject * |
|
+_get_crl_dp(X509 *certificate) { |
|
+ STACK_OF(DIST_POINT) *dps; |
|
+ int i, j, result; |
|
+ PyObject *lst; |
|
+ |
|
+#if OPENSSL_VERSION_NUMBER < 0x10001000L |
|
+ dps = X509_get_ext_d2i(certificate, NID_crl_distribution_points, |
|
+ NULL, NULL); |
|
+#else |
|
+ /* Calls x509v3_cache_extensions and sets up crldp */ |
|
+ X509_check_ca(certificate); |
|
+ dps = certificate->crldp; |
|
+#endif |
|
+ |
|
+ if (dps == NULL) { |
|
+ return Py_None; |
|
+ } |
|
+ |
|
+ if ((lst = PyList_New(0)) == NULL) { |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ for (i=0; i < sk_DIST_POINT_num(dps); i++) { |
|
+ DIST_POINT *dp; |
|
+ STACK_OF(GENERAL_NAME) *gns; |
|
+ |
|
+ dp = sk_DIST_POINT_value(dps, i); |
|
+ gns = dp->distpoint->name.fullname; |
|
+ |
|
+ for (j=0; j < sk_GENERAL_NAME_num(gns); j++) { |
|
+ GENERAL_NAME *gn; |
|
+ ASN1_IA5STRING *uri; |
|
+ PyObject *ouri; |
|
+ |
|
+ gn = sk_GENERAL_NAME_value(gns, j); |
|
+ if (gn->type != GEN_URI) { |
|
+ continue; |
|
+ } |
|
+ uri = gn->d.uniformResourceIdentifier; |
|
+ ouri = PyUnicode_FromStringAndSize((char *)uri->data, |
|
+ uri->length); |
|
+ if (ouri == NULL) { |
|
+ Py_DECREF(lst); |
|
+ return NULL; |
|
+ } |
|
+ result = PyList_Append(lst, ouri); |
|
+ Py_DECREF(ouri); |
|
+ if (result < 0) { |
|
+ Py_DECREF(lst); |
|
+ return NULL; |
|
+ } |
|
+ } |
|
+ } |
|
+ /* convert to tuple or None */ |
|
+ if (PyList_Size(lst) == 0) { |
|
+ Py_DECREF(lst); |
|
+ return Py_None; |
|
+ } else { |
|
+ PyObject *tup; |
|
+ tup = PyList_AsTuple(lst); |
|
+ Py_DECREF(lst); |
|
+ return tup; |
|
+ } |
|
+} |
|
+ |
|
+static PyObject * |
|
+_decode_certificate(X509 *certificate) { |
|
|
|
PyObject *retval = NULL; |
|
BIO *biobuf = NULL; |
|
@@ -894,9 +1077,10 @@ _decode_certificate (X509 *certificate, |
|
PyObject *issuer; |
|
PyObject *version; |
|
PyObject *sn_obj; |
|
+ PyObject *obj; |
|
ASN1_INTEGER *serialNumber; |
|
char buf[2048]; |
|
- int len; |
|
+ int len, result; |
|
ASN1_TIME *notBefore, *notAfter; |
|
PyObject *pnotBefore, *pnotAfter; |
|
|
|
@@ -914,65 +1098,62 @@ _decode_certificate (X509 *certificate, |
|
} |
|
Py_DECREF(peer); |
|
|
|
- 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; |
|
- } |
|
+ 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); |
|
|
|
- version = PyInt_FromLong(X509_get_version(certificate) + 1); |
|
- if (PyDict_SetItemString(retval, "version", version) < 0) { |
|
- Py_DECREF(version); |
|
- goto fail0; |
|
- } |
|
+ version = PyLong_FromLong(X509_get_version(certificate) + 1); |
|
+ if (version == NULL) |
|
+ goto fail0; |
|
+ if (PyDict_SetItemString(retval, "version", version) < 0) { |
|
Py_DECREF(version); |
|
+ goto fail0; |
|
} |
|
+ Py_DECREF(version); |
|
|
|
/* get a memory buffer */ |
|
biobuf = BIO_new(BIO_s_mem()); |
|
|
|
- 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; |
|
- } |
|
+ (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 = PyUnicode_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; |
|
- } |
|
+ (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 = PyUnicode_FromStringAndSize(buf, len); |
|
+ if (pnotBefore == NULL) |
|
+ goto fail1; |
|
+ if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) { |
|
Py_DECREF(pnotBefore); |
|
+ goto fail1; |
|
} |
|
+ Py_DECREF(pnotBefore); |
|
|
|
(void) BIO_reset(biobuf); |
|
notAfter = X509_get_notAfter(certificate); |
|
@@ -1005,6 +1186,41 @@ _decode_certificate (X509 *certificate, |
|
Py_DECREF(peer_alt_names); |
|
} |
|
|
|
+ /* Authority Information Access: OCSP URIs */ |
|
+ obj = _get_aia_uri(certificate, NID_ad_OCSP); |
|
+ if (obj == NULL) { |
|
+ goto fail1; |
|
+ } else if (obj != Py_None) { |
|
+ result = PyDict_SetItemString(retval, "OCSP", obj); |
|
+ Py_DECREF(obj); |
|
+ if (result < 0) { |
|
+ goto fail1; |
|
+ } |
|
+ } |
|
+ |
|
+ obj = _get_aia_uri(certificate, NID_ad_ca_issuers); |
|
+ if (obj == NULL) { |
|
+ goto fail1; |
|
+ } else if (obj != Py_None) { |
|
+ result = PyDict_SetItemString(retval, "caIssuers", obj); |
|
+ Py_DECREF(obj); |
|
+ if (result < 0) { |
|
+ goto fail1; |
|
+ } |
|
+ } |
|
+ |
|
+ /* CDP (CRL distribution points) */ |
|
+ obj = _get_crl_dp(certificate); |
|
+ if (obj == NULL) { |
|
+ goto fail1; |
|
+ } else if (obj != Py_None) { |
|
+ result = PyDict_SetItemString(retval, "crlDistributionPoints", obj); |
|
+ Py_DECREF(obj); |
|
+ if (result < 0) { |
|
+ goto fail1; |
|
+ } |
|
+ } |
|
+ |
|
BIO_free(biobuf); |
|
return retval; |
|
|
|
@@ -1016,6 +1232,24 @@ _decode_certificate (X509 *certificate, |
|
return NULL; |
|
} |
|
|
|
+static PyObject * |
|
+_certificate_to_der(X509 *certificate) |
|
+{ |
|
+ unsigned char *bytes_buf = NULL; |
|
+ int len; |
|
+ PyObject *retval; |
|
+ |
|
+ bytes_buf = NULL; |
|
+ len = i2d_X509(certificate, &bytes_buf); |
|
+ if (len < 0) { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ return NULL; |
|
+ } |
|
+ /* this is actually an immutable bytes sequence */ |
|
+ retval = PyBytes_FromStringAndSize((const char *) bytes_buf, len); |
|
+ OPENSSL_free(bytes_buf); |
|
+ return retval; |
|
+} |
|
|
|
static PyObject * |
|
PySSL_test_decode_certificate (PyObject *mod, PyObject *args) { |
|
@@ -1024,28 +1258,30 @@ PySSL_test_decode_certificate (PyObject |
|
char *filename = NULL; |
|
X509 *x=NULL; |
|
BIO *cert; |
|
- int verbose = 1; |
|
|
|
- if (!PyArg_ParseTuple(args, "s|i:test_decode_certificate", &filename, &verbose)) |
|
+ if (!PyArg_ParseTuple(args, "s:test_decode_certificate", &filename)) |
|
return 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; |
|
} |
|
|
|
if (BIO_read_filename(cert,filename) <= 0) { |
|
- PyErr_SetString(PySSLErrorObject, "Can't open file"); |
|
+ 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"); |
|
+ PyErr_SetString(PySSLErrorObject, |
|
+ "Error decoding PEM-encoded file"); |
|
goto fail0; |
|
} |
|
|
|
- retval = _decode_certificate(x, verbose); |
|
+ retval = _decode_certificate(x); |
|
X509_free(x); |
|
|
|
fail0: |
|
@@ -1056,10 +1292,8 @@ PySSL_test_decode_certificate (PyObject |
|
|
|
|
|
static PyObject * |
|
-PySSL_peercert(PySSLObject *self, PyObject *args) |
|
+PySSL_peercert(PySSLSocket *self, PyObject *args) |
|
{ |
|
- PyObject *retval = NULL; |
|
- int len; |
|
int verification; |
|
PyObject *binary_mode = Py_None; |
|
int b; |
|
@@ -1067,6 +1301,11 @@ PySSL_peercert(PySSLObject *self, PyObje |
|
if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode)) |
|
return NULL; |
|
|
|
+ if (!self->handshake_done) { |
|
+ PyErr_SetString(PyExc_ValueError, |
|
+ "handshake not done yet"); |
|
+ return NULL; |
|
+ } |
|
if (!self->peer_cert) |
|
Py_RETURN_NONE; |
|
|
|
@@ -1075,26 +1314,13 @@ PySSL_peercert(PySSLObject *self, PyObje |
|
return NULL; |
|
if (b) { |
|
/* 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; |
|
- |
|
+ return _certificate_to_der(self->peer_cert); |
|
} else { |
|
- |
|
- verification = SSL_CTX_get_verify_mode(self->ctx); |
|
+ verification = SSL_CTX_get_verify_mode(SSL_get_SSL_CTX(self->ssl)); |
|
if ((verification & SSL_VERIFY_PEER) == 0) |
|
return PyDict_New(); |
|
else |
|
- return _decode_certificate (self->peer_cert, 0); |
|
+ return _decode_certificate(self->peer_cert); |
|
} |
|
} |
|
|
|
@@ -1110,7 +1336,7 @@ If the optional argument is True, return |
|
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) { |
|
+static PyObject *PySSL_cipher (PySSLSocket *self) { |
|
|
|
PyObject *retval, *v; |
|
const SSL_CIPHER *current; |
|
@@ -1137,7 +1363,7 @@ static PyObject *PySSL_cipher (PySSLObje |
|
goto fail0; |
|
PyTuple_SET_ITEM(retval, 0, v); |
|
} |
|
- cipher_protocol = SSL_CIPHER_get_version(current); |
|
+ cipher_protocol = (char *) SSL_CIPHER_get_version(current); |
|
if (cipher_protocol == NULL) { |
|
Py_INCREF(Py_None); |
|
PyTuple_SET_ITEM(retval, 1, Py_None); |
|
@@ -1158,15 +1384,85 @@ static PyObject *PySSL_cipher (PySSLObje |
|
return NULL; |
|
} |
|
|
|
-static void PySSL_dealloc(PySSLObject *self) |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { |
|
+ const unsigned char *out; |
|
+ unsigned int outlen; |
|
+ |
|
+ SSL_get0_next_proto_negotiated(self->ssl, |
|
+ &out, &outlen); |
|
+ |
|
+ if (out == NULL) |
|
+ Py_RETURN_NONE; |
|
+ return PyUnicode_FromStringAndSize((char *) out, outlen); |
|
+} |
|
+#endif |
|
+ |
|
+static PyObject *PySSL_compression(PySSLSocket *self) { |
|
+#ifdef OPENSSL_NO_COMP |
|
+ Py_RETURN_NONE; |
|
+#else |
|
+ const COMP_METHOD *comp_method; |
|
+ const char *short_name; |
|
+ |
|
+ if (self->ssl == NULL) |
|
+ Py_RETURN_NONE; |
|
+ comp_method = SSL_get_current_compression(self->ssl); |
|
+ if (comp_method == NULL || comp_method->type == NID_undef) |
|
+ Py_RETURN_NONE; |
|
+ short_name = OBJ_nid2sn(comp_method->type); |
|
+ if (short_name == NULL) |
|
+ Py_RETURN_NONE; |
|
+ return PyBytes_FromString(short_name); |
|
+#endif |
|
+} |
|
+ |
|
+static PySSLContext *PySSL_get_context(PySSLSocket *self, void *closure) { |
|
+ Py_INCREF(self->ctx); |
|
+ return self->ctx; |
|
+} |
|
+ |
|
+static int PySSL_set_context(PySSLSocket *self, PyObject *value, |
|
+ void *closure) { |
|
+ |
|
+ if (PyObject_TypeCheck(value, &PySSLContext_Type)) { |
|
+#if !HAVE_SNI |
|
+ PyErr_SetString(PyExc_NotImplementedError, "setting a socket's " |
|
+ "context is not supported by your OpenSSL library"); |
|
+ return -1; |
|
+#else |
|
+ Py_INCREF(value); |
|
+ Py_DECREF(self->ctx); |
|
+ self->ctx = (PySSLContext *) value; |
|
+ SSL_set_SSL_CTX(self->ssl, self->ctx->ctx); |
|
+#endif |
|
+ } else { |
|
+ PyErr_SetString(PyExc_TypeError, "The value must be a SSLContext"); |
|
+ return -1; |
|
+ } |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_set_context_doc, |
|
+"_setter_context(ctx)\n\ |
|
+\ |
|
+This changes the context associated with the SSLSocket. This is typically\n\ |
|
+used from within a callback function set by the set_servername_callback\n\ |
|
+on the SSLContext to change the certificate information associated with the\n\ |
|
+SSLSocket before the cryptographic exchange handshake messages\n"); |
|
+ |
|
+ |
|
+ |
|
+static void PySSL_dealloc(PySSLSocket *self) |
|
{ |
|
if (self->peer_cert) /* Possible not to have one? */ |
|
X509_free (self->peer_cert); |
|
if (self->ssl) |
|
SSL_free(self->ssl); |
|
- if (self->ctx) |
|
- SSL_CTX_free(self->ctx); |
|
Py_XDECREF(self->Socket); |
|
+ Py_XDECREF(self->ssl_sock); |
|
+ Py_XDECREF(self->ctx); |
|
PyObject_Del(self); |
|
} |
|
|
|
@@ -1238,16 +1534,21 @@ normal_return: |
|
return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; |
|
} |
|
|
|
-static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) |
|
+static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args) |
|
{ |
|
Py_buffer buf; |
|
int len; |
|
int sockstate; |
|
int err; |
|
int nonblocking; |
|
+ PySocketSockObject *sock = self->Socket; |
|
+ |
|
+ Py_INCREF(sock); |
|
|
|
- if (!PyArg_ParseTuple(args, "s*:write", &buf)) |
|
+ if (!PyArg_ParseTuple(args, "s*:write", &buf)) { |
|
+ Py_DECREF(sock); |
|
return NULL; |
|
+ } |
|
|
|
if (buf.len > INT_MAX) { |
|
PyErr_Format(PyExc_OverflowError, |
|
@@ -1256,11 +1557,11 @@ static PyObject *PySSL_SSLwrite(PySSLObj |
|
} |
|
|
|
/* just in case the blocking state of the socket has been changed */ |
|
- nonblocking = (self->Socket->sock_timeout >= 0.0); |
|
+ nonblocking = (sock->sock_timeout >= 0.0); |
|
BIO_set_nbio(SSL_get_rbio(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(sock, 1); |
|
if (sockstate == SOCKET_HAS_TIMED_OUT) { |
|
PyErr_SetString(PySSLErrorObject, |
|
"The write operation timed out"); |
|
@@ -1283,9 +1584,9 @@ static PyObject *PySSL_SSLwrite(PySSLObj |
|
goto error; |
|
} |
|
if (err == SSL_ERROR_WANT_READ) { |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 0); |
|
} else if (err == SSL_ERROR_WANT_WRITE) { |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 1); |
|
} else { |
|
sockstate = SOCKET_OPERATION_OK; |
|
} |
|
@@ -1302,6 +1603,7 @@ static PyObject *PySSL_SSLwrite(PySSLObj |
|
} |
|
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); |
|
|
|
+ Py_DECREF(sock); |
|
PyBuffer_Release(&buf); |
|
if (len > 0) |
|
return PyInt_FromLong(len); |
|
@@ -1309,6 +1611,7 @@ static PyObject *PySSL_SSLwrite(PySSLObj |
|
return PySSL_SetError(self, len, __FILE__, __LINE__); |
|
|
|
error: |
|
+ Py_DECREF(sock); |
|
PyBuffer_Release(&buf); |
|
return NULL; |
|
} |
|
@@ -1319,7 +1622,7 @@ PyDoc_STRVAR(PySSL_SSLwrite_doc, |
|
Writes the string s into the SSL object. Returns the number\n\ |
|
of bytes written."); |
|
|
|
-static PyObject *PySSL_SSLpending(PySSLObject *self) |
|
+static PyObject *PySSL_SSLpending(PySSLSocket *self) |
|
{ |
|
int count = 0; |
|
|
|
@@ -1338,23 +1641,46 @@ PyDoc_STRVAR(PySSL_SSLpending_doc, |
|
Returns the number of already decrypted bytes available for read,\n\ |
|
pending on the connection.\n"); |
|
|
|
-static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) |
|
+static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args) |
|
{ |
|
- PyObject *buf; |
|
- int count = 0; |
|
- int len = 1024; |
|
+ PyObject *dest = NULL; |
|
+ Py_buffer buf; |
|
+ char *mem; |
|
+ int len, count; |
|
+ int buf_passed = 0; |
|
int sockstate; |
|
int err; |
|
int nonblocking; |
|
+ PySocketSockObject *sock = self->Socket; |
|
|
|
- if (!PyArg_ParseTuple(args, "|i:read", &len)) |
|
- return NULL; |
|
+ Py_INCREF(sock); |
|
|
|
- if (!(buf = PyString_FromStringAndSize((char *) 0, len))) |
|
- return NULL; |
|
+ buf.obj = NULL; |
|
+ buf.buf = NULL; |
|
+ if (!PyArg_ParseTuple(args, "i|w*:read", &len, &buf)) |
|
+ goto error; |
|
+ |
|
+ if ((buf.buf == NULL) && (buf.obj == NULL)) { |
|
+ dest = PyBytes_FromStringAndSize(NULL, len); |
|
+ if (dest == NULL) |
|
+ goto error; |
|
+ mem = PyBytes_AS_STRING(dest); |
|
+ } |
|
+ else { |
|
+ buf_passed = 1; |
|
+ mem = buf.buf; |
|
+ if (len <= 0 || len > buf.len) { |
|
+ len = (int) buf.len; |
|
+ if (buf.len != len) { |
|
+ PyErr_SetString(PyExc_OverflowError, |
|
+ "maximum length can't fit in a C 'int'"); |
|
+ goto error; |
|
+ } |
|
+ } |
|
+ } |
|
|
|
/* just in case the blocking state of the socket has been changed */ |
|
- nonblocking = (self->Socket->sock_timeout >= 0.0); |
|
+ nonblocking = (sock->sock_timeout >= 0.0); |
|
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); |
|
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); |
|
|
|
@@ -1364,70 +1690,71 @@ static PyObject *PySSL_SSLread(PySSLObje |
|
PySSL_END_ALLOW_THREADS |
|
|
|
if (!count) { |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 0); |
|
if (sockstate == SOCKET_HAS_TIMED_OUT) { |
|
PyErr_SetString(PySSLErrorObject, |
|
"The read operation timed out"); |
|
- Py_DECREF(buf); |
|
- return NULL; |
|
+ goto error; |
|
} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { |
|
PyErr_SetString(PySSLErrorObject, |
|
"Underlying socket too large for select()."); |
|
- Py_DECREF(buf); |
|
- return NULL; |
|
+ goto error; |
|
} 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; |
|
- } |
|
+ count = 0; |
|
+ goto done; |
|
} |
|
} |
|
do { |
|
PySSL_BEGIN_ALLOW_THREADS |
|
- count = SSL_read(self->ssl, PyString_AsString(buf), len); |
|
+ count = SSL_read(self->ssl, mem, len); |
|
err = SSL_get_error(self->ssl, count); |
|
PySSL_END_ALLOW_THREADS |
|
- if(PyErr_CheckSignals()) { |
|
- Py_DECREF(buf); |
|
- return NULL; |
|
- } |
|
+ if (PyErr_CheckSignals()) |
|
+ goto error; |
|
if (err == SSL_ERROR_WANT_READ) { |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 0); |
|
} else if (err == SSL_ERROR_WANT_WRITE) { |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 1); |
|
} else if ((err == SSL_ERROR_ZERO_RETURN) && |
|
(SSL_get_shutdown(self->ssl) == |
|
SSL_RECEIVED_SHUTDOWN)) |
|
{ |
|
- _PyString_Resize(&buf, 0); |
|
- return buf; |
|
+ count = 0; |
|
+ goto done; |
|
} else { |
|
sockstate = SOCKET_OPERATION_OK; |
|
} |
|
if (sockstate == SOCKET_HAS_TIMED_OUT) { |
|
PyErr_SetString(PySSLErrorObject, |
|
"The read operation timed out"); |
|
- Py_DECREF(buf); |
|
- return NULL; |
|
+ goto error; |
|
} else if (sockstate == SOCKET_IS_NONBLOCKING) { |
|
break; |
|
} |
|
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); |
|
if (count <= 0) { |
|
- Py_DECREF(buf); |
|
- return PySSL_SetError(self, count, __FILE__, __LINE__); |
|
+ PySSL_SetError(self, count, __FILE__, __LINE__); |
|
+ goto error; |
|
+ } |
|
+ |
|
+done: |
|
+ Py_DECREF(sock); |
|
+ if (!buf_passed) { |
|
+ _PyBytes_Resize(&dest, count); |
|
+ return dest; |
|
} |
|
- if (count != len) |
|
- _PyString_Resize(&buf, count); |
|
- return buf; |
|
+ else { |
|
+ PyBuffer_Release(&buf); |
|
+ return PyLong_FromLong(count); |
|
+ } |
|
+ |
|
+error: |
|
+ Py_DECREF(sock); |
|
+ if (!buf_passed) |
|
+ Py_XDECREF(dest); |
|
+ else |
|
+ PyBuffer_Release(&buf); |
|
+ return NULL; |
|
} |
|
|
|
PyDoc_STRVAR(PySSL_SSLread_doc, |
|
@@ -1435,20 +1762,22 @@ PyDoc_STRVAR(PySSL_SSLread_doc, |
|
\n\ |
|
Read up to len bytes from the SSL socket."); |
|
|
|
-static PyObject *PySSL_SSLshutdown(PySSLObject *self) |
|
+static PyObject *PySSL_SSLshutdown(PySSLSocket *self) |
|
{ |
|
int err, ssl_err, sockstate, nonblocking; |
|
int zeros = 0; |
|
+ PySocketSockObject *sock = self->Socket; |
|
|
|
/* Guard against closed socket */ |
|
- if (self->Socket->sock_fd < 0) { |
|
- PyErr_SetString(PySSLErrorObject, |
|
- "Underlying socket has been closed."); |
|
+ if (sock->sock_fd < 0) { |
|
+ _setSSLError("Underlying socket connection gone", |
|
+ PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); |
|
return NULL; |
|
} |
|
+ Py_INCREF(sock); |
|
|
|
/* Just in case the blocking state of the socket has been changed */ |
|
- nonblocking = (self->Socket->sock_timeout >= 0.0); |
|
+ nonblocking = (sock->sock_timeout >= 0.0); |
|
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); |
|
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); |
|
|
|
@@ -1483,9 +1812,9 @@ static PyObject *PySSL_SSLshutdown(PySSL |
|
/* Possibly retry shutdown until timeout or failure */ |
|
ssl_err = SSL_get_error(self->ssl, err); |
|
if (ssl_err == SSL_ERROR_WANT_READ) |
|
- sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); |
|
+ sockstate = check_socket_and_wait_for_timeout(sock, 0); |
|
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(sock, 1); |
|
else |
|
break; |
|
if (sockstate == SOCKET_HAS_TIMED_OUT) { |
|
@@ -1495,24 +1824,29 @@ static PyObject *PySSL_SSLshutdown(PySSL |
|
else |
|
PyErr_SetString(PySSLErrorObject, |
|
"The write operation timed out"); |
|
- return NULL; |
|
+ goto error; |
|
} |
|
else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { |
|
PyErr_SetString(PySSLErrorObject, |
|
"Underlying socket too large for select()."); |
|
- return NULL; |
|
+ goto error; |
|
} |
|
else if (sockstate != SOCKET_OPERATION_OK) |
|
/* Retain the SSL error code */ |
|
break; |
|
} |
|
|
|
- if (err < 0) |
|
+ if (err < 0) { |
|
+ Py_DECREF(sock); |
|
return PySSL_SetError(self, err, __FILE__, __LINE__); |
|
- else { |
|
- Py_INCREF(self->Socket); |
|
- return (PyObject *) (self->Socket); |
|
} |
|
+ else |
|
+ /* It's already INCREF'ed */ |
|
+ return (PyObject *) sock; |
|
+ |
|
+error: |
|
+ Py_DECREF(sock); |
|
+ return NULL; |
|
} |
|
|
|
PyDoc_STRVAR(PySSL_SSLshutdown_doc, |
|
@@ -1521,6 +1855,47 @@ PyDoc_STRVAR(PySSL_SSLshutdown_doc, |
|
Does the SSL shutdown handshake with the remote end, and returns\n\ |
|
the underlying socket object."); |
|
|
|
+#if HAVE_OPENSSL_FINISHED |
|
+static PyObject * |
|
+PySSL_tls_unique_cb(PySSLSocket *self) |
|
+{ |
|
+ PyObject *retval = NULL; |
|
+ char buf[PySSL_CB_MAXLEN]; |
|
+ size_t len; |
|
+ |
|
+ if (SSL_session_reused(self->ssl) ^ !self->socket_type) { |
|
+ /* if session is resumed XOR we are the client */ |
|
+ len = SSL_get_finished(self->ssl, buf, PySSL_CB_MAXLEN); |
|
+ } |
|
+ else { |
|
+ /* if a new session XOR we are the server */ |
|
+ len = SSL_get_peer_finished(self->ssl, buf, PySSL_CB_MAXLEN); |
|
+ } |
|
+ |
|
+ /* It cannot be negative in current OpenSSL version as of July 2011 */ |
|
+ if (len == 0) |
|
+ Py_RETURN_NONE; |
|
+ |
|
+ retval = PyBytes_FromStringAndSize(buf, len); |
|
+ |
|
+ return retval; |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_tls_unique_cb_doc, |
|
+"tls_unique_cb() -> bytes\n\ |
|
+\n\ |
|
+Returns the 'tls-unique' channel binding data, as defined by RFC 5929.\n\ |
|
+\n\ |
|
+If the TLS handshake is not yet complete, None is returned"); |
|
+ |
|
+#endif /* HAVE_OPENSSL_FINISHED */ |
|
+ |
|
+static PyGetSetDef ssl_getsetlist[] = { |
|
+ {"context", (getter) PySSL_get_context, |
|
+ (setter) PySSL_set_context, PySSL_set_context_doc}, |
|
+ {NULL}, /* sentinel */ |
|
+}; |
|
+ |
|
static PyMethodDef PySSLMethods[] = { |
|
{"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS}, |
|
{"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, |
|
@@ -1529,118 +1904,1786 @@ static PyMethodDef PySSLMethods[] = { |
|
PySSL_SSLread_doc}, |
|
{"pending", (PyCFunction)PySSL_SSLpending, METH_NOARGS, |
|
PySSL_SSLpending_doc}, |
|
- {"server", (PyCFunction)PySSL_server, METH_NOARGS}, |
|
- {"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS}, |
|
{"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, |
|
PySSL_peercert_doc}, |
|
{"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+ {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, |
|
+#endif |
|
+ {"compression", (PyCFunction)PySSL_compression, METH_NOARGS}, |
|
{"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, |
|
PySSL_SSLshutdown_doc}, |
|
+#if HAVE_OPENSSL_FINISHED |
|
+ {"tls_unique_cb", (PyCFunction)PySSL_tls_unique_cb, METH_NOARGS, |
|
+ PySSL_tls_unique_cb_doc}, |
|
+#endif |
|
{NULL, NULL} |
|
}; |
|
|
|
-static PyObject *PySSL_getattr(PySSLObject *self, char *name) |
|
-{ |
|
- return Py_FindMethod(PySSLMethods, (PyObject *)self, name); |
|
-} |
|
- |
|
-static PyTypeObject PySSL_Type = { |
|
+static PyTypeObject PySSLSocket_Type = { |
|
PyVarObject_HEAD_INIT(NULL, 0) |
|
- "ssl.SSLContext", /*tp_name*/ |
|
- sizeof(PySSLObject), /*tp_basicsize*/ |
|
+ "_ssl._SSLSocket", /*tp_name*/ |
|
+ sizeof(PySSLSocket), /*tp_basicsize*/ |
|
0, /*tp_itemsize*/ |
|
/* methods */ |
|
(destructor)PySSL_dealloc, /*tp_dealloc*/ |
|
0, /*tp_print*/ |
|
- (getattrfunc)PySSL_getattr, /*tp_getattr*/ |
|
+ 0, /*tp_getattr*/ |
|
0, /*tp_setattr*/ |
|
- 0, /*tp_compare*/ |
|
+ 0, /*tp_reserved*/ |
|
0, /*tp_repr*/ |
|
0, /*tp_as_number*/ |
|
0, /*tp_as_sequence*/ |
|
0, /*tp_as_mapping*/ |
|
0, /*tp_hash*/ |
|
+ 0, /*tp_call*/ |
|
+ 0, /*tp_str*/ |
|
+ 0, /*tp_getattro*/ |
|
+ 0, /*tp_setattro*/ |
|
+ 0, /*tp_as_buffer*/ |
|
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
|
+ 0, /*tp_doc*/ |
|
+ 0, /*tp_traverse*/ |
|
+ 0, /*tp_clear*/ |
|
+ 0, /*tp_richcompare*/ |
|
+ 0, /*tp_weaklistoffset*/ |
|
+ 0, /*tp_iter*/ |
|
+ 0, /*tp_iternext*/ |
|
+ PySSLMethods, /*tp_methods*/ |
|
+ 0, /*tp_members*/ |
|
+ ssl_getsetlist, /*tp_getset*/ |
|
}; |
|
|
|
-#ifdef HAVE_OPENSSL_RAND |
|
|
|
-/* helper routines for seeding the SSL PRNG */ |
|
+/* |
|
+ * _SSLContext objects |
|
+ */ |
|
+ |
|
static PyObject * |
|
-PySSL_RAND_add(PyObject *self, PyObject *args) |
|
+context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
|
{ |
|
- char *buf; |
|
- int len; |
|
- double entropy; |
|
+ char *kwlist[] = {"protocol", NULL}; |
|
+ PySSLContext *self; |
|
+ int proto_version = PY_SSL_VERSION_SSL23; |
|
+ long options; |
|
+ SSL_CTX *ctx = NULL; |
|
+ |
|
+ if (!PyArg_ParseTupleAndKeywords( |
|
+ args, kwds, "i:_SSLContext", kwlist, |
|
+ &proto_version)) |
|
+ return NULL; |
|
|
|
- if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) |
|
+ PySSL_BEGIN_ALLOW_THREADS |
|
+ if (proto_version == PY_SSL_VERSION_TLS1) |
|
+ ctx = SSL_CTX_new(TLSv1_method()); |
|
+#if HAVE_TLSv1_2 |
|
+ else if (proto_version == PY_SSL_VERSION_TLS1_1) |
|
+ ctx = SSL_CTX_new(TLSv1_1_method()); |
|
+ else if (proto_version == PY_SSL_VERSION_TLS1_2) |
|
+ ctx = SSL_CTX_new(TLSv1_2_method()); |
|
+#endif |
|
+ else if (proto_version == PY_SSL_VERSION_SSL3) |
|
+ ctx = SSL_CTX_new(SSLv3_method()); |
|
+#ifndef OPENSSL_NO_SSL2 |
|
+ else if (proto_version == PY_SSL_VERSION_SSL2) |
|
+ ctx = SSL_CTX_new(SSLv2_method()); |
|
+#endif |
|
+ else if (proto_version == PY_SSL_VERSION_SSL23) |
|
+ ctx = SSL_CTX_new(SSLv23_method()); |
|
+ else |
|
+ proto_version = -1; |
|
+ PySSL_END_ALLOW_THREADS |
|
+ |
|
+ if (proto_version == -1) { |
|
+ PyErr_SetString(PyExc_ValueError, |
|
+ "invalid protocol version"); |
|
return NULL; |
|
- RAND_add(buf, len, entropy); |
|
- Py_INCREF(Py_None); |
|
- return Py_None; |
|
+ } |
|
+ if (ctx == NULL) { |
|
+ PyErr_SetString(PySSLErrorObject, |
|
+ "failed to allocate SSL context"); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ assert(type != NULL && type->tp_alloc != NULL); |
|
+ self = (PySSLContext *) type->tp_alloc(type, 0); |
|
+ if (self == NULL) { |
|
+ SSL_CTX_free(ctx); |
|
+ return NULL; |
|
+ } |
|
+ self->ctx = ctx; |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+ self->npn_protocols = NULL; |
|
+#endif |
|
+#ifndef OPENSSL_NO_TLSEXT |
|
+ self->set_hostname = NULL; |
|
+#endif |
|
+ /* Don't check host name by default */ |
|
+ self->check_hostname = 0; |
|
+ /* Defaults */ |
|
+ SSL_CTX_set_verify(self->ctx, SSL_VERIFY_NONE, NULL); |
|
+ options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; |
|
+ SSL_CTX_set_options(self->ctx, options); |
|
+ |
|
+#ifndef OPENSSL_NO_ECDH |
|
+ /* Allow automatic ECDH curve selection (on OpenSSL 1.0.2+), or use |
|
+ prime256v1 by default. This is Apache mod_ssl's initialization |
|
+ policy, so we should be safe. */ |
|
+#if defined(SSL_CTX_set_ecdh_auto) |
|
+ SSL_CTX_set_ecdh_auto(self->ctx, 1); |
|
+#else |
|
+ { |
|
+ EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); |
|
+ SSL_CTX_set_tmp_ecdh(self->ctx, key); |
|
+ EC_KEY_free(key); |
|
+ } |
|
+#endif |
|
+#endif |
|
+ |
|
+#define SID_CTX "Python" |
|
+ SSL_CTX_set_session_id_context(self->ctx, (const unsigned char *) SID_CTX, |
|
+ sizeof(SID_CTX)); |
|
+#undef SID_CTX |
|
+ |
|
+ return (PyObject *)self; |
|
} |
|
|
|
-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. See RFC 1750."); |
|
+static int |
|
+context_traverse(PySSLContext *self, visitproc visit, void *arg) |
|
+{ |
|
+#ifndef OPENSSL_NO_TLSEXT |
|
+ Py_VISIT(self->set_hostname); |
|
+#endif |
|
+ return 0; |
|
+} |
|
|
|
-static PyObject * |
|
-PySSL_RAND_status(PyObject *self) |
|
+static int |
|
+context_clear(PySSLContext *self) |
|
{ |
|
- return PyInt_FromLong(RAND_status()); |
|
+#ifndef OPENSSL_NO_TLSEXT |
|
+ Py_CLEAR(self->set_hostname); |
|
+#endif |
|
+ return 0; |
|
} |
|
|
|
-PyDoc_STRVAR(PySSL_RAND_status_doc, |
|
-"RAND_status() -> 0 or 1\n\ |
|
-\n\ |
|
-Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\ |
|
-It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ |
|
-using the ssl() function."); |
|
+static void |
|
+context_dealloc(PySSLContext *self) |
|
+{ |
|
+ context_clear(self); |
|
+ SSL_CTX_free(self->ctx); |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+ PyMem_Free(self->npn_protocols); |
|
+#endif |
|
+ Py_TYPE(self)->tp_free(self); |
|
+} |
|
|
|
static PyObject * |
|
-PySSL_RAND_egd(PyObject *self, PyObject *arg) |
|
+set_ciphers(PySSLContext *self, PyObject *args) |
|
{ |
|
- int bytes; |
|
+ int ret; |
|
+ const char *cipherlist; |
|
|
|
- if (!PyString_Check(arg)) |
|
- return PyErr_Format(PyExc_TypeError, |
|
- "RAND_egd() expected string, found %s", |
|
- Py_TYPE(arg)->tp_name); |
|
- bytes = RAND_egd(PyString_AS_STRING(arg)); |
|
- if (bytes == -1) { |
|
+ if (!PyArg_ParseTuple(args, "s:set_ciphers", &cipherlist)) |
|
+ return NULL; |
|
+ ret = SSL_CTX_set_cipher_list(self->ctx, cipherlist); |
|
+ if (ret == 0) { |
|
+ /* Clearing the error queue is necessary on some OpenSSL versions, |
|
+ otherwise the error will be reported again when another SSL call |
|
+ is done. */ |
|
+ ERR_clear_error(); |
|
PyErr_SetString(PySSLErrorObject, |
|
- "EGD connection failed or EGD did not return " |
|
- "enough data to seed the PRNG"); |
|
+ "No cipher can be selected."); |
|
return NULL; |
|
} |
|
- return PyInt_FromLong(bytes); |
|
+ Py_RETURN_NONE; |
|
} |
|
|
|
-PyDoc_STRVAR(PySSL_RAND_egd_doc, |
|
-"RAND_egd(path) -> bytes\n\ |
|
-\n\ |
|
-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 not provide enough data to seed PRNG."); |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+/* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */ |
|
+static int |
|
+_advertiseNPN_cb(SSL *s, |
|
+ const unsigned char **data, unsigned int *len, |
|
+ void *args) |
|
+{ |
|
+ PySSLContext *ssl_ctx = (PySSLContext *) args; |
|
|
|
-#endif /* HAVE_OPENSSL_RAND */ |
|
+ if (ssl_ctx->npn_protocols == NULL) { |
|
+ *data = (unsigned char *) ""; |
|
+ *len = 0; |
|
+ } else { |
|
+ *data = (unsigned char *) ssl_ctx->npn_protocols; |
|
+ *len = ssl_ctx->npn_protocols_len; |
|
+ } |
|
|
|
-/* List of functions exported by this module. */ |
|
+ return SSL_TLSEXT_ERR_OK; |
|
+} |
|
+/* this callback gets passed to SSL_CTX_set_next_proto_select_cb */ |
|
+static int |
|
+_selectNPN_cb(SSL *s, |
|
+ unsigned char **out, unsigned char *outlen, |
|
+ const unsigned char *server, unsigned int server_len, |
|
+ void *args) |
|
+{ |
|
+ PySSLContext *ssl_ctx = (PySSLContext *) args; |
|
+ |
|
+ unsigned char *client = (unsigned char *) ssl_ctx->npn_protocols; |
|
+ int client_len; |
|
+ |
|
+ if (client == NULL) { |
|
+ client = (unsigned char *) ""; |
|
+ client_len = 0; |
|
+ } else { |
|
+ client_len = ssl_ctx->npn_protocols_len; |
|
+ } |
|
+ |
|
+ SSL_select_next_proto(out, outlen, |
|
+ server, server_len, |
|
+ client, client_len); |
|
+ |
|
+ return SSL_TLSEXT_ERR_OK; |
|
+} |
|
+#endif |
|
+ |
|
+static PyObject * |
|
+_set_npn_protocols(PySSLContext *self, PyObject *args) |
|
+{ |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+ Py_buffer protos; |
|
+ |
|
+ if (!PyArg_ParseTuple(args, "s*:set_npn_protocols", &protos)) |
|
+ return NULL; |
|
+ |
|
+ if (self->npn_protocols != NULL) { |
|
+ PyMem_Free(self->npn_protocols); |
|
+ } |
|
+ |
|
+ self->npn_protocols = PyMem_Malloc(protos.len); |
|
+ if (self->npn_protocols == NULL) { |
|
+ PyBuffer_Release(&protos); |
|
+ return PyErr_NoMemory(); |
|
+ } |
|
+ memcpy(self->npn_protocols, protos.buf, protos.len); |
|
+ self->npn_protocols_len = (int) protos.len; |
|
+ |
|
+ /* set both server and client callbacks, because the context can |
|
+ * be used to create both types of sockets */ |
|
+ SSL_CTX_set_next_protos_advertised_cb(self->ctx, |
|
+ _advertiseNPN_cb, |
|
+ self); |
|
+ SSL_CTX_set_next_proto_select_cb(self->ctx, |
|
+ _selectNPN_cb, |
|
+ self); |
|
+ |
|
+ PyBuffer_Release(&protos); |
|
+ Py_RETURN_NONE; |
|
+#else |
|
+ PyErr_SetString(PyExc_NotImplementedError, |
|
+ "The NPN extension requires OpenSSL 1.0.1 or later."); |
|
+ return NULL; |
|
+#endif |
|
+} |
|
+ |
|
+static PyObject * |
|
+get_verify_mode(PySSLContext *self, void *c) |
|
+{ |
|
+ switch (SSL_CTX_get_verify_mode(self->ctx)) { |
|
+ case SSL_VERIFY_NONE: |
|
+ return PyLong_FromLong(PY_SSL_CERT_NONE); |
|
+ case SSL_VERIFY_PEER: |
|
+ return PyLong_FromLong(PY_SSL_CERT_OPTIONAL); |
|
+ case SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT: |
|
+ return PyLong_FromLong(PY_SSL_CERT_REQUIRED); |
|
+ } |
|
+ PyErr_SetString(PySSLErrorObject, |
|
+ "invalid return value from SSL_CTX_get_verify_mode"); |
|
+ return NULL; |
|
+} |
|
+ |
|
+static int |
|
+set_verify_mode(PySSLContext *self, PyObject *arg, void *c) |
|
+{ |
|
+ int n, mode; |
|
+ if (!PyArg_Parse(arg, "i", &n)) |
|
+ return -1; |
|
+ if (n == PY_SSL_CERT_NONE) |
|
+ mode = SSL_VERIFY_NONE; |
|
+ else if (n == PY_SSL_CERT_OPTIONAL) |
|
+ mode = SSL_VERIFY_PEER; |
|
+ else if (n == PY_SSL_CERT_REQUIRED) |
|
+ mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
|
+ else { |
|
+ PyErr_SetString(PyExc_ValueError, |
|
+ "invalid value for verify_mode"); |
|
+ return -1; |
|
+ } |
|
+ if (mode == SSL_VERIFY_NONE && self->check_hostname) { |
|
+ PyErr_SetString(PyExc_ValueError, |
|
+ "Cannot set verify_mode to CERT_NONE when " |
|
+ "check_hostname is enabled."); |
|
+ return -1; |
|
+ } |
|
+ SSL_CTX_set_verify(self->ctx, mode, NULL); |
|
+ return 0; |
|
+} |
|
+ |
|
+#ifdef HAVE_OPENSSL_VERIFY_PARAM |
|
+static PyObject * |
|
+get_verify_flags(PySSLContext *self, void *c) |
|
+{ |
|
+ X509_STORE *store; |
|
+ unsigned long flags; |
|
+ |
|
+ store = SSL_CTX_get_cert_store(self->ctx); |
|
+ flags = X509_VERIFY_PARAM_get_flags(store->param); |
|
+ return PyLong_FromUnsignedLong(flags); |
|
+} |
|
+ |
|
+static int |
|
+set_verify_flags(PySSLContext *self, PyObject *arg, void *c) |
|
+{ |
|
+ X509_STORE *store; |
|
+ unsigned long new_flags, flags, set, clear; |
|
+ |
|
+ if (!PyArg_Parse(arg, "k", &new_flags)) |
|
+ return -1; |
|
+ store = SSL_CTX_get_cert_store(self->ctx); |
|
+ flags = X509_VERIFY_PARAM_get_flags(store->param); |
|
+ clear = flags & ~new_flags; |
|
+ set = ~flags & new_flags; |
|
+ if (clear) { |
|
+ if (!X509_VERIFY_PARAM_clear_flags(store->param, clear)) { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ return -1; |
|
+ } |
|
+ } |
|
+ if (set) { |
|
+ if (!X509_VERIFY_PARAM_set_flags(store->param, set)) { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ return -1; |
|
+ } |
|
+ } |
|
+ return 0; |
|
+} |
|
+#endif |
|
+ |
|
+static PyObject * |
|
+get_options(PySSLContext *self, void *c) |
|
+{ |
|
+ return PyLong_FromLong(SSL_CTX_get_options(self->ctx)); |
|
+} |
|
+ |
|
+static int |
|
+set_options(PySSLContext *self, PyObject *arg, void *c) |
|
+{ |
|
+ long new_opts, opts, set, clear; |
|
+ if (!PyArg_Parse(arg, "l", &new_opts)) |
|
+ return -1; |
|
+ opts = SSL_CTX_get_options(self->ctx); |
|
+ clear = opts & ~new_opts; |
|
+ set = ~opts & new_opts; |
|
+ if (clear) { |
|
+#ifdef HAVE_SSL_CTX_CLEAR_OPTIONS |
|
+ SSL_CTX_clear_options(self->ctx, clear); |
|
+#else |
|
+ PyErr_SetString(PyExc_ValueError, |
|
+ "can't clear options before OpenSSL 0.9.8m"); |
|
+ return -1; |
|
+#endif |
|
+ } |
|
+ if (set) |
|
+ SSL_CTX_set_options(self->ctx, set); |
|
+ return 0; |
|
+} |
|
+ |
|
+static PyObject * |
|
+get_check_hostname(PySSLContext *self, void *c) |
|
+{ |
|
+ return PyBool_FromLong(self->check_hostname); |
|
+} |
|
+ |
|
+static int |
|
+set_check_hostname(PySSLContext *self, PyObject *arg, void *c) |
|
+{ |
|
+ PyObject *py_check_hostname; |
|
+ int check_hostname; |
|
+ if (!PyArg_Parse(arg, "O", &py_check_hostname)) |
|
+ return -1; |
|
+ |
|
+ check_hostname = PyObject_IsTrue(py_check_hostname); |
|
+ if (check_hostname < 0) |
|
+ return -1; |
|
+ if (check_hostname && |
|
+ SSL_CTX_get_verify_mode(self->ctx) == SSL_VERIFY_NONE) { |
|
+ PyErr_SetString(PyExc_ValueError, |
|
+ "check_hostname needs a SSL context with either " |
|
+ "CERT_OPTIONAL or CERT_REQUIRED"); |
|
+ return -1; |
|
+ } |
|
+ self->check_hostname = check_hostname; |
|
+ return 0; |
|
+} |
|
+ |
|
+ |
|
+typedef struct { |
|
+ PyThreadState *thread_state; |
|
+ PyObject *callable; |
|
+ char *password; |
|
+ int size; |
|
+ int error; |
|
+} _PySSLPasswordInfo; |
|
+ |
|
+static int |
|
+_pwinfo_set(_PySSLPasswordInfo *pw_info, PyObject* password, |
|
+ const char *bad_type_error) |
|
+{ |
|
+ /* Set the password and size fields of a _PySSLPasswordInfo struct |
|
+ from a unicode, bytes, or byte array object. |
|
+ The password field will be dynamically allocated and must be freed |
|
+ by the caller */ |
|
+ PyObject *password_bytes = NULL; |
|
+ const char *data = NULL; |
|
+ Py_ssize_t size; |
|
+ |
|
+ if (PyUnicode_Check(password)) { |
|
+ password_bytes = PyUnicode_AsEncodedString(password, NULL, NULL); |
|
+ if (!password_bytes) { |
|
+ goto error; |
|
+ } |
|
+ data = PyBytes_AS_STRING(password_bytes); |
|
+ size = PyBytes_GET_SIZE(password_bytes); |
|
+ } else if (PyBytes_Check(password)) { |
|
+ data = PyBytes_AS_STRING(password); |
|
+ size = PyBytes_GET_SIZE(password); |
|
+ } else if (PyByteArray_Check(password)) { |
|
+ data = PyByteArray_AS_STRING(password); |
|
+ size = PyByteArray_GET_SIZE(password); |
|
+ } else { |
|
+ PyErr_SetString(PyExc_TypeError, bad_type_error); |
|
+ goto error; |
|
+ } |
|
+ |
|
+ if (size > (Py_ssize_t)INT_MAX) { |
|
+ PyErr_Format(PyExc_ValueError, |
|
+ "password cannot be longer than %d bytes", INT_MAX); |
|
+ goto error; |
|
+ } |
|
+ |
|
+ PyMem_Free(pw_info->password); |
|
+ pw_info->password = PyMem_Malloc(size); |
|
+ if (!pw_info->password) { |
|
+ PyErr_SetString(PyExc_MemoryError, |
|
+ "unable to allocate password buffer"); |
|
+ goto error; |
|
+ } |
|
+ memcpy(pw_info->password, data, size); |
|
+ pw_info->size = (int)size; |
|
+ |
|
+ Py_XDECREF(password_bytes); |
|
+ return 1; |
|
+ |
|
+error: |
|
+ Py_XDECREF(password_bytes); |
|
+ return 0; |
|
+} |
|
+ |
|
+static int |
|
+_password_callback(char *buf, int size, int rwflag, void *userdata) |
|
+{ |
|
+ _PySSLPasswordInfo *pw_info = (_PySSLPasswordInfo*) userdata; |
|
+ PyObject *fn_ret = NULL; |
|
+ |
|
+ PySSL_END_ALLOW_THREADS_S(pw_info->thread_state); |
|
+ |
|
+ if (pw_info->callable) { |
|
+ fn_ret = PyObject_CallFunctionObjArgs(pw_info->callable, NULL); |
|
+ if (!fn_ret) { |
|
+ /* TODO: It would be nice to move _ctypes_add_traceback() into the |
|
+ core python API, so we could use it to add a frame here */ |
|
+ goto error; |
|
+ } |
|
+ |
|
+ if (!_pwinfo_set(pw_info, fn_ret, |
|
+ "password callback must return a string")) { |
|
+ goto error; |
|
+ } |
|
+ Py_CLEAR(fn_ret); |
|
+ } |
|
+ |
|
+ if (pw_info->size > size) { |
|
+ PyErr_Format(PyExc_ValueError, |
|
+ "password cannot be longer than %d bytes", size); |
|
+ goto error; |
|
+ } |
|
+ |
|
+ PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); |
|
+ memcpy(buf, pw_info->password, pw_info->size); |
|
+ return pw_info->size; |
|
+ |
|
+error: |
|
+ Py_XDECREF(fn_ret); |
|
+ PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); |
|
+ pw_info->error = 1; |
|
+ return -1; |
|
+} |
|
+ |
|
+static PyObject * |
|
+load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) |
|
+{ |
|
+ char *kwlist[] = {"certfile", "keyfile", "password", NULL}; |
|
+ PyObject *password = NULL; |
|
+ char *certfile_bytes = NULL, *keyfile_bytes = NULL; |
|
+ pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback; |
|
+ void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata; |
|
+ _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 }; |
|
+ int r; |
|
+ |
|
+ errno = 0; |
|
+ ERR_clear_error(); |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, |
|
+ "et|etO:load_cert_chain", kwlist, |
|
+ Py_FileSystemDefaultEncoding, &certfile_bytes, |
|
+ Py_FileSystemDefaultEncoding, &keyfile_bytes, |
|
+ &password)) |
|
+ return NULL; |
|
+ if (password && password != Py_None) { |
|
+ if (PyCallable_Check(password)) { |
|
+ pw_info.callable = password; |
|
+ } else if (!_pwinfo_set(&pw_info, password, |
|
+ "password should be a string or callable")) { |
|
+ goto error; |
|
+ } |
|
+ SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback); |
|
+ SSL_CTX_set_default_passwd_cb_userdata(self->ctx, &pw_info); |
|
+ } |
|
+ PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); |
|
+ r = SSL_CTX_use_certificate_chain_file(self->ctx, certfile_bytes); |
|
+ PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); |
|
+ if (r != 1) { |
|
+ if (pw_info.error) { |
|
+ ERR_clear_error(); |
|
+ /* the password callback has already set the error information */ |
|
+ } |
|
+ else if (errno != 0) { |
|
+ ERR_clear_error(); |
|
+ PyErr_SetFromErrno(PyExc_IOError); |
|
+ } |
|
+ else { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ } |
|
+ goto error; |
|
+ } |
|
+ PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); |
|
+ r = SSL_CTX_use_PrivateKey_file(self->ctx, |
|
+ keyfile_bytes ? keyfile_bytes : certfile_bytes, |
|
+ SSL_FILETYPE_PEM); |
|
+ PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); |
|
+ if (r != 1) { |
|
+ if (pw_info.error) { |
|
+ ERR_clear_error(); |
|
+ /* the password callback has already set the error information */ |
|
+ } |
|
+ else if (errno != 0) { |
|
+ ERR_clear_error(); |
|
+ PyErr_SetFromErrno(PyExc_IOError); |
|
+ } |
|
+ else { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ } |
|
+ goto error; |
|
+ } |
|
+ PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); |
|
+ r = SSL_CTX_check_private_key(self->ctx); |
|
+ PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); |
|
+ if (r != 1) { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ goto error; |
|
+ } |
|
+ SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); |
|
+ SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); |
|
+ PyMem_Free(pw_info.password); |
|
+ Py_RETURN_NONE; |
|
+ |
|
+error: |
|
+ SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); |
|
+ SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); |
|
+ PyMem_Free(pw_info.password); |
|
+ PyMem_Free(keyfile_bytes); |
|
+ PyMem_Free(certfile_bytes); |
|
+ return NULL; |
|
+} |
|
+ |
|
+/* internal helper function, returns -1 on error |
|
+ */ |
|
+static int |
|
+_add_ca_certs(PySSLContext *self, void *data, Py_ssize_t len, |
|
+ int filetype) |
|
+{ |
|
+ BIO *biobuf = NULL; |
|
+ X509_STORE *store; |
|
+ int retval = 0, err, loaded = 0; |
|
+ |
|
+ assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM); |
|
+ |
|
+ if (len <= 0) { |
|
+ PyErr_SetString(PyExc_ValueError, |
|
+ "Empty certificate data"); |
|
+ return -1; |
|
+ } else if (len > INT_MAX) { |
|
+ PyErr_SetString(PyExc_OverflowError, |
|
+ "Certificate data is too long."); |
|
+ return -1; |
|
+ } |
|
+ |
|
+ biobuf = BIO_new_mem_buf(data, (int)len); |
|
+ if (biobuf == NULL) { |
|
+ _setSSLError("Can't allocate buffer", 0, __FILE__, __LINE__); |
|
+ return -1; |
|
+ } |
|
+ |
|
+ store = SSL_CTX_get_cert_store(self->ctx); |
|
+ assert(store != NULL); |
|
+ |
|
+ while (1) { |
|
+ X509 *cert = NULL; |
|
+ int r; |
|
+ |
|
+ if (filetype == SSL_FILETYPE_ASN1) { |
|
+ cert = d2i_X509_bio(biobuf, NULL); |
|
+ } else { |
|
+ cert = PEM_read_bio_X509(biobuf, NULL, |
|
+ self->ctx->default_passwd_callback, |
|
+ self->ctx->default_passwd_callback_userdata); |
|
+ } |
|
+ if (cert == NULL) { |
|
+ break; |
|
+ } |
|
+ r = X509_STORE_add_cert(store, cert); |
|
+ X509_free(cert); |
|
+ if (!r) { |
|
+ err = ERR_peek_last_error(); |
|
+ if ((ERR_GET_LIB(err) == ERR_LIB_X509) && |
|
+ (ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE)) { |
|
+ /* cert already in hash table, not an error */ |
|
+ ERR_clear_error(); |
|
+ } else { |
|
+ break; |
|
+ } |
|
+ } |
|
+ loaded++; |
|
+ } |
|
+ |
|
+ err = ERR_peek_last_error(); |
|
+ if ((filetype == SSL_FILETYPE_ASN1) && |
|
+ (loaded > 0) && |
|
+ (ERR_GET_LIB(err) == ERR_LIB_ASN1) && |
|
+ (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) { |
|
+ /* EOF ASN1 file, not an error */ |
|
+ ERR_clear_error(); |
|
+ retval = 0; |
|
+ } else if ((filetype == SSL_FILETYPE_PEM) && |
|
+ (loaded > 0) && |
|
+ (ERR_GET_LIB(err) == ERR_LIB_PEM) && |
|
+ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { |
|
+ /* EOF PEM file, not an error */ |
|
+ ERR_clear_error(); |
|
+ retval = 0; |
|
+ } else { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ retval = -1; |
|
+ } |
|
+ |
|
+ BIO_free(biobuf); |
|
+ return retval; |
|
+} |
|
+ |
|
+ |
|
+static PyObject * |
|
+load_verify_locations(PySSLContext *self, PyObject *args, PyObject *kwds) |
|
+{ |
|
+ char *kwlist[] = {"cafile", "capath", "cadata", NULL}; |
|
+ PyObject *cadata = NULL, *cafile = NULL, *capath = NULL; |
|
+ PyObject *cafile_bytes = NULL, *capath_bytes = NULL; |
|
+ const char *cafile_buf = NULL, *capath_buf = NULL; |
|
+ int r = 0, ok = 1; |
|
+ |
|
+ errno = 0; |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, |
|
+ "|OOO:load_verify_locations", kwlist, |
|
+ &cafile, &capath, &cadata)) |
|
+ return NULL; |
|
+ |
|
+ if (cafile == Py_None) |
|
+ cafile = NULL; |
|
+ if (capath == Py_None) |
|
+ capath = NULL; |
|
+ if (cadata == Py_None) |
|
+ cadata = NULL; |
|
+ |
|
+ if (cafile == NULL && capath == NULL && cadata == NULL) { |
|
+ PyErr_SetString(PyExc_TypeError, |
|
+ "cafile, capath and cadata cannot be all omitted"); |
|
+ goto error; |
|
+ } |
|
+ |
|
+ if (cafile) { |
|
+ cafile_bytes = PyString_AsEncodedObject( |
|
+ cafile, Py_FileSystemDefaultEncoding, "strict"); |
|
+ if (!cafile_bytes) { |
|
+ goto error; |
|
+ } |
|
+ } |
|
+ if (capath) { |
|
+ capath_bytes = PyString_AsEncodedObject( |
|
+ capath, Py_FileSystemDefaultEncoding, "strict"); |
|
+ if (!capath_bytes) { |
|
+ goto error; |
|
+ } |
|
+ } |
|
+ |
|
+ /* validata cadata type and load cadata */ |
|
+ if (cadata) { |
|
+ Py_buffer buf; |
|
+ PyObject *cadata_ascii = NULL; |
|
+ |
|
+ if (!PyUnicode_Check(cadata) && PyObject_GetBuffer(cadata, &buf, PyBUF_SIMPLE) == 0) { |
|
+ if (!PyBuffer_IsContiguous(&buf, 'C') || buf.ndim > 1) { |
|
+ PyBuffer_Release(&buf); |
|
+ PyErr_SetString(PyExc_TypeError, |
|
+ "cadata should be a contiguous buffer with " |
|
+ "a single dimension"); |
|
+ goto error; |
|
+ } |
|
+ r = _add_ca_certs(self, buf.buf, buf.len, SSL_FILETYPE_ASN1); |
|
+ PyBuffer_Release(&buf); |
|
+ if (r == -1) { |
|
+ goto error; |
|
+ } |
|
+ } else { |
|
+ PyErr_Clear(); |
|
+ cadata_ascii = PyUnicode_AsASCIIString(cadata); |
|
+ if (cadata_ascii == NULL) { |
|
+ PyErr_SetString(PyExc_TypeError, |
|
+ "cadata should be a ASCII string or a " |
|
+ "bytes-like object"); |
|
+ goto error; |
|
+ } |
|
+ r = _add_ca_certs(self, |
|
+ PyBytes_AS_STRING(cadata_ascii), |
|
+ PyBytes_GET_SIZE(cadata_ascii), |
|
+ SSL_FILETYPE_PEM); |
|
+ Py_DECREF(cadata_ascii); |
|
+ if (r == -1) { |
|
+ goto error; |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ /* load cafile or capath */ |
|
+ if (cafile_bytes || capath_bytes) { |
|
+ if (cafile) |
|
+ cafile_buf = PyBytes_AS_STRING(cafile_bytes); |
|
+ if (capath) |
|
+ capath_buf = PyBytes_AS_STRING(capath_bytes); |
|
+ PySSL_BEGIN_ALLOW_THREADS |
|
+ r = SSL_CTX_load_verify_locations( |
|
+ self->ctx, |
|
+ cafile_buf, |
|
+ capath_buf); |
|
+ PySSL_END_ALLOW_THREADS |
|
+ if (r != 1) { |
|
+ ok = 0; |
|
+ if (errno != 0) { |
|
+ ERR_clear_error(); |
|
+ PyErr_SetFromErrno(PyExc_IOError); |
|
+ } |
|
+ else { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ } |
|
+ goto error; |
|
+ } |
|
+ } |
|
+ goto end; |
|
+ |
|
+ error: |
|
+ ok = 0; |
|
+ end: |
|
+ Py_XDECREF(cafile_bytes); |
|
+ Py_XDECREF(capath_bytes); |
|
+ if (ok) { |
|
+ Py_RETURN_NONE; |
|
+ } else { |
|
+ return NULL; |
|
+ } |
|
+} |
|
+ |
|
+static PyObject * |
|
+load_dh_params(PySSLContext *self, PyObject *filepath) |
|
+{ |
|
+ BIO *bio; |
|
+ DH *dh; |
|
+ char *path = PyBytes_AsString(filepath); |
|
+ if (!path) { |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ bio = BIO_new_file(path, "r"); |
|
+ if (bio == NULL) { |
|
+ ERR_clear_error(); |
|
+ PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filepath); |
|
+ return NULL; |
|
+ } |
|
+ errno = 0; |
|
+ PySSL_BEGIN_ALLOW_THREADS |
|
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); |
|
+ BIO_free(bio); |
|
+ PySSL_END_ALLOW_THREADS |
|
+ if (dh == NULL) { |
|
+ if (errno != 0) { |
|
+ ERR_clear_error(); |
|
+ PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath); |
|
+ } |
|
+ else { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ } |
|
+ return NULL; |
|
+ } |
|
+ if (SSL_CTX_set_tmp_dh(self->ctx, dh) == 0) |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ DH_free(dh); |
|
+ Py_RETURN_NONE; |
|
+} |
|
+ |
|
+static PyObject * |
|
+context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) |
|
+{ |
|
+ char *kwlist[] = {"sock", "server_side", "server_hostname", "ssl_sock", NULL}; |
|
+ PySocketSockObject *sock; |
|
+ int server_side = 0; |
|
+ char *hostname = NULL; |
|
+ PyObject *hostname_obj, *ssl_sock = Py_None, *res; |
|
+ |
|
+ /* server_hostname is either None (or absent), or to be encoded |
|
+ using the idna encoding. */ |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!i|O!O:_wrap_socket", kwlist, |
|
+ PySocketModule.Sock_Type, |
|
+ &sock, &server_side, |
|
+ Py_TYPE(Py_None), &hostname_obj, |
|
+ &ssl_sock)) { |
|
+ PyErr_Clear(); |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!iet|O:_wrap_socket", kwlist, |
|
+ PySocketModule.Sock_Type, |
|
+ &sock, &server_side, |
|
+ "idna", &hostname, &ssl_sock)) |
|
+ return NULL; |
|
+#if !HAVE_SNI |
|
+ PyMem_Free(hostname); |
|
+ PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " |
|
+ "by your OpenSSL library"); |
|
+ return NULL; |
|
+#endif |
|
+ } |
|
+ |
|
+ res = (PyObject *) newPySSLSocket(self, sock, server_side, |
|
+ hostname, ssl_sock); |
|
+ if (hostname != NULL) |
|
+ PyMem_Free(hostname); |
|
+ return res; |
|
+} |
|
+ |
|
+static PyObject * |
|
+session_stats(PySSLContext *self, PyObject *unused) |
|
+{ |
|
+ int r; |
|
+ PyObject *value, *stats = PyDict_New(); |
|
+ if (!stats) |
|
+ return NULL; |
|
+ |
|
+#define ADD_STATS(SSL_NAME, KEY_NAME) \ |
|
+ value = PyLong_FromLong(SSL_CTX_sess_ ## SSL_NAME (self->ctx)); \ |
|
+ if (value == NULL) \ |
|
+ goto error; \ |
|
+ r = PyDict_SetItemString(stats, KEY_NAME, value); \ |
|
+ Py_DECREF(value); \ |
|
+ if (r < 0) \ |
|
+ goto error; |
|
+ |
|
+ ADD_STATS(number, "number"); |
|
+ ADD_STATS(connect, "connect"); |
|
+ ADD_STATS(connect_good, "connect_good"); |
|
+ ADD_STATS(connect_renegotiate, "connect_renegotiate"); |
|
+ ADD_STATS(accept, "accept"); |
|
+ ADD_STATS(accept_good, "accept_good"); |
|
+ ADD_STATS(accept_renegotiate, "accept_renegotiate"); |
|
+ ADD_STATS(accept, "accept"); |
|
+ ADD_STATS(hits, "hits"); |
|
+ ADD_STATS(misses, "misses"); |
|
+ ADD_STATS(timeouts, "timeouts"); |
|
+ ADD_STATS(cache_full, "cache_full"); |
|
+ |
|
+#undef ADD_STATS |
|
+ |
|
+ return stats; |
|
+ |
|
+error: |
|
+ Py_DECREF(stats); |
|
+ return NULL; |
|
+} |
|
+ |
|
+static PyObject * |
|
+set_default_verify_paths(PySSLContext *self, PyObject *unused) |
|
+{ |
|
+ if (!SSL_CTX_set_default_verify_paths(self->ctx)) { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ return NULL; |
|
+ } |
|
+ Py_RETURN_NONE; |
|
+} |
|
+ |
|
+#ifndef OPENSSL_NO_ECDH |
|
+static PyObject * |
|
+set_ecdh_curve(PySSLContext *self, PyObject *name) |
|
+{ |
|
+ char *name_bytes; |
|
+ int nid; |
|
+ EC_KEY *key; |
|
+ |
|
+ name_bytes = PyBytes_AsString(name); |
|
+ if (!name_bytes) { |
|
+ return NULL; |
|
+ } |
|
+ nid = OBJ_sn2nid(name_bytes); |
|
+ if (nid == 0) { |
|
+ PyErr_Format(PyExc_ValueError, |
|
+ "unknown elliptic curve name %R", name); |
|
+ return NULL; |
|
+ } |
|
+ key = EC_KEY_new_by_curve_name(nid); |
|
+ if (key == NULL) { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ return NULL; |
|
+ } |
|
+ SSL_CTX_set_tmp_ecdh(self->ctx, key); |
|
+ EC_KEY_free(key); |
|
+ Py_RETURN_NONE; |
|
+} |
|
+#endif |
|
+ |
|
+#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT) |
|
+static int |
|
+_servername_callback(SSL *s, int *al, void *args) |
|
+{ |
|
+ int ret; |
|
+ PySSLContext *ssl_ctx = (PySSLContext *) args; |
|
+ PySSLSocket *ssl; |
|
+ PyObject *servername_o; |
|
+ PyObject *servername_idna; |
|
+ PyObject *result; |
|
+ /* The high-level ssl.SSLSocket object */ |
|
+ PyObject *ssl_socket; |
|
+ const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); |
|
+#ifdef WITH_THREAD |
|
+ PyGILState_STATE gstate = PyGILState_Ensure(); |
|
+#endif |
|
+ |
|
+ if (ssl_ctx->set_hostname == NULL) { |
|
+ /* remove race condition in this the call back while if removing the |
|
+ * callback is in progress */ |
|
+#ifdef WITH_THREAD |
|
+ PyGILState_Release(gstate); |
|
+#endif |
|
+ return SSL_TLSEXT_ERR_OK; |
|
+ } |
|
+ |
|
+ ssl = SSL_get_app_data(s); |
|
+ assert(PySSLSocket_Check(ssl)); |
|
+ ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); |
|
+ Py_INCREF(ssl_socket); |
|
+ if (ssl_socket == Py_None) { |
|
+ goto error; |
|
+ } |
|
+ |
|
+ if (servername == NULL) { |
|
+ result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket, |
|
+ Py_None, ssl_ctx, NULL); |
|
+ } |
|
+ else { |
|
+ servername_o = PyBytes_FromString(servername); |
|
+ if (servername_o == NULL) { |
|
+ PyErr_WriteUnraisable((PyObject *) ssl_ctx); |
|
+ goto error; |
|
+ } |
|
+ servername_idna = PyUnicode_FromEncodedObject(servername_o, "idna", NULL); |
|
+ if (servername_idna == NULL) { |
|
+ PyErr_WriteUnraisable(servername_o); |
|
+ Py_DECREF(servername_o); |
|
+ goto error; |
|
+ } |
|
+ Py_DECREF(servername_o); |
|
+ result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket, |
|
+ servername_idna, ssl_ctx, NULL); |
|
+ Py_DECREF(servername_idna); |
|
+ } |
|
+ Py_DECREF(ssl_socket); |
|
+ |
|
+ if (result == NULL) { |
|
+ PyErr_WriteUnraisable(ssl_ctx->set_hostname); |
|
+ *al = SSL_AD_HANDSHAKE_FAILURE; |
|
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL; |
|
+ } |
|
+ else { |
|
+ if (result != Py_None) { |
|
+ *al = (int) PyLong_AsLong(result); |
|
+ if (PyErr_Occurred()) { |
|
+ PyErr_WriteUnraisable(result); |
|
+ *al = SSL_AD_INTERNAL_ERROR; |
|
+ } |
|
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL; |
|
+ } |
|
+ else { |
|
+ ret = SSL_TLSEXT_ERR_OK; |
|
+ } |
|
+ Py_DECREF(result); |
|
+ } |
|
+ |
|
+#ifdef WITH_THREAD |
|
+ PyGILState_Release(gstate); |
|
+#endif |
|
+ return ret; |
|
+ |
|
+error: |
|
+ Py_DECREF(ssl_socket); |
|
+ *al = SSL_AD_INTERNAL_ERROR; |
|
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL; |
|
+#ifdef WITH_THREAD |
|
+ PyGILState_Release(gstate); |
|
+#endif |
|
+ return ret; |
|
+} |
|
+#endif |
|
+ |
|
+PyDoc_STRVAR(PySSL_set_servername_callback_doc, |
|
+"set_servername_callback(method)\n\ |
|
+\n\ |
|
+This sets a callback that will be called when a server name is provided by\n\ |
|
+the SSL/TLS client in the SNI extension.\n\ |
|
+\n\ |
|
+If the argument is None then the callback is disabled. The method is called\n\ |
|
+with the SSLSocket, the server name as a string, and the SSLContext object.\n\ |
|
+See RFC 6066 for details of the SNI extension."); |
|
+ |
|
+static PyObject * |
|
+set_servername_callback(PySSLContext *self, PyObject *args) |
|
+{ |
|
+#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT) |
|
+ PyObject *cb; |
|
+ |
|
+ if (!PyArg_ParseTuple(args, "O", &cb)) |
|
+ return NULL; |
|
+ |
|
+ Py_CLEAR(self->set_hostname); |
|
+ if (cb == Py_None) { |
|
+ SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); |
|
+ } |
|
+ else { |
|
+ if (!PyCallable_Check(cb)) { |
|
+ SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); |
|
+ PyErr_SetString(PyExc_TypeError, |
|
+ "not a callable object"); |
|
+ return NULL; |
|
+ } |
|
+ Py_INCREF(cb); |
|
+ self->set_hostname = cb; |
|
+ SSL_CTX_set_tlsext_servername_callback(self->ctx, _servername_callback); |
|
+ SSL_CTX_set_tlsext_servername_arg(self->ctx, self); |
|
+ } |
|
+ Py_RETURN_NONE; |
|
+#else |
|
+ PyErr_SetString(PyExc_NotImplementedError, |
|
+ "The TLS extension servername callback, " |
|
+ "SSL_CTX_set_tlsext_servername_callback, " |
|
+ "is not in the current OpenSSL library."); |
|
+ return NULL; |
|
+#endif |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_get_stats_doc, |
|
+"cert_store_stats() -> {'crl': int, 'x509_ca': int, 'x509': int}\n\ |
|
+\n\ |
|
+Returns quantities of loaded X.509 certificates. X.509 certificates with a\n\ |
|
+CA extension and certificate revocation lists inside the context's cert\n\ |
|
+store.\n\ |
|
+NOTE: Certificates in a capath directory aren't loaded unless they have\n\ |
|
+been used at least once."); |
|
+ |
|
+static PyObject * |
|
+cert_store_stats(PySSLContext *self) |
|
+{ |
|
+ X509_STORE *store; |
|
+ X509_OBJECT *obj; |
|
+ int x509 = 0, crl = 0, pkey = 0, ca = 0, i; |
|
+ |
|
+ store = SSL_CTX_get_cert_store(self->ctx); |
|
+ for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { |
|
+ obj = sk_X509_OBJECT_value(store->objs, i); |
|
+ switch (obj->type) { |
|
+ case X509_LU_X509: |
|
+ x509++; |
|
+ if (X509_check_ca(obj->data.x509)) { |
|
+ ca++; |
|
+ } |
|
+ break; |
|
+ case X509_LU_CRL: |
|
+ crl++; |
|
+ break; |
|
+ case X509_LU_PKEY: |
|
+ pkey++; |
|
+ break; |
|
+ default: |
|
+ /* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY. |
|
+ * As far as I can tell they are internal states and never |
|
+ * stored in a cert store */ |
|
+ break; |
|
+ } |
|
+ } |
|
+ return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl, |
|
+ "x509_ca", ca); |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_get_ca_certs_doc, |
|
+"get_ca_certs(binary_form=False) -> list of loaded certificate\n\ |
|
+\n\ |
|
+Returns a list of dicts with information of loaded CA certs. If the\n\ |
|
+optional argument is True, returns a DER-encoded copy of the CA certificate.\n\ |
|
+NOTE: Certificates in a capath directory aren't loaded unless they have\n\ |
|
+been used at least once."); |
|
+ |
|
+static PyObject * |
|
+get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds) |
|
+{ |
|
+ char *kwlist[] = {"binary_form", NULL}; |
|
+ X509_STORE *store; |
|
+ PyObject *ci = NULL, *rlist = NULL, *py_binary_mode = Py_False; |
|
+ int i; |
|
+ int binary_mode = 0; |
|
+ |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:get_ca_certs", |
|
+ kwlist, &py_binary_mode)) { |
|
+ return NULL; |
|
+ } |
|
+ binary_mode = PyObject_IsTrue(py_binary_mode); |
|
+ if (binary_mode < 0) { |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ if ((rlist = PyList_New(0)) == NULL) { |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ store = SSL_CTX_get_cert_store(self->ctx); |
|
+ for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { |
|
+ X509_OBJECT *obj; |
|
+ X509 *cert; |
|
+ |
|
+ obj = sk_X509_OBJECT_value(store->objs, i); |
|
+ if (obj->type != X509_LU_X509) { |
|
+ /* not a x509 cert */ |
|
+ continue; |
|
+ } |
|
+ /* CA for any purpose */ |
|
+ cert = obj->data.x509; |
|
+ if (!X509_check_ca(cert)) { |
|
+ continue; |
|
+ } |
|
+ if (binary_mode) { |
|
+ ci = _certificate_to_der(cert); |
|
+ } else { |
|
+ ci = _decode_certificate(cert); |
|
+ } |
|
+ if (ci == NULL) { |
|
+ goto error; |
|
+ } |
|
+ if (PyList_Append(rlist, ci) == -1) { |
|
+ goto error; |
|
+ } |
|
+ Py_CLEAR(ci); |
|
+ } |
|
+ return rlist; |
|
+ |
|
+ error: |
|
+ Py_XDECREF(ci); |
|
+ Py_XDECREF(rlist); |
|
+ return NULL; |
|
+} |
|
+ |
|
+ |
|
+static PyGetSetDef context_getsetlist[] = { |
|
+ {"check_hostname", (getter) get_check_hostname, |
|
+ (setter) set_check_hostname, NULL}, |
|
+ {"options", (getter) get_options, |
|
+ (setter) set_options, NULL}, |
|
+#ifdef HAVE_OPENSSL_VERIFY_PARAM |
|
+ {"verify_flags", (getter) get_verify_flags, |
|
+ (setter) set_verify_flags, NULL}, |
|
+#endif |
|
+ {"verify_mode", (getter) get_verify_mode, |
|
+ (setter) set_verify_mode, NULL}, |
|
+ {NULL}, /* sentinel */ |
|
+}; |
|
+ |
|
+static struct PyMethodDef context_methods[] = { |
|
+ {"_wrap_socket", (PyCFunction) context_wrap_socket, |
|
+ METH_VARARGS | METH_KEYWORDS, NULL}, |
|
+ {"set_ciphers", (PyCFunction) set_ciphers, |
|
+ METH_VARARGS, NULL}, |
|
+ {"_set_npn_protocols", (PyCFunction) _set_npn_protocols, |
|
+ METH_VARARGS, NULL}, |
|
+ {"load_cert_chain", (PyCFunction) load_cert_chain, |
|
+ METH_VARARGS | METH_KEYWORDS, NULL}, |
|
+ {"load_dh_params", (PyCFunction) load_dh_params, |
|
+ METH_O, NULL}, |
|
+ {"load_verify_locations", (PyCFunction) load_verify_locations, |
|
+ METH_VARARGS | METH_KEYWORDS, NULL}, |
|
+ {"session_stats", (PyCFunction) session_stats, |
|
+ METH_NOARGS, NULL}, |
|
+ {"set_default_verify_paths", (PyCFunction) set_default_verify_paths, |
|
+ METH_NOARGS, NULL}, |
|
+#ifndef OPENSSL_NO_ECDH |
|
+ {"set_ecdh_curve", (PyCFunction) set_ecdh_curve, |
|
+ METH_O, NULL}, |
|
+#endif |
|
+ {"set_servername_callback", (PyCFunction) set_servername_callback, |
|
+ METH_VARARGS, PySSL_set_servername_callback_doc}, |
|
+ {"cert_store_stats", (PyCFunction) cert_store_stats, |
|
+ METH_NOARGS, PySSL_get_stats_doc}, |
|
+ {"get_ca_certs", (PyCFunction) get_ca_certs, |
|
+ METH_VARARGS | METH_KEYWORDS, PySSL_get_ca_certs_doc}, |
|
+ {NULL, NULL} /* sentinel */ |
|
+}; |
|
+ |
|
+static PyTypeObject PySSLContext_Type = { |
|
+ PyVarObject_HEAD_INIT(NULL, 0) |
|
+ "_ssl._SSLContext", /*tp_name*/ |
|
+ sizeof(PySSLContext), /*tp_basicsize*/ |
|
+ 0, /*tp_itemsize*/ |
|
+ (destructor)context_dealloc, /*tp_dealloc*/ |
|
+ 0, /*tp_print*/ |
|
+ 0, /*tp_getattr*/ |
|
+ 0, /*tp_setattr*/ |
|
+ 0, /*tp_reserved*/ |
|
+ 0, /*tp_repr*/ |
|
+ 0, /*tp_as_number*/ |
|
+ 0, /*tp_as_sequence*/ |
|
+ 0, /*tp_as_mapping*/ |
|
+ 0, /*tp_hash*/ |
|
+ 0, /*tp_call*/ |
|
+ 0, /*tp_str*/ |
|
+ 0, /*tp_getattro*/ |
|
+ 0, /*tp_setattro*/ |
|
+ 0, /*tp_as_buffer*/ |
|
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ |
|
+ 0, /*tp_doc*/ |
|
+ (traverseproc) context_traverse, /*tp_traverse*/ |
|
+ (inquiry) context_clear, /*tp_clear*/ |
|
+ 0, /*tp_richcompare*/ |
|
+ 0, /*tp_weaklistoffset*/ |
|
+ 0, /*tp_iter*/ |
|
+ 0, /*tp_iternext*/ |
|
+ context_methods, /*tp_methods*/ |
|
+ 0, /*tp_members*/ |
|
+ context_getsetlist, /*tp_getset*/ |
|
+ 0, /*tp_base*/ |
|
+ 0, /*tp_dict*/ |
|
+ 0, /*tp_descr_get*/ |
|
+ 0, /*tp_descr_set*/ |
|
+ 0, /*tp_dictoffset*/ |
|
+ 0, /*tp_init*/ |
|
+ 0, /*tp_alloc*/ |
|
+ context_new, /*tp_new*/ |
|
+}; |
|
+ |
|
+ |
|
+ |
|
+#ifdef HAVE_OPENSSL_RAND |
|
+ |
|
+/* helper routines for seeding the SSL PRNG */ |
|
+static PyObject * |
|
+PySSL_RAND_add(PyObject *self, PyObject *args) |
|
+{ |
|
+ char *buf; |
|
+ Py_ssize_t len, written; |
|
+ double entropy; |
|
+ |
|
+ if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) |
|
+ return NULL; |
|
+ do { |
|
+ if (len >= INT_MAX) { |
|
+ written = INT_MAX; |
|
+ } else { |
|
+ written = len; |
|
+ } |
|
+ RAND_add(buf, (int)written, entropy); |
|
+ buf += written; |
|
+ len -= written; |
|
+ } while (len); |
|
+ Py_INCREF(Py_None); |
|
+ return Py_None; |
|
+} |
|
+ |
|
+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. See RFC 1750."); |
|
+ |
|
+static PyObject * |
|
+PySSL_RAND_status(PyObject *self) |
|
+{ |
|
+ return PyLong_FromLong(RAND_status()); |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_RAND_status_doc, |
|
+"RAND_status() -> 0 or 1\n\ |
|
+\n\ |
|
+Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\ |
|
+It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ |
|
+using the ssl() function."); |
|
+ |
|
+static PyObject * |
|
+PySSL_RAND_egd(PyObject *self, PyObject *arg) |
|
+{ |
|
+ int bytes; |
|
+ |
|
+ if (!PyString_Check(arg)) |
|
+ return PyErr_Format(PyExc_TypeError, |
|
+ "RAND_egd() expected string, found %s", |
|
+ Py_TYPE(arg)->tp_name); |
|
+ bytes = RAND_egd(PyString_AS_STRING(arg)); |
|
+ if (bytes == -1) { |
|
+ PyErr_SetString(PySSLErrorObject, |
|
+ "EGD connection failed or EGD did not return " |
|
+ "enough data to seed the PRNG"); |
|
+ return NULL; |
|
+ } |
|
+ return PyInt_FromLong(bytes); |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_RAND_egd_doc, |
|
+"RAND_egd(path) -> bytes\n\ |
|
+\n\ |
|
+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 not provide enough data to seed PRNG."); |
|
+ |
|
+#endif /* HAVE_OPENSSL_RAND */ |
|
+ |
|
+ |
|
+PyDoc_STRVAR(PySSL_get_default_verify_paths_doc, |
|
+"get_default_verify_paths() -> tuple\n\ |
|
+\n\ |
|
+Return search paths and environment vars that are used by SSLContext's\n\ |
|
+set_default_verify_paths() to load default CAs. The values are\n\ |
|
+'cert_file_env', 'cert_file', 'cert_dir_env', 'cert_dir'."); |
|
+ |
|
+static PyObject * |
|
+PySSL_get_default_verify_paths(PyObject *self) |
|
+{ |
|
+ PyObject *ofile_env = NULL; |
|
+ PyObject *ofile = NULL; |
|
+ PyObject *odir_env = NULL; |
|
+ PyObject *odir = NULL; |
|
+ |
|
+#define convert(info, target) { \ |
|
+ const char *tmp = (info); \ |
|
+ target = NULL; \ |
|
+ if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \ |
|
+ else { target = PyBytes_FromString(tmp); } \ |
|
+ if (!target) goto error; \ |
|
+ } while(0) |
|
+ |
|
+ convert(X509_get_default_cert_file_env(), ofile_env); |
|
+ convert(X509_get_default_cert_file(), ofile); |
|
+ convert(X509_get_default_cert_dir_env(), odir_env); |
|
+ convert(X509_get_default_cert_dir(), odir); |
|
+#undef convert |
|
+ |
|
+ return Py_BuildValue("NNNN", ofile_env, ofile, odir_env, odir); |
|
+ |
|
+ error: |
|
+ Py_XDECREF(ofile_env); |
|
+ Py_XDECREF(ofile); |
|
+ Py_XDECREF(odir_env); |
|
+ Py_XDECREF(odir); |
|
+ return NULL; |
|
+} |
|
+ |
|
+static PyObject* |
|
+asn1obj2py(ASN1_OBJECT *obj) |
|
+{ |
|
+ int nid; |
|
+ const char *ln, *sn; |
|
+ char buf[100]; |
|
+ Py_ssize_t buflen; |
|
+ |
|
+ nid = OBJ_obj2nid(obj); |
|
+ if (nid == NID_undef) { |
|
+ PyErr_Format(PyExc_ValueError, "Unknown object"); |
|
+ return NULL; |
|
+ } |
|
+ sn = OBJ_nid2sn(nid); |
|
+ ln = OBJ_nid2ln(nid); |
|
+ buflen = OBJ_obj2txt(buf, sizeof(buf), obj, 1); |
|
+ if (buflen < 0) { |
|
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
|
+ return NULL; |
|
+ } |
|
+ if (buflen) { |
|
+ return Py_BuildValue("isss#", nid, sn, ln, buf, buflen); |
|
+ } else { |
|
+ return Py_BuildValue("issO", nid, sn, ln, Py_None); |
|
+ } |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_txt2obj_doc, |
|
+"txt2obj(txt, name=False) -> (nid, shortname, longname, oid)\n\ |
|
+\n\ |
|
+Lookup NID, short name, long name and OID of an ASN1_OBJECT. By default\n\ |
|
+objects are looked up by OID. With name=True short and long name are also\n\ |
|
+matched."); |
|
+ |
|
+static PyObject* |
|
+PySSL_txt2obj(PyObject *self, PyObject *args, PyObject *kwds) |
|
+{ |
|
+ char *kwlist[] = {"txt", "name", NULL}; |
|
+ PyObject *result = NULL; |
|
+ char *txt; |
|
+ PyObject *pyname = Py_None; |
|
+ int name = 0; |
|
+ ASN1_OBJECT *obj; |
|
+ |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O:txt2obj", |
|
+ kwlist, &txt, &pyname)) { |
|
+ return NULL; |
|
+ } |
|
+ name = PyObject_IsTrue(pyname); |
|
+ if (name < 0) |
|
+ return NULL; |
|
+ obj = OBJ_txt2obj(txt, name ? 0 : 1); |
|
+ if (obj == NULL) { |
|
+ PyErr_Format(PyExc_ValueError, "unknown object '%.100s'", txt); |
|
+ return NULL; |
|
+ } |
|
+ result = asn1obj2py(obj); |
|
+ ASN1_OBJECT_free(obj); |
|
+ return result; |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_nid2obj_doc, |
|
+"nid2obj(nid) -> (nid, shortname, longname, oid)\n\ |
|
+\n\ |
|
+Lookup NID, short name, long name and OID of an ASN1_OBJECT by NID."); |
|
+ |
|
+static PyObject* |
|
+PySSL_nid2obj(PyObject *self, PyObject *args) |
|
+{ |
|
+ PyObject *result = NULL; |
|
+ int nid; |
|
+ ASN1_OBJECT *obj; |
|
+ |
|
+ if (!PyArg_ParseTuple(args, "i:nid2obj", &nid)) { |
|
+ return NULL; |
|
+ } |
|
+ if (nid < NID_undef) { |
|
+ PyErr_SetString(PyExc_ValueError, "NID must be positive."); |
|
+ return NULL; |
|
+ } |
|
+ obj = OBJ_nid2obj(nid); |
|
+ if (obj == NULL) { |
|
+ PyErr_Format(PyExc_ValueError, "unknown NID %i", nid); |
|
+ return NULL; |
|
+ } |
|
+ result = asn1obj2py(obj); |
|
+ ASN1_OBJECT_free(obj); |
|
+ return result; |
|
+} |
|
+ |
|
+#ifdef _MSC_VER |
|
+ |
|
+static PyObject* |
|
+certEncodingType(DWORD encodingType) |
|
+{ |
|
+ static PyObject *x509_asn = NULL; |
|
+ static PyObject *pkcs_7_asn = NULL; |
|
+ |
|
+ if (x509_asn == NULL) { |
|
+ x509_asn = PyString_InternFromString("x509_asn"); |
|
+ if (x509_asn == NULL) |
|
+ return NULL; |
|
+ } |
|
+ if (pkcs_7_asn == NULL) { |
|
+ pkcs_7_asn = PyString_InternFromString("pkcs_7_asn"); |
|
+ if (pkcs_7_asn == NULL) |
|
+ return NULL; |
|
+ } |
|
+ switch(encodingType) { |
|
+ case X509_ASN_ENCODING: |
|
+ Py_INCREF(x509_asn); |
|
+ return x509_asn; |
|
+ case PKCS_7_ASN_ENCODING: |
|
+ Py_INCREF(pkcs_7_asn); |
|
+ return pkcs_7_asn; |
|
+ default: |
|
+ return PyInt_FromLong(encodingType); |
|
+ } |
|
+} |
|
+ |
|
+static PyObject* |
|
+parseKeyUsage(PCCERT_CONTEXT pCertCtx, DWORD flags) |
|
+{ |
|
+ CERT_ENHKEY_USAGE *usage; |
|
+ DWORD size, error, i; |
|
+ PyObject *retval; |
|
+ |
|
+ if (!CertGetEnhancedKeyUsage(pCertCtx, flags, NULL, &size)) { |
|
+ error = GetLastError(); |
|
+ if (error == CRYPT_E_NOT_FOUND) { |
|
+ Py_RETURN_TRUE; |
|
+ } |
|
+ return PyErr_SetFromWindowsErr(error); |
|
+ } |
|
+ |
|
+ usage = (CERT_ENHKEY_USAGE*)PyMem_Malloc(size); |
|
+ if (usage == NULL) { |
|
+ return PyErr_NoMemory(); |
|
+ } |
|
+ |
|
+ /* Now get the actual enhanced usage property */ |
|
+ if (!CertGetEnhancedKeyUsage(pCertCtx, flags, usage, &size)) { |
|
+ PyMem_Free(usage); |
|
+ error = GetLastError(); |
|
+ if (error == CRYPT_E_NOT_FOUND) { |
|
+ Py_RETURN_TRUE; |
|
+ } |
|
+ return PyErr_SetFromWindowsErr(error); |
|
+ } |
|
+ retval = PySet_New(NULL); |
|
+ if (retval == NULL) { |
|
+ goto error; |
|
+ } |
|
+ for (i = 0; i < usage->cUsageIdentifier; ++i) { |
|
+ if (usage->rgpszUsageIdentifier[i]) { |
|
+ PyObject *oid; |
|
+ int err; |
|
+ oid = PyString_FromString(usage->rgpszUsageIdentifier[i]); |
|
+ if (oid == NULL) { |
|
+ Py_CLEAR(retval); |
|
+ goto error; |
|
+ } |
|
+ err = PySet_Add(retval, oid); |
|
+ Py_DECREF(oid); |
|
+ if (err == -1) { |
|
+ Py_CLEAR(retval); |
|
+ goto error; |
|
+ } |
|
+ } |
|
+ } |
|
+ error: |
|
+ PyMem_Free(usage); |
|
+ return retval; |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_enum_certificates_doc, |
|
+"enum_certificates(store_name) -> []\n\ |
|
+\n\ |
|
+Retrieve certificates from Windows' cert store. store_name may be one of\n\ |
|
+'CA', 'ROOT' or 'MY'. The system may provide more cert storages, too.\n\ |
|
+The function returns a list of (bytes, encoding_type, trust) tuples. The\n\ |
|
+encoding_type flag can be interpreted with X509_ASN_ENCODING or\n\ |
|
+PKCS_7_ASN_ENCODING. The trust setting is either a set of OIDs or the\n\ |
|
+boolean True."); |
|
+ |
|
+static PyObject * |
|
+PySSL_enum_certificates(PyObject *self, PyObject *args, PyObject *kwds) |
|
+{ |
|
+ char *kwlist[] = {"store_name", NULL}; |
|
+ char *store_name; |
|
+ HCERTSTORE hStore = NULL; |
|
+ PCCERT_CONTEXT pCertCtx = NULL; |
|
+ PyObject *keyusage = NULL, *cert = NULL, *enc = NULL, *tup = NULL; |
|
+ PyObject *result = NULL; |
|
+ |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:enum_certificates", |
|
+ kwlist, &store_name)) { |
|
+ return NULL; |
|
+ } |
|
+ result = PyList_New(0); |
|
+ if (result == NULL) { |
|
+ return NULL; |
|
+ } |
|
+ hStore = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); |
|
+ if (hStore == NULL) { |
|
+ Py_DECREF(result); |
|
+ return PyErr_SetFromWindowsErr(GetLastError()); |
|
+ } |
|
+ |
|
+ while (pCertCtx = CertEnumCertificatesInStore(hStore, pCertCtx)) { |
|
+ cert = PyBytes_FromStringAndSize((const char*)pCertCtx->pbCertEncoded, |
|
+ pCertCtx->cbCertEncoded); |
|
+ if (!cert) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ if ((enc = certEncodingType(pCertCtx->dwCertEncodingType)) == NULL) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ keyusage = parseKeyUsage(pCertCtx, CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG); |
|
+ if (keyusage == Py_True) { |
|
+ Py_DECREF(keyusage); |
|
+ keyusage = parseKeyUsage(pCertCtx, CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG); |
|
+ } |
|
+ if (keyusage == NULL) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ if ((tup = PyTuple_New(3)) == NULL) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ PyTuple_SET_ITEM(tup, 0, cert); |
|
+ cert = NULL; |
|
+ PyTuple_SET_ITEM(tup, 1, enc); |
|
+ enc = NULL; |
|
+ PyTuple_SET_ITEM(tup, 2, keyusage); |
|
+ keyusage = NULL; |
|
+ if (PyList_Append(result, tup) < 0) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ Py_CLEAR(tup); |
|
+ } |
|
+ if (pCertCtx) { |
|
+ /* loop ended with an error, need to clean up context manually */ |
|
+ CertFreeCertificateContext(pCertCtx); |
|
+ } |
|
+ |
|
+ /* In error cases cert, enc and tup may not be NULL */ |
|
+ Py_XDECREF(cert); |
|
+ Py_XDECREF(enc); |
|
+ Py_XDECREF(keyusage); |
|
+ Py_XDECREF(tup); |
|
+ |
|
+ if (!CertCloseStore(hStore, 0)) { |
|
+ /* This error case might shadow another exception.*/ |
|
+ Py_XDECREF(result); |
|
+ return PyErr_SetFromWindowsErr(GetLastError()); |
|
+ } |
|
+ return result; |
|
+} |
|
+ |
|
+PyDoc_STRVAR(PySSL_enum_crls_doc, |
|
+"enum_crls(store_name) -> []\n\ |
|
+\n\ |
|
+Retrieve CRLs from Windows' cert store. store_name may be one of\n\ |
|
+'CA', 'ROOT' or 'MY'. The system may provide more cert storages, too.\n\ |
|
+The function returns a list of (bytes, encoding_type) tuples. The\n\ |
|
+encoding_type flag can be interpreted with X509_ASN_ENCODING or\n\ |
|
+PKCS_7_ASN_ENCODING."); |
|
+ |
|
+static PyObject * |
|
+PySSL_enum_crls(PyObject *self, PyObject *args, PyObject *kwds) |
|
+{ |
|
+ char *kwlist[] = {"store_name", NULL}; |
|
+ char *store_name; |
|
+ HCERTSTORE hStore = NULL; |
|
+ PCCRL_CONTEXT pCrlCtx = NULL; |
|
+ PyObject *crl = NULL, *enc = NULL, *tup = NULL; |
|
+ PyObject *result = NULL; |
|
+ |
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:enum_crls", |
|
+ kwlist, &store_name)) { |
|
+ return NULL; |
|
+ } |
|
+ result = PyList_New(0); |
|
+ if (result == NULL) { |
|
+ return NULL; |
|
+ } |
|
+ hStore = CertOpenSystemStore((HCRYPTPROV)NULL, store_name); |
|
+ if (hStore == NULL) { |
|
+ Py_DECREF(result); |
|
+ return PyErr_SetFromWindowsErr(GetLastError()); |
|
+ } |
|
+ |
|
+ while (pCrlCtx = CertEnumCRLsInStore(hStore, pCrlCtx)) { |
|
+ crl = PyBytes_FromStringAndSize((const char*)pCrlCtx->pbCrlEncoded, |
|
+ pCrlCtx->cbCrlEncoded); |
|
+ if (!crl) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ if ((enc = certEncodingType(pCrlCtx->dwCertEncodingType)) == NULL) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ if ((tup = PyTuple_New(2)) == NULL) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ PyTuple_SET_ITEM(tup, 0, crl); |
|
+ crl = NULL; |
|
+ PyTuple_SET_ITEM(tup, 1, enc); |
|
+ enc = NULL; |
|
+ |
|
+ if (PyList_Append(result, tup) < 0) { |
|
+ Py_CLEAR(result); |
|
+ break; |
|
+ } |
|
+ Py_CLEAR(tup); |
|
+ } |
|
+ if (pCrlCtx) { |
|
+ /* loop ended with an error, need to clean up context manually */ |
|
+ CertFreeCRLContext(pCrlCtx); |
|
+ } |
|
+ |
|
+ /* In error cases cert, enc and tup may not be NULL */ |
|
+ Py_XDECREF(crl); |
|
+ Py_XDECREF(enc); |
|
+ Py_XDECREF(tup); |
|
+ |
|
+ if (!CertCloseStore(hStore, 0)) { |
|
+ /* This error case might shadow another exception.*/ |
|
+ Py_XDECREF(result); |
|
+ return PyErr_SetFromWindowsErr(GetLastError()); |
|
+ } |
|
+ return result; |
|
+} |
|
+ |
|
+#endif /* _MSC_VER */ |
|
+ |
|
+/* List of functions exported by this module. */ |
|
|
|
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}, |
|
- {"RAND_egd", PySSL_RAND_egd, METH_O, |
|
+ {"RAND_egd", PySSL_RAND_egd, METH_VARARGS, |
|
PySSL_RAND_egd_doc}, |
|
{"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS, |
|
PySSL_RAND_status_doc}, |
|
#endif |
|
+ {"get_default_verify_paths", (PyCFunction)PySSL_get_default_verify_paths, |
|
+ METH_NOARGS, PySSL_get_default_verify_paths_doc}, |
|
+#ifdef _MSC_VER |
|
+ {"enum_certificates", (PyCFunction)PySSL_enum_certificates, |
|
+ METH_VARARGS | METH_KEYWORDS, PySSL_enum_certificates_doc}, |
|
+ {"enum_crls", (PyCFunction)PySSL_enum_crls, |
|
+ METH_VARARGS | METH_KEYWORDS, PySSL_enum_crls_doc}, |
|
+#endif |
|
+ {"txt2obj", (PyCFunction)PySSL_txt2obj, |
|
+ METH_VARARGS | METH_KEYWORDS, PySSL_txt2obj_doc}, |
|
+ {"nid2obj", (PyCFunction)PySSL_nid2obj, |
|
+ METH_VARARGS, PySSL_nid2obj_doc}, |
|
{NULL, NULL} /* Sentinel */ |
|
}; |
|
|
|
@@ -1656,16 +3701,17 @@ static unsigned long _ssl_thread_id_func |
|
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 |
|
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. |
|
+ 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. |
|
@@ -1689,10 +3735,11 @@ static int _setup_ssl_threads(void) { |
|
if (_ssl_locks == NULL) { |
|
_ssl_locks_count = CRYPTO_num_locks(); |
|
_ssl_locks = (PyThread_type_lock *) |
|
- malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); |
|
+ PyMem_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); |
|
+ 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) { |
|
@@ -1700,7 +3747,7 @@ static int _setup_ssl_threads(void) { |
|
for (j = 0; j < i; j++) { |
|
PyThread_free_lock(_ssl_locks[j]); |
|
} |
|
- free(_ssl_locks); |
|
+ PyMem_Free(_ssl_locks); |
|
return 0; |
|
} |
|
} |
|
@@ -1716,14 +3763,39 @@ PyDoc_STRVAR(module_doc, |
|
"Implementation module for SSL socket operations. See the socket module\n\ |
|
for documentation."); |
|
|
|
+ |
|
+ |
|
+ |
|
+static void |
|
+parse_openssl_version(unsigned long libver, |
|
+ unsigned int *major, unsigned int *minor, |
|
+ unsigned int *fix, unsigned int *patch, |
|
+ unsigned int *status) |
|
+{ |
|
+ *status = libver & 0xF; |
|
+ libver >>= 4; |
|
+ *patch = libver & 0xFF; |
|
+ libver >>= 8; |
|
+ *fix = libver & 0xFF; |
|
+ libver >>= 8; |
|
+ *minor = libver & 0xFF; |
|
+ libver >>= 8; |
|
+ *major = libver & 0xFF; |
|
+} |
|
+ |
|
PyMODINIT_FUNC |
|
init_ssl(void) |
|
{ |
|
PyObject *m, *d, *r; |
|
unsigned long libver; |
|
unsigned int major, minor, fix, patch, status; |
|
+ struct py_ssl_error_code *errcode; |
|
+ struct py_ssl_library_code *libcode; |
|
|
|
- Py_TYPE(&PySSL_Type) = &PyType_Type; |
|
+ if (PyType_Ready(&PySSLContext_Type) < 0) |
|
+ return; |
|
+ if (PyType_Ready(&PySSLSocket_Type) < 0) |
|
+ return; |
|
|
|
m = Py_InitModule3("_ssl", PySSL_methods, module_doc); |
|
if (m == NULL) |
|
@@ -1746,15 +3818,53 @@ init_ssl(void) |
|
OpenSSL_add_all_algorithms(); |
|
|
|
/* Add symbols to module dict */ |
|
- PySSLErrorObject = PyErr_NewException("ssl.SSLError", |
|
- PySocketModule.error, |
|
- NULL); |
|
+ PySSLErrorObject = PyErr_NewExceptionWithDoc( |
|
+ "ssl.SSLError", SSLError_doc, |
|
+ PySocketModule.error, NULL); |
|
if (PySSLErrorObject == NULL) |
|
return; |
|
- if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0) |
|
+ ((PyTypeObject *)PySSLErrorObject)->tp_str = (reprfunc)SSLError_str; |
|
+ |
|
+ PySSLZeroReturnErrorObject = PyErr_NewExceptionWithDoc( |
|
+ "ssl.SSLZeroReturnError", SSLZeroReturnError_doc, |
|
+ PySSLErrorObject, NULL); |
|
+ PySSLWantReadErrorObject = PyErr_NewExceptionWithDoc( |
|
+ "ssl.SSLWantReadError", SSLWantReadError_doc, |
|
+ PySSLErrorObject, NULL); |
|
+ PySSLWantWriteErrorObject = PyErr_NewExceptionWithDoc( |
|
+ "ssl.SSLWantWriteError", SSLWantWriteError_doc, |
|
+ PySSLErrorObject, NULL); |
|
+ PySSLSyscallErrorObject = PyErr_NewExceptionWithDoc( |
|
+ "ssl.SSLSyscallError", SSLSyscallError_doc, |
|
+ PySSLErrorObject, NULL); |
|
+ PySSLEOFErrorObject = PyErr_NewExceptionWithDoc( |
|
+ "ssl.SSLEOFError", SSLEOFError_doc, |
|
+ PySSLErrorObject, NULL); |
|
+ if (PySSLZeroReturnErrorObject == NULL |
|
+ || PySSLWantReadErrorObject == NULL |
|
+ || PySSLWantWriteErrorObject == NULL |
|
+ || PySSLSyscallErrorObject == NULL |
|
+ || PySSLEOFErrorObject == NULL) |
|
+ return; |
|
+ |
|
+ ((PyTypeObject *)PySSLZeroReturnErrorObject)->tp_str = (reprfunc)SSLError_str; |
|
+ ((PyTypeObject *)PySSLWantReadErrorObject)->tp_str = (reprfunc)SSLError_str; |
|
+ ((PyTypeObject *)PySSLWantWriteErrorObject)->tp_str = (reprfunc)SSLError_str; |
|
+ ((PyTypeObject *)PySSLSyscallErrorObject)->tp_str = (reprfunc)SSLError_str; |
|
+ ((PyTypeObject *)PySSLEOFErrorObject)->tp_str = (reprfunc)SSLError_str; |
|
+ |
|
+ if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0 |
|
+ || PyDict_SetItemString(d, "SSLZeroReturnError", PySSLZeroReturnErrorObject) != 0 |
|
+ || PyDict_SetItemString(d, "SSLWantReadError", PySSLWantReadErrorObject) != 0 |
|
+ || PyDict_SetItemString(d, "SSLWantWriteError", PySSLWantWriteErrorObject) != 0 |
|
+ || PyDict_SetItemString(d, "SSLSyscallError", PySSLSyscallErrorObject) != 0 |
|
+ || PyDict_SetItemString(d, "SSLEOFError", PySSLEOFErrorObject) != 0) |
|
+ return; |
|
+ if (PyDict_SetItemString(d, "_SSLContext", |
|
+ (PyObject *)&PySSLContext_Type) != 0) |
|
return; |
|
- if (PyDict_SetItemString(d, "SSLType", |
|
- (PyObject *)&PySSL_Type) != 0) |
|
+ if (PyDict_SetItemString(d, "_SSLSocket", |
|
+ (PyObject *)&PySSLSocket_Type) != 0) |
|
return; |
|
PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", |
|
PY_SSL_ERROR_ZERO_RETURN); |
|
@@ -1782,6 +3892,66 @@ init_ssl(void) |
|
PY_SSL_CERT_OPTIONAL); |
|
PyModule_AddIntConstant(m, "CERT_REQUIRED", |
|
PY_SSL_CERT_REQUIRED); |
|
+ /* CRL verification for verification_flags */ |
|
+ PyModule_AddIntConstant(m, "VERIFY_DEFAULT", |
|
+ 0); |
|
+ PyModule_AddIntConstant(m, "VERIFY_CRL_CHECK_LEAF", |
|
+ X509_V_FLAG_CRL_CHECK); |
|
+ PyModule_AddIntConstant(m, "VERIFY_CRL_CHECK_CHAIN", |
|
+ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); |
|
+ PyModule_AddIntConstant(m, "VERIFY_X509_STRICT", |
|
+ X509_V_FLAG_X509_STRICT); |
|
+ |
|
+ /* Alert Descriptions from ssl.h */ |
|
+ /* note RESERVED constants no longer intended for use have been removed */ |
|
+ /* http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6 */ |
|
+ |
|
+#define ADD_AD_CONSTANT(s) \ |
|
+ PyModule_AddIntConstant(m, "ALERT_DESCRIPTION_"#s, \ |
|
+ SSL_AD_##s) |
|
+ |
|
+ ADD_AD_CONSTANT(CLOSE_NOTIFY); |
|
+ ADD_AD_CONSTANT(UNEXPECTED_MESSAGE); |
|
+ ADD_AD_CONSTANT(BAD_RECORD_MAC); |
|
+ ADD_AD_CONSTANT(RECORD_OVERFLOW); |
|
+ ADD_AD_CONSTANT(DECOMPRESSION_FAILURE); |
|
+ ADD_AD_CONSTANT(HANDSHAKE_FAILURE); |
|
+ ADD_AD_CONSTANT(BAD_CERTIFICATE); |
|
+ ADD_AD_CONSTANT(UNSUPPORTED_CERTIFICATE); |
|
+ ADD_AD_CONSTANT(CERTIFICATE_REVOKED); |
|
+ ADD_AD_CONSTANT(CERTIFICATE_EXPIRED); |
|
+ ADD_AD_CONSTANT(CERTIFICATE_UNKNOWN); |
|
+ ADD_AD_CONSTANT(ILLEGAL_PARAMETER); |
|
+ ADD_AD_CONSTANT(UNKNOWN_CA); |
|
+ ADD_AD_CONSTANT(ACCESS_DENIED); |
|
+ ADD_AD_CONSTANT(DECODE_ERROR); |
|
+ ADD_AD_CONSTANT(DECRYPT_ERROR); |
|
+ ADD_AD_CONSTANT(PROTOCOL_VERSION); |
|
+ ADD_AD_CONSTANT(INSUFFICIENT_SECURITY); |
|
+ ADD_AD_CONSTANT(INTERNAL_ERROR); |
|
+ ADD_AD_CONSTANT(USER_CANCELLED); |
|
+ ADD_AD_CONSTANT(NO_RENEGOTIATION); |
|
+ /* Not all constants are in old OpenSSL versions */ |
|
+#ifdef SSL_AD_UNSUPPORTED_EXTENSION |
|
+ ADD_AD_CONSTANT(UNSUPPORTED_EXTENSION); |
|
+#endif |
|
+#ifdef SSL_AD_CERTIFICATE_UNOBTAINABLE |
|
+ ADD_AD_CONSTANT(CERTIFICATE_UNOBTAINABLE); |
|
+#endif |
|
+#ifdef SSL_AD_UNRECOGNIZED_NAME |
|
+ ADD_AD_CONSTANT(UNRECOGNIZED_NAME); |
|
+#endif |
|
+#ifdef SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE |
|
+ ADD_AD_CONSTANT(BAD_CERTIFICATE_STATUS_RESPONSE); |
|
+#endif |
|
+#ifdef SSL_AD_BAD_CERTIFICATE_HASH_VALUE |
|
+ ADD_AD_CONSTANT(BAD_CERTIFICATE_HASH_VALUE); |
|
+#endif |
|
+#ifdef SSL_AD_UNKNOWN_PSK_IDENTITY |
|
+ ADD_AD_CONSTANT(UNKNOWN_PSK_IDENTITY); |
|
+#endif |
|
+ |
|
+#undef ADD_AD_CONSTANT |
|
|
|
/* protocol versions */ |
|
#ifndef OPENSSL_NO_SSL2 |
|
@@ -1794,6 +3964,109 @@ init_ssl(void) |
|
PY_SSL_VERSION_SSL23); |
|
PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", |
|
PY_SSL_VERSION_TLS1); |
|
+#if HAVE_TLSv1_2 |
|
+ PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_1", |
|
+ PY_SSL_VERSION_TLS1_1); |
|
+ PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2", |
|
+ PY_SSL_VERSION_TLS1_2); |
|
+#endif |
|
+ |
|
+ /* protocol options */ |
|
+ PyModule_AddIntConstant(m, "OP_ALL", |
|
+ SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); |
|
+ PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); |
|
+ PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); |
|
+ PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); |
|
+#if HAVE_TLSv1_2 |
|
+ PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); |
|
+ PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); |
|
+#endif |
|
+ PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE", |
|
+ SSL_OP_CIPHER_SERVER_PREFERENCE); |
|
+ PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); |
|
+#ifdef SSL_OP_SINGLE_ECDH_USE |
|
+ PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE); |
|
+#endif |
|
+#ifdef SSL_OP_NO_COMPRESSION |
|
+ PyModule_AddIntConstant(m, "OP_NO_COMPRESSION", |
|
+ SSL_OP_NO_COMPRESSION); |
|
+#endif |
|
+ |
|
+#if HAVE_SNI |
|
+ r = Py_True; |
|
+#else |
|
+ r = Py_False; |
|
+#endif |
|
+ Py_INCREF(r); |
|
+ PyModule_AddObject(m, "HAS_SNI", r); |
|
+ |
|
+#if HAVE_OPENSSL_FINISHED |
|
+ r = Py_True; |
|
+#else |
|
+ r = Py_False; |
|
+#endif |
|
+ Py_INCREF(r); |
|
+ PyModule_AddObject(m, "HAS_TLS_UNIQUE", r); |
|
+ |
|
+#ifdef OPENSSL_NO_ECDH |
|
+ r = Py_False; |
|
+#else |
|
+ r = Py_True; |
|
+#endif |
|
+ Py_INCREF(r); |
|
+ PyModule_AddObject(m, "HAS_ECDH", r); |
|
+ |
|
+#ifdef OPENSSL_NPN_NEGOTIATED |
|
+ r = Py_True; |
|
+#else |
|
+ r = Py_False; |
|
+#endif |
|
+ Py_INCREF(r); |
|
+ PyModule_AddObject(m, "HAS_NPN", r); |
|
+ |
|
+ /* Mappings for error codes */ |
|
+ err_codes_to_names = PyDict_New(); |
|
+ err_names_to_codes = PyDict_New(); |
|
+ if (err_codes_to_names == NULL || err_names_to_codes == NULL) |
|
+ return; |
|
+ errcode = error_codes; |
|
+ while (errcode->mnemonic != NULL) { |
|
+ PyObject *mnemo, *key; |
|
+ mnemo = PyUnicode_FromString(errcode->mnemonic); |
|
+ key = Py_BuildValue("ii", errcode->library, errcode->reason); |
|
+ if (mnemo == NULL || key == NULL) |
|
+ return; |
|
+ if (PyDict_SetItem(err_codes_to_names, key, mnemo)) |
|
+ return; |
|
+ if (PyDict_SetItem(err_names_to_codes, mnemo, key)) |
|
+ return; |
|
+ Py_DECREF(key); |
|
+ Py_DECREF(mnemo); |
|
+ errcode++; |
|
+ } |
|
+ if (PyModule_AddObject(m, "err_codes_to_names", err_codes_to_names)) |
|
+ return; |
|
+ if (PyModule_AddObject(m, "err_names_to_codes", err_names_to_codes)) |
|
+ return; |
|
+ |
|
+ lib_codes_to_names = PyDict_New(); |
|
+ if (lib_codes_to_names == NULL) |
|
+ return; |
|
+ libcode = library_codes; |
|
+ while (libcode->library != NULL) { |
|
+ PyObject *mnemo, *key; |
|
+ key = PyLong_FromLong(libcode->code); |
|
+ mnemo = PyUnicode_FromString(libcode->library); |
|
+ if (key == NULL || mnemo == NULL) |
|
+ return; |
|
+ if (PyDict_SetItem(lib_codes_to_names, key, mnemo)) |
|
+ return; |
|
+ Py_DECREF(key); |
|
+ Py_DECREF(mnemo); |
|
+ libcode++; |
|
+ } |
|
+ if (PyModule_AddObject(m, "lib_codes_to_names", lib_codes_to_names)) |
|
+ return; |
|
|
|
/* OpenSSL version */ |
|
/* SSLeay() gives us the version of the library linked against, |
|
@@ -1805,19 +4078,17 @@ init_ssl(void) |
|
return; |
|
if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) |
|
return; |
|
- status = libver & 0xF; |
|
- libver >>= 4; |
|
- patch = libver & 0xFF; |
|
- libver >>= 8; |
|
- fix = libver & 0xFF; |
|
- libver >>= 8; |
|
- minor = libver & 0xFF; |
|
- libver >>= 8; |
|
- major = libver & 0xFF; |
|
+ parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); |
|
r = Py_BuildValue("IIIII", major, minor, fix, patch, status); |
|
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) |
|
return; |
|
r = PyString_FromString(SSLeay_version(SSLEAY_VERSION)); |
|
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) |
|
return; |
|
+ |
|
+ libver = OPENSSL_VERSION_NUMBER; |
|
+ parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); |
|
+ r = Py_BuildValue("IIIII", major, minor, fix, patch, status); |
|
+ if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) |
|
+ return; |
|
} |
|
diff --git a/Lib/ssl.py b/Lib/ssl.py |
|
--- a/Lib/ssl.py |
|
+++ b/Lib/ssl.py |
|
@@ -1,8 +1,7 @@ |
|
# Wrapper module for _ssl, providing some additional facilities |
|
# implemented in Python. Written by Bill Janssen. |
|
|
|
-"""\ |
|
-This module provides some more Pythonic support for SSL. |
|
+"""This module provides some more Pythonic support for SSL. |
|
|
|
Object types: |
|
|
|
@@ -53,62 +52,461 @@ PROTOCOL_SSLv2 |
|
PROTOCOL_SSLv3 |
|
PROTOCOL_SSLv23 |
|
PROTOCOL_TLSv1 |
|
+PROTOCOL_TLSv1_1 |
|
+PROTOCOL_TLSv1_2 |
|
+ |
|
+The following constants identify various SSL alert message descriptions as per |
|
+http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6 |
|
+ |
|
+ALERT_DESCRIPTION_CLOSE_NOTIFY |
|
+ALERT_DESCRIPTION_UNEXPECTED_MESSAGE |
|
+ALERT_DESCRIPTION_BAD_RECORD_MAC |
|
+ALERT_DESCRIPTION_RECORD_OVERFLOW |
|
+ALERT_DESCRIPTION_DECOMPRESSION_FAILURE |
|
+ALERT_DESCRIPTION_HANDSHAKE_FAILURE |
|
+ALERT_DESCRIPTION_BAD_CERTIFICATE |
|
+ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE |
|
+ALERT_DESCRIPTION_CERTIFICATE_REVOKED |
|
+ALERT_DESCRIPTION_CERTIFICATE_EXPIRED |
|
+ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN |
|
+ALERT_DESCRIPTION_ILLEGAL_PARAMETER |
|
+ALERT_DESCRIPTION_UNKNOWN_CA |
|
+ALERT_DESCRIPTION_ACCESS_DENIED |
|
+ALERT_DESCRIPTION_DECODE_ERROR |
|
+ALERT_DESCRIPTION_DECRYPT_ERROR |
|
+ALERT_DESCRIPTION_PROTOCOL_VERSION |
|
+ALERT_DESCRIPTION_INSUFFICIENT_SECURITY |
|
+ALERT_DESCRIPTION_INTERNAL_ERROR |
|
+ALERT_DESCRIPTION_USER_CANCELLED |
|
+ALERT_DESCRIPTION_NO_RENEGOTIATION |
|
+ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION |
|
+ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE |
|
+ALERT_DESCRIPTION_UNRECOGNIZED_NAME |
|
+ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE |
|
+ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE |
|
+ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY |
|
""" |
|
|
|
import textwrap |
|
+import re |
|
+import sys |
|
+import os |
|
+from collections import namedtuple |
|
+from contextlib import closing |
|
|
|
import _ssl # if we can't import it, let the error propagate |
|
|
|
from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION |
|
-from _ssl import SSLError |
|
+from _ssl import _SSLContext |
|
+from _ssl import ( |
|
+ SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError, |
|
+ SSLSyscallError, SSLEOFError, |
|
+ ) |
|
from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED |
|
+from _ssl import (VERIFY_DEFAULT, VERIFY_CRL_CHECK_LEAF, VERIFY_CRL_CHECK_CHAIN, |
|
+ VERIFY_X509_STRICT) |
|
+from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj |
|
from _ssl import RAND_status, RAND_egd, RAND_add |
|
-from _ssl import \ |
|
- SSL_ERROR_ZERO_RETURN, \ |
|
- SSL_ERROR_WANT_READ, \ |
|
- SSL_ERROR_WANT_WRITE, \ |
|
- SSL_ERROR_WANT_X509_LOOKUP, \ |
|
- SSL_ERROR_SYSCALL, \ |
|
- SSL_ERROR_SSL, \ |
|
- SSL_ERROR_WANT_CONNECT, \ |
|
- SSL_ERROR_EOF, \ |
|
- SSL_ERROR_INVALID_ERROR_CODE |
|
-from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 |
|
-_PROTOCOL_NAMES = { |
|
- PROTOCOL_TLSv1: "TLSv1", |
|
- PROTOCOL_SSLv23: "SSLv23", |
|
- PROTOCOL_SSLv3: "SSLv3", |
|
-} |
|
+ |
|
+def _import_symbols(prefix): |
|
+ for n in dir(_ssl): |
|
+ if n.startswith(prefix): |
|
+ globals()[n] = getattr(_ssl, n) |
|
+ |
|
+_import_symbols('OP_') |
|
+_import_symbols('ALERT_DESCRIPTION_') |
|
+_import_symbols('SSL_ERROR_') |
|
+_import_symbols('PROTOCOL_') |
|
+ |
|
+from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN |
|
+ |
|
+from _ssl import _OPENSSL_API_VERSION |
|
+ |
|
+_PROTOCOL_NAMES = {value: name for name, value in globals().items() if name.startswith('PROTOCOL_')} |
|
+ |
|
try: |
|
- from _ssl import PROTOCOL_SSLv2 |
|
_SSLv2_IF_EXISTS = PROTOCOL_SSLv2 |
|
-except ImportError: |
|
+except NameError: |
|
_SSLv2_IF_EXISTS = None |
|
-else: |
|
- _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" |
|
|
|
from socket import socket, _fileobject, _delegate_methods, error as socket_error |
|
-from socket import getnameinfo as _getnameinfo |
|
-from socket import SOL_SOCKET, SO_TYPE, SOCK_STREAM |
|
+if sys.platform == "win32": |
|
+ from _ssl import enum_certificates, enum_crls |
|
+ |
|
+from socket import socket, AF_INET, SOCK_STREAM, create_connection |
|
+from socket import SOL_SOCKET, SO_TYPE |
|
import base64 # for DER-to-PEM translation |
|
import errno |
|
|
|
+if _ssl.HAS_TLS_UNIQUE: |
|
+ CHANNEL_BINDING_TYPES = ['tls-unique'] |
|
+else: |
|
+ CHANNEL_BINDING_TYPES = [] |
|
+ |
|
# Disable weak or insecure ciphers by default |
|
# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL') |
|
-_DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2' |
|
+# Enable a better set of ciphers by default |
|
+# This list has been explicitly chosen to: |
|
+# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) |
|
+# * Prefer ECDHE over DHE for better performance |
|
+# * Prefer any AES-GCM over any AES-CBC for better performance and security |
|
+# * Then Use HIGH cipher suites as a fallback |
|
+# * Then Use 3DES as fallback which is secure but slow |
|
+# * Finally use RC4 as a fallback which is problematic but needed for |
|
+# compatibility some times. |
|
+# * Disable NULL authentication, NULL encryption, and MD5 MACs for security |
|
+# reasons |
|
+_DEFAULT_CIPHERS = ( |
|
+ 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' |
|
+ 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' |
|
+ 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' |
|
+) |
|
|
|
+# Restricted and more secure ciphers for the server side |
|
+# This list has been explicitly chosen to: |
|
+# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) |
|
+# * Prefer ECDHE over DHE for better performance |
|
+# * Prefer any AES-GCM over any AES-CBC for better performance and security |
|
+# * Then Use HIGH cipher suites as a fallback |
|
+# * Then Use 3DES as fallback which is secure but slow |
|
+# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, and RC4 for |
|
+# security reasons |
|
+_RESTRICTED_SERVER_CIPHERS = ( |
|
+ 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' |
|
+ 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' |
|
+ '!eNULL:!MD5:!DSS:!RC4' |
|
+) |
|
+ |
|
+ |
|
+class CertificateError(ValueError): |
|
+ pass |
|
+ |
|
+ |
|
+def _dnsname_match(dn, hostname, max_wildcards=1): |
|
+ """Matching according to RFC 6125, section 6.4.3 |
|
+ |
|
+ http://tools.ietf.org/html/rfc6125#section-6.4.3 |
|
+ """ |
|
+ pats = [] |
|
+ if not dn: |
|
+ return False |
|
+ |
|
+ pieces = dn.split(r'.') |
|
+ leftmost = pieces[0] |
|
+ remainder = pieces[1:] |
|
+ |
|
+ wildcards = leftmost.count('*') |
|
+ if wildcards > max_wildcards: |
|
+ # Issue #17980: avoid denials of service by refusing more |
|
+ # than one wildcard per fragment. A survery of established |
|
+ # policy among SSL implementations showed it to be a |
|
+ # reasonable choice. |
|
+ raise CertificateError( |
|
+ "too many wildcards in certificate DNS name: " + repr(dn)) |
|
+ |
|
+ # speed up common case w/o wildcards |
|
+ if not wildcards: |
|
+ return dn.lower() == hostname.lower() |
|
+ |
|
+ # RFC 6125, section 6.4.3, subitem 1. |
|
+ # The client SHOULD NOT attempt to match a presented identifier in which |
|
+ # the wildcard character comprises a label other than the left-most label. |
|
+ if leftmost == '*': |
|
+ # When '*' is a fragment by itself, it matches a non-empty dotless |
|
+ # fragment. |
|
+ pats.append('[^.]+') |
|
+ elif leftmost.startswith('xn--') or hostname.startswith('xn--'): |
|
+ # RFC 6125, section 6.4.3, subitem 3. |
|
+ # The client SHOULD NOT attempt to match a presented identifier |
|
+ # where the wildcard character is embedded within an A-label or |
|
+ # U-label of an internationalized domain name. |
|
+ pats.append(re.escape(leftmost)) |
|
+ else: |
|
+ # Otherwise, '*' matches any dotless string, e.g. www* |
|
+ pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) |
|
+ |
|
+ # add the remaining fragments, ignore any wildcards |
|
+ for frag in remainder: |
|
+ pats.append(re.escape(frag)) |
|
+ |
|
+ pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) |
|
+ return pat.match(hostname) |
|
+ |
|
+ |
|
+def match_hostname(cert, hostname): |
|
+ """Verify that *cert* (in decoded format as returned by |
|
+ SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 |
|
+ rules are followed, but IP addresses are not accepted for *hostname*. |
|
+ |
|
+ CertificateError is raised on failure. On success, the function |
|
+ returns nothing. |
|
+ """ |
|
+ if not cert: |
|
+ raise ValueError("empty or no certificate, match_hostname needs a " |
|
+ "SSL socket or SSL context with either " |
|
+ "CERT_OPTIONAL or CERT_REQUIRED") |
|
+ dnsnames = [] |
|
+ san = cert.get('subjectAltName', ()) |
|
+ for key, value in san: |
|
+ if key == 'DNS': |
|
+ if _dnsname_match(value, hostname): |
|
+ return |
|
+ dnsnames.append(value) |
|
+ if not dnsnames: |
|
+ # The subject is only checked when there is no dNSName entry |
|
+ # in subjectAltName |
|
+ for sub in cert.get('subject', ()): |
|
+ for key, value in sub: |
|
+ # XXX according to RFC 2818, the most specific Common Name |
|
+ # must be used. |
|
+ if key == 'commonName': |
|
+ if _dnsname_match(value, hostname): |
|
+ return |
|
+ dnsnames.append(value) |
|
+ if len(dnsnames) > 1: |
|
+ raise CertificateError("hostname %r " |
|
+ "doesn't match either of %s" |
|
+ % (hostname, ', '.join(map(repr, dnsnames)))) |
|
+ elif len(dnsnames) == 1: |
|
+ raise CertificateError("hostname %r " |
|
+ "doesn't match %r" |
|
+ % (hostname, dnsnames[0])) |
|
+ else: |
|
+ raise CertificateError("no appropriate commonName or " |
|
+ "subjectAltName fields were found") |
|
+ |
|
+ |
|
+DefaultVerifyPaths = namedtuple("DefaultVerifyPaths", |
|
+ "cafile capath openssl_cafile_env openssl_cafile openssl_capath_env " |
|
+ "openssl_capath") |
|
+ |
|
+def get_default_verify_paths(): |
|
+ """Return paths to default cafile and capath. |
|
+ """ |
|
+ parts = _ssl.get_default_verify_paths() |
|
+ |
|
+ # environment vars shadow paths |
|
+ cafile = os.environ.get(parts[0], parts[1]) |
|
+ capath = os.environ.get(parts[2], parts[3]) |
|
+ |
|
+ return DefaultVerifyPaths(cafile if os.path.isfile(cafile) else None, |
|
+ capath if os.path.isdir(capath) else None, |
|
+ *parts) |
|
+ |
|
+ |
|
+class _ASN1Object(namedtuple("_ASN1Object", "nid shortname longname oid")): |
|
+ """ASN.1 object identifier lookup |
|
+ """ |
|
+ __slots__ = () |
|
+ |
|
+ def __new__(cls, oid): |
|
+ return super(_ASN1Object, cls).__new__(cls, *_txt2obj(oid, name=False)) |
|
+ |
|
+ @classmethod |
|
+ def fromnid(cls, nid): |
|
+ """Create _ASN1Object from OpenSSL numeric ID |
|
+ """ |
|
+ return super(_ASN1Object, cls).__new__(cls, *_nid2obj(nid)) |
|
+ |
|
+ @classmethod |
|
+ def fromname(cls, name): |
|
+ """Create _ASN1Object from short name, long name or OID |
|
+ """ |
|
+ return super(_ASN1Object, cls).__new__(cls, *_txt2obj(name, name=True)) |
|
+ |
|
+ |
|
+class Purpose(_ASN1Object): |
|
+ """SSLContext purpose flags with X509v3 Extended Key Usage objects |
|
+ """ |
|
+ |
|
+Purpose.SERVER_AUTH = Purpose('1.3.6.1.5.5.7.3.1') |
|
+Purpose.CLIENT_AUTH = Purpose('1.3.6.1.5.5.7.3.2') |
|
+ |
|
+ |
|
+class SSLContext(_SSLContext): |
|
+ """An SSLContext holds various SSL-related configuration options and |
|
+ data, such as certificates and possibly a private key.""" |
|
+ |
|
+ __slots__ = ('protocol', '__weakref__') |
|
+ _windows_cert_stores = ("CA", "ROOT") |
|
+ |
|
+ def __new__(cls, protocol, *args, **kwargs): |
|
+ self = _SSLContext.__new__(cls, protocol) |
|
+ if protocol != _SSLv2_IF_EXISTS: |
|
+ self.set_ciphers(_DEFAULT_CIPHERS) |
|
+ return self |
|
+ |
|
+ def __init__(self, protocol): |
|
+ self.protocol = protocol |
|
+ |
|
+ def wrap_socket(self, sock, server_side=False, |
|
+ do_handshake_on_connect=True, |
|
+ suppress_ragged_eofs=True, |
|
+ server_hostname=None): |
|
+ return SSLSocket(sock=sock, server_side=server_side, |
|
+ do_handshake_on_connect=do_handshake_on_connect, |
|
+ suppress_ragged_eofs=suppress_ragged_eofs, |
|
+ server_hostname=server_hostname, |
|
+ _context=self) |
|
+ |
|
+ def set_npn_protocols(self, npn_protocols): |
|
+ protos = bytearray() |
|
+ for protocol in npn_protocols: |
|
+ b = protocol.encode('ascii') |
|
+ if len(b) == 0 or len(b) > 255: |
|
+ raise SSLError('NPN protocols must be 1 to 255 in length') |
|
+ protos.append(len(b)) |
|
+ protos.extend(b) |
|
+ |
|
+ self._set_npn_protocols(protos) |
|
+ |
|
+ def _load_windows_store_certs(self, storename, purpose): |
|
+ certs = bytearray() |
|
+ for cert, encoding, trust in enum_certificates(storename): |
|
+ # CA certs are never PKCS#7 encoded |
|
+ if encoding == "x509_asn": |
|
+ if trust is True or purpose.oid in trust: |
|
+ certs.extend(cert) |
|
+ self.load_verify_locations(cadata=certs) |
|
+ return certs |
|
+ |
|
+ def load_default_certs(self, purpose=Purpose.SERVER_AUTH): |
|
+ if not isinstance(purpose, _ASN1Object): |
|
+ raise TypeError(purpose) |
|
+ if sys.platform == "win32": |
|
+ for storename in self._windows_cert_stores: |
|
+ self._load_windows_store_certs(storename, purpose) |
|
+ else: |
|
+ self.set_default_verify_paths() |
|
+ |
|
+ |
|
+def create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, |
|
+ capath=None, cadata=None): |
|
+ """Create a SSLContext object with default settings. |
|
+ |
|
+ NOTE: The protocol and settings may change anytime without prior |
|
+ deprecation. The values represent a fair balance between maximum |
|
+ compatibility and security. |
|
+ """ |
|
+ if not isinstance(purpose, _ASN1Object): |
|
+ raise TypeError(purpose) |
|
+ |
|
+ context = SSLContext(PROTOCOL_SSLv23) |
|
+ |
|
+ # SSLv2 considered harmful. |
|
+ context.options |= OP_NO_SSLv2 |
|
+ |
|
+ # SSLv3 has problematic security and is only required for really old |
|
+ # clients such as IE6 on Windows XP |
|
+ context.options |= OP_NO_SSLv3 |
|
+ |
|
+ # disable compression to prevent CRIME attacks (OpenSSL 1.0+) |
|
+ context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0) |
|
+ |
|
+ if purpose == Purpose.SERVER_AUTH: |
|
+ # verify certs and host name in client mode |
|
+ context.verify_mode = CERT_REQUIRED |
|
+ context.check_hostname = True |
|
+ elif purpose == Purpose.CLIENT_AUTH: |
|
+ # Prefer the server's ciphers by default so that we get stronger |
|
+ # encryption |
|
+ context.options |= getattr(_ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) |
|
+ |
|
+ # Use single use keys in order to improve forward secrecy |
|
+ context.options |= getattr(_ssl, "OP_SINGLE_DH_USE", 0) |
|
+ context.options |= getattr(_ssl, "OP_SINGLE_ECDH_USE", 0) |
|
+ |
|
+ # disallow ciphers with known vulnerabilities |
|
+ context.set_ciphers(_RESTRICTED_SERVER_CIPHERS) |
|
+ |
|
+ if cafile or capath or cadata: |
|
+ context.load_verify_locations(cafile, capath, cadata) |
|
+ elif context.verify_mode != CERT_NONE: |
|
+ # no explicit cafile, capath or cadata but the verify mode is |
|
+ # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system |
|
+ # root CA certificates for the given purpose. This may fail silently. |
|
+ context.load_default_certs(purpose) |
|
+ return context |
|
+ |
|
+ |
|
+def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, |
|
+ check_hostname=False, purpose=Purpose.SERVER_AUTH, |
|
+ certfile=None, keyfile=None, |
|
+ cafile=None, capath=None, cadata=None): |
|
+ """Create a SSLContext object for Python stdlib modules |
|
+ |
|
+ All Python stdlib modules shall use this function to create SSLContext |
|
+ objects in order to keep common settings in one place. The configuration |
|
+ is less restrict than create_default_context()'s to increase backward |
|
+ compatibility. |
|
+ """ |
|
+ if not isinstance(purpose, _ASN1Object): |
|
+ raise TypeError(purpose) |
|
+ |
|
+ context = SSLContext(protocol) |
|
+ # SSLv2 considered harmful. |
|
+ context.options |= OP_NO_SSLv2 |
|
+ |
|
+ if cert_reqs is not None: |
|
+ context.verify_mode = cert_reqs |
|
+ context.check_hostname = check_hostname |
|
+ |
|
+ if keyfile and not certfile: |
|
+ raise ValueError("certfile must be specified") |
|
+ if certfile or keyfile: |
|
+ context.load_cert_chain(certfile, keyfile) |
|
+ |
|
+ # load CA root certs |
|
+ if cafile or capath or cadata: |
|
+ context.load_verify_locations(cafile, capath, cadata) |
|
+ elif context.verify_mode != CERT_NONE: |
|
+ # no explicit cafile, capath or cadata but the verify mode is |
|
+ # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system |
|
+ # root CA certificates for the given purpose. This may fail silently. |
|
+ context.load_default_certs(purpose) |
|
+ |
|
+ return context |
|
|
|
class SSLSocket(socket): |
|
- |
|
"""This class implements a subtype of socket.socket that wraps |
|
the underlying OS socket in an SSL context when necessary, and |
|
provides read and write methods over that channel.""" |
|
|
|
- def __init__(self, sock, keyfile=None, certfile=None, |
|
+ def __init__(self, sock=None, keyfile=None, certfile=None, |
|
server_side=False, cert_reqs=CERT_NONE, |
|
ssl_version=PROTOCOL_SSLv23, ca_certs=None, |
|
do_handshake_on_connect=True, |
|
- suppress_ragged_eofs=True, ciphers=None): |
|
+ family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None, |
|
+ suppress_ragged_eofs=True, npn_protocols=None, ciphers=None, |
|
+ server_hostname=None, |
|
+ _context=None): |
|
+ |
|
+ if _context: |
|
+ self._context = _context |
|
+ else: |
|
+ if server_side and not certfile: |
|
+ raise ValueError("certfile must be specified for server-side " |
|
+ "operations") |
|
+ if keyfile and not certfile: |
|
+ raise ValueError("certfile must be specified") |
|
+ if certfile and not keyfile: |
|
+ keyfile = certfile |
|
+ self._context = SSLContext(ssl_version) |
|
+ self._context.verify_mode = cert_reqs |
|
+ if ca_certs: |
|
+ self._context.load_verify_locations(ca_certs) |
|
+ if certfile: |
|
+ self._context.load_cert_chain(certfile, keyfile) |
|
+ if npn_protocols: |
|
+ self._context.set_npn_protocols(npn_protocols) |
|
+ if ciphers: |
|
+ self._context.set_ciphers(ciphers) |
|
+ self.keyfile = keyfile |
|
+ self.certfile = certfile |
|
+ self.cert_reqs = cert_reqs |
|
+ self.ssl_version = ssl_version |
|
+ self.ca_certs = ca_certs |
|
+ self.ciphers = ciphers |
|
# Can't use sock.type as other flags (such as SOCK_NONBLOCK) get |
|
# mixed in. |
|
if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM: |
|
@@ -122,98 +520,161 @@ class SSLSocket(socket): |
|
delattr(self, attr) |
|
except AttributeError: |
|
pass |
|
+ if server_side and server_hostname: |
|
+ raise ValueError("server_hostname can only be specified " |
|
+ "in client mode") |
|
+ if self._context.check_hostname and not server_hostname: |
|
+ if HAS_SNI: |
|
+ raise ValueError("check_hostname requires server_hostname") |
|
+ else: |
|
+ raise ValueError("check_hostname requires server_hostname, " |
|
+ "but it's not supported by your OpenSSL " |
|
+ "library") |
|
+ self.server_side = server_side |
|
+ self.server_hostname = server_hostname |
|
+ self.do_handshake_on_connect = do_handshake_on_connect |
|
+ self.suppress_ragged_eofs = suppress_ragged_eofs |
|
|
|
- if ciphers is None and ssl_version != _SSLv2_IF_EXISTS: |
|
- ciphers = _DEFAULT_CIPHERS |
|
- |
|
- if certfile and not keyfile: |
|
- keyfile = certfile |
|
- # see if it's connected |
|
+ # See if we are connected |
|
try: |
|
- socket.getpeername(self) |
|
- except socket_error, e: |
|
+ self.getpeername() |
|
+ except socket_error as e: |
|
if e.errno != errno.ENOTCONN: |
|
raise |
|
- # no, no connection yet |
|
- self._connected = False |
|
- self._sslobj = None |
|
+ connected = False |
|
else: |
|
- # yes, create the SSL object |
|
- self._connected = True |
|
- self._sslobj = _ssl.sslwrap(self._sock, server_side, |
|
- keyfile, certfile, |
|
- cert_reqs, ssl_version, ca_certs, |
|
- ciphers) |
|
- if do_handshake_on_connect: |
|
- self.do_handshake() |
|
- self.keyfile = keyfile |
|
- self.certfile = certfile |
|
- self.cert_reqs = cert_reqs |
|
- self.ssl_version = ssl_version |
|
- self.ca_certs = ca_certs |
|
- self.ciphers = ciphers |
|
- self.do_handshake_on_connect = do_handshake_on_connect |
|
- self.suppress_ragged_eofs = suppress_ragged_eofs |
|
+ connected = True |
|
+ |
|
+ self._closed = False |
|
+ self._sslobj = None |
|
+ self._connected = connected |
|
+ if connected: |
|
+ # create the SSL object |
|
+ try: |
|
+ self._sslobj = self._context._wrap_socket(self._sock, server_side, |
|
+ server_hostname, ssl_sock=self) |
|
+ if do_handshake_on_connect: |
|
+ timeout = self.gettimeout() |
|
+ if timeout == 0.0: |
|
+ # non-blocking |
|
+ raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets") |
|
+ self.do_handshake() |
|
+ |
|
+ except (OSError, ValueError): |
|
+ self.close() |
|
+ raise |
|
self._makefile_refs = 0 |
|
|
|
- def read(self, len=1024): |
|
+ @property |
|
+ def context(self): |
|
+ return self._context |
|
|
|
+ @context.setter |
|
+ def context(self, ctx): |
|
+ self._context = ctx |
|
+ self._sslobj.context = ctx |
|
+ |
|
+ def dup(self): |
|
+ raise NotImplemented("Can't dup() %s instances" % |
|
+ self.__class__.__name__) |
|
+ |
|
+ def _checkClosed(self, msg=None): |
|
+ # raise an exception here if you wish to check for spurious closes |
|
+ pass |
|
+ |
|
+ def _check_connected(self): |
|
+ if not self._connected: |
|
+ # getpeername() will raise ENOTCONN if the socket is really |
|
+ # not connected; note that we can be connected even without |
|
+ # _connected being set, e.g. if connect() first returned |
|
+ # EAGAIN. |
|
+ self.getpeername() |
|
+ |
|
+ def read(self, len=0, buffer=None): |
|
"""Read up to LEN bytes and return them. |
|
Return zero-length string on EOF.""" |
|
|
|
+ self._checkClosed() |
|
+ if not self._sslobj: |
|
+ raise ValueError("Read on closed or unwrapped SSL socket.") |
|
try: |
|
- return self._sslobj.read(len) |
|
- except SSLError, x: |
|
+ if buffer is not None: |
|
+ v = self._sslobj.read(len, buffer) |
|
+ else: |
|
+ v = self._sslobj.read(len or 1024) |
|
+ return v |
|
+ except SSLError as x: |
|
if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: |
|
- return '' |
|
+ if buffer is not None: |
|
+ return 0 |
|
+ else: |
|
+ return b'' |
|
else: |
|
raise |
|
|
|
def write(self, data): |
|
- |
|
"""Write DATA to the underlying SSL channel. Returns |
|
number of bytes of DATA actually transmitted.""" |
|
|
|
+ self._checkClosed() |
|
+ if not self._sslobj: |
|
+ raise ValueError("Write on closed or unwrapped SSL socket.") |
|
return self._sslobj.write(data) |
|
|
|
def getpeercert(self, binary_form=False): |
|
- |
|
"""Returns a formatted version of the data in the |
|
certificate provided by the other end of the SSL channel. |
|
Return None if no certificate was provided, {} if a |
|
certificate was provided, but not validated.""" |
|
|
|
+ self._checkClosed() |
|
+ self._check_connected() |
|
return self._sslobj.peer_certificate(binary_form) |
|
|
|
+ def selected_npn_protocol(self): |
|
+ self._checkClosed() |
|
+ if not self._sslobj or not _ssl.HAS_NPN: |
|
+ return None |
|
+ else: |
|
+ return self._sslobj.selected_npn_protocol() |
|
+ |
|
def cipher(self): |
|
- |
|
+ self._checkClosed() |
|
if not self._sslobj: |
|
return None |
|
else: |
|
return self._sslobj.cipher() |
|
|
|
+ def compression(self): |
|
+ self._checkClosed() |
|
+ if not self._sslobj: |
|
+ return None |
|
+ else: |
|
+ return self._sslobj.compression() |
|
+ |
|
def send(self, data, flags=0): |
|
+ self._checkClosed() |
|
if self._sslobj: |
|
if flags != 0: |
|
raise ValueError( |
|
"non-zero flags not allowed in calls to send() on %s" % |
|
self.__class__) |
|
- while True: |
|
- try: |
|
- v = self._sslobj.write(data) |
|
- except SSLError, x: |
|
- if x.args[0] == SSL_ERROR_WANT_READ: |
|
- return 0 |
|
- elif x.args[0] == SSL_ERROR_WANT_WRITE: |
|
- return 0 |
|
- else: |
|
- raise |
|
+ try: |
|
+ v = self._sslobj.write(data) |
|
+ except SSLError as x: |
|
+ if x.args[0] == SSL_ERROR_WANT_READ: |
|
+ return 0 |
|
+ elif x.args[0] == SSL_ERROR_WANT_WRITE: |
|
+ return 0 |
|
else: |
|
- return v |
|
+ raise |
|
+ else: |
|
+ return v |
|
else: |
|
return self._sock.send(data, flags) |
|
|
|
def sendto(self, data, flags_or_addr, addr=None): |
|
+ self._checkClosed() |
|
if self._sslobj: |
|
raise ValueError("sendto not allowed on instances of %s" % |
|
self.__class__) |
|
@@ -222,7 +683,9 @@ class SSLSocket(socket): |
|
else: |
|
return self._sock.sendto(data, flags_or_addr, addr) |
|
|
|
+ |
|
def sendall(self, data, flags=0): |
|
+ self._checkClosed() |
|
if self._sslobj: |
|
if flags != 0: |
|
raise ValueError( |
|
@@ -238,6 +701,7 @@ class SSLSocket(socket): |
|
return socket.sendall(self, data, flags) |
|
|
|
def recv(self, buflen=1024, flags=0): |
|
+ self._checkClosed() |
|
if self._sslobj: |
|
if flags != 0: |
|
raise ValueError( |
|
@@ -248,6 +712,7 @@ class SSLSocket(socket): |
|
return self._sock.recv(buflen, flags) |
|
|
|
def recv_into(self, buffer, nbytes=None, flags=0): |
|
+ self._checkClosed() |
|
if buffer and (nbytes is None): |
|
nbytes = len(buffer) |
|
elif nbytes is None: |
|
@@ -257,14 +722,12 @@ class SSLSocket(socket): |
|
raise ValueError( |
|
"non-zero flags not allowed in calls to recv_into() on %s" % |
|
self.__class__) |
|
- tmp_buffer = self.read(nbytes) |
|
- v = len(tmp_buffer) |
|
- buffer[:v] = tmp_buffer |
|
- return v |
|
+ return self.read(nbytes, buffer) |
|
else: |
|
return self._sock.recv_into(buffer, nbytes, flags) |
|
|
|
def recvfrom(self, buflen=1024, flags=0): |
|
+ self._checkClosed() |
|
if self._sslobj: |
|
raise ValueError("recvfrom not allowed on instances of %s" % |
|
self.__class__) |
|
@@ -272,27 +735,23 @@ class SSLSocket(socket): |
|
return self._sock.recvfrom(buflen, flags) |
|
|
|
def recvfrom_into(self, buffer, nbytes=None, flags=0): |
|
+ self._checkClosed() |
|
if self._sslobj: |
|
raise ValueError("recvfrom_into not allowed on instances of %s" % |
|
self.__class__) |
|
else: |
|
return self._sock.recvfrom_into(buffer, nbytes, flags) |
|
|
|
+ |
|
def pending(self): |
|
+ self._checkClosed() |
|
if self._sslobj: |
|
return self._sslobj.pending() |
|
else: |
|
return 0 |
|
|
|
- def unwrap(self): |
|
- if self._sslobj: |
|
- s = self._sslobj.shutdown() |
|
- self._sslobj = None |
|
- return s |
|
- else: |
|
- raise ValueError("No SSL wrapper around " + str(self)) |
|
- |
|
def shutdown(self, how): |
|
+ self._checkClosed() |
|
self._sslobj = None |
|
socket.shutdown(self, how) |
|
|
|
@@ -303,32 +762,55 @@ class SSLSocket(socket): |
|
else: |
|
self._makefile_refs -= 1 |
|
|
|
- def do_handshake(self): |
|
+ def unwrap(self): |
|
+ if self._sslobj: |
|
+ s = self._sslobj.shutdown() |
|
+ self._sslobj = None |
|
+ return s |
|
+ else: |
|
+ raise ValueError("No SSL wrapper around " + str(self)) |
|
|
|
+ def _real_close(self): |
|
+ self._sslobj = None |
|
+ socket._real_close(self) |
|
+ |
|
+ def do_handshake(self, block=False): |
|
"""Perform a TLS/SSL handshake.""" |
|
+ self._check_connected() |
|
+ timeout = self.gettimeout() |
|
+ try: |
|
+ if timeout == 0.0 and block: |
|
+ self.settimeout(None) |
|
+ self._sslobj.do_handshake() |
|
+ finally: |
|
+ self.settimeout(timeout) |
|
|
|
- self._sslobj.do_handshake() |
|
+ if self.context.check_hostname: |
|
+ if not self.server_hostname: |
|
+ raise ValueError("check_hostname needs server_hostname " |
|
+ "argument") |
|
+ match_hostname(self.getpeercert(), self.server_hostname) |
|
|
|
- def _real_connect(self, addr, return_errno): |
|
+ def _real_connect(self, addr, connect_ex): |
|
+ if self.server_side: |
|
+ raise ValueError("can't connect in server-side mode") |
|
# Here we assume that the socket is client-side, and not |
|
# connected at the time of the call. We connect it, then wrap it. |
|
if self._connected: |
|
raise ValueError("attempt to connect already-connected SSLSocket!") |
|
- self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile, |
|
- self.cert_reqs, self.ssl_version, |
|
- self.ca_certs, self.ciphers) |
|
+ self._sslobj = self.context._wrap_socket(self._sock, False, self.server_hostname, ssl_sock=self) |
|
try: |
|
- if return_errno: |
|
+ if connect_ex: |
|
rc = socket.connect_ex(self, addr) |
|
else: |
|
rc = None |
|
socket.connect(self, addr) |
|
if not rc: |
|
+ self._connected = True |
|
if self.do_handshake_on_connect: |
|
self.do_handshake() |
|
- self._connected = True |
|
return rc |
|
- except socket_error: |
|
+ except (OSError, ValueError): |
|
self._sslobj = None |
|
raise |
|
|
|
@@ -343,27 +825,16 @@ class SSLSocket(socket): |
|
return self._real_connect(addr, True) |
|
|
|
def accept(self): |
|
- |
|
"""Accepts a new connection from a remote client, and returns |
|
a tuple containing that new connection wrapped with a server-side |
|
SSL channel, and the address of the remote client.""" |
|
|
|
newsock, addr = socket.accept(self) |
|
- try: |
|
- return (SSLSocket(newsock, |
|
- keyfile=self.keyfile, |
|
- certfile=self.certfile, |
|
- server_side=True, |
|
- cert_reqs=self.cert_reqs, |
|
- ssl_version=self.ssl_version, |
|
- ca_certs=self.ca_certs, |
|
- ciphers=self.ciphers, |
|
- do_handshake_on_connect=self.do_handshake_on_connect, |
|
- suppress_ragged_eofs=self.suppress_ragged_eofs), |
|
- addr) |
|
- except socket_error as e: |
|
- newsock.close() |
|
- raise e |
|
+ newsock = self.context.wrap_socket(newsock, |
|
+ do_handshake_on_connect=self.do_handshake_on_connect, |
|
+ suppress_ragged_eofs=self.suppress_ragged_eofs, |
|
+ server_side=True) |
|
+ return newsock, addr |
|
|
|
def makefile(self, mode='r', bufsize=-1): |
|
|
|
@@ -376,54 +847,81 @@ class SSLSocket(socket): |
|
# the file-like object. |
|
return _fileobject(self, mode, bufsize, close=True) |
|
|
|
+ def get_channel_binding(self, cb_type="tls-unique"): |
|
+ """Get channel binding data for current connection. Raise ValueError |
|
+ if the requested `cb_type` is not supported. Return bytes of the data |
|
+ or None if the data is not available (e.g. before the handshake). |
|
+ """ |
|
+ if cb_type not in CHANNEL_BINDING_TYPES: |
|
+ raise ValueError("Unsupported channel binding type") |
|
+ if cb_type != "tls-unique": |
|
+ raise NotImplementedError( |
|
+ "{0} channel binding type not implemented" |
|
+ .format(cb_type)) |
|
+ if self._sslobj is None: |
|
+ return None |
|
+ return self._sslobj.tls_unique_cb() |
|
|
|
|
|
def wrap_socket(sock, keyfile=None, certfile=None, |
|
server_side=False, cert_reqs=CERT_NONE, |
|
ssl_version=PROTOCOL_SSLv23, ca_certs=None, |
|
do_handshake_on_connect=True, |
|
- suppress_ragged_eofs=True, ciphers=None): |
|
+ suppress_ragged_eofs=True, |
|
+ ciphers=None): |
|
|
|
- return SSLSocket(sock, keyfile=keyfile, certfile=certfile, |
|
+ return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile, |
|
server_side=server_side, cert_reqs=cert_reqs, |
|
ssl_version=ssl_version, ca_certs=ca_certs, |
|
do_handshake_on_connect=do_handshake_on_connect, |
|
suppress_ragged_eofs=suppress_ragged_eofs, |
|
ciphers=ciphers) |
|
|
|
- |
|
# some utility functions |
|
|
|
def cert_time_to_seconds(cert_time): |
|
+ """Return the time in seconds since the Epoch, given the timestring |
|
+ representing the "notBefore" or "notAfter" date from a certificate |
|
+ in ``"%b %d %H:%M:%S %Y %Z"`` strptime format (C locale). |
|
|
|
- """Takes a date-time string in standard ASN1_print form |
|
- ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return |
|
- a Python time value in seconds past the epoch.""" |
|
+ "notBefore" or "notAfter" dates must use UTC (RFC 5280). |
|
|
|
- import time |
|
- return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT")) |
|
+ Month is one of: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec |
|
+ UTC should be specified as GMT (see ASN1_TIME_print()) |
|
+ """ |
|
+ from time import strptime |
|
+ from calendar import timegm |
|
+ |
|
+ months = ( |
|
+ "Jan","Feb","Mar","Apr","May","Jun", |
|
+ "Jul","Aug","Sep","Oct","Nov","Dec" |
|
+ ) |
|
+ time_format = ' %d %H:%M:%S %Y GMT' # NOTE: no month, fixed GMT |
|
+ try: |
|
+ month_number = months.index(cert_time[:3].title()) + 1 |
|
+ except ValueError: |
|
+ raise ValueError('time data %r does not match ' |
|
+ 'format "%%b%s"' % (cert_time, time_format)) |
|
+ else: |
|
+ # found valid month |
|
+ tt = strptime(cert_time[3:], time_format) |
|
+ # return an integer, the previous mktime()-based implementation |
|
+ # returned a float (fractional seconds are always zero here). |
|
+ return timegm((tt[0], month_number) + tt[2:6]) |
|
|
|
PEM_HEADER = "-----BEGIN CERTIFICATE-----" |
|
PEM_FOOTER = "-----END CERTIFICATE-----" |
|
|
|
def DER_cert_to_PEM_cert(der_cert_bytes): |
|
- |
|
"""Takes a certificate in binary DER format and returns the |
|
PEM version of it as a string.""" |
|
|
|
- if hasattr(base64, 'standard_b64encode'): |
|
- # preferred because older API gets line-length wrong |
|
- f = base64.standard_b64encode(der_cert_bytes) |
|
- return (PEM_HEADER + '\n' + |
|
- textwrap.fill(f, 64) + '\n' + |
|
- PEM_FOOTER + '\n') |
|
- else: |
|
- return (PEM_HEADER + '\n' + |
|
- base64.encodestring(der_cert_bytes) + |
|
- PEM_FOOTER + '\n') |
|
+ f = base64.standard_b64encode(der_cert_bytes).decode('ascii') |
|
+ return (PEM_HEADER + '\n' + |
|
+ textwrap.fill(f, 64) + '\n' + |
|
+ PEM_FOOTER + '\n') |
|
|
|
def PEM_cert_to_DER_cert(pem_cert_string): |
|
- |
|
"""Takes a certificate in ASCII PEM format and returns the |
|
DER-encoded version of it as a byte sequence""" |
|
|
|
@@ -434,25 +932,25 @@ def PEM_cert_to_DER_cert(pem_cert_string |
|
raise ValueError("Invalid PEM encoding; must end with %s" |
|
% PEM_FOOTER) |
|
d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)] |
|
- return base64.decodestring(d) |
|
+ return base64.decodestring(d.encode('ASCII', 'strict')) |
|
|
|
-def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None): |
|
- |
|
+def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv23, ca_certs=None): |
|
"""Retrieve the certificate from the server at the specified address, |
|
and return it as a PEM-encoded string. |
|
If 'ca_certs' is specified, validate the server cert against it. |
|
If 'ssl_version' is specified, use it in the connection attempt.""" |
|
|
|
host, port = addr |
|
- if (ca_certs is not None): |
|
+ if ca_certs is not None: |
|
cert_reqs = CERT_REQUIRED |
|
else: |
|
cert_reqs = CERT_NONE |
|
- s = wrap_socket(socket(), ssl_version=ssl_version, |
|
- cert_reqs=cert_reqs, ca_certs=ca_certs) |
|
- s.connect(addr) |
|
- dercert = s.getpeercert(True) |
|
- s.close() |
|
+ context = _create_stdlib_context(ssl_version, |
|
+ cert_reqs=cert_reqs, |
|
+ cafile=ca_certs) |
|
+ with closing(create_connection(addr)) as sock: |
|
+ with closing(context.wrap_socket(sock)) as sslsock: |
|
+ dercert = sslsock.getpeercert(True) |
|
return DER_cert_to_PEM_cert(dercert) |
|
|
|
def get_protocol_name(protocol_code): |
|
diff -up Python-2.7.5/Lib/ssl.py.makefile Python-2.7.5/Lib/ssl.py |
|
--- Python-2.7.5/Lib/ssl.py.makefile 2015-03-04 16:48:10.040698640 +0100 |
|
+++ Python-2.7.5/Lib/ssl.py 2015-03-04 16:48:32.885909530 +0100 |
|
@@ -481,6 +481,7 @@ class SSLSocket(socket): |
|
server_hostname=None, |
|
_context=None): |
|
|
|
+ self._makefile_refs = 0 |
|
if _context: |
|
self._context = _context |
|
else: |
|
@@ -563,7 +564,6 @@ class SSLSocket(socket): |
|
except (OSError, ValueError): |
|
self.close() |
|
raise |
|
- self._makefile_refs = 0 |
|
|
|
@property |
|
def context(self): |
|
|
|
diff --git a/Lib/test/capath/4e1295a3.0 b/Lib/test/capath/4e1295a3.0 |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/capath/4e1295a3.0 |
|
@@ -0,0 +1,14 @@ |
|
+-----BEGIN CERTIFICATE----- |
|
+MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD |
|
+VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv |
|
+bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy |
|
+dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X |
|
+DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw |
|
+EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l |
|
+dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT |
|
+EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp |
|
+MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw |
|
+L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN |
|
+BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX |
|
+9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4= |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/capath/5ed36f99.0 b/Lib/test/capath/5ed36f99.0 |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/capath/5ed36f99.0 |
|
@@ -0,0 +1,41 @@ |
|
+-----BEGIN CERTIFICATE----- |
|
+MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 |
|
+IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB |
|
+IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA |
|
+Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO |
|
+BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi |
|
+MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ |
|
+ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC |
|
+CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ |
|
+8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 |
|
+zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y |
|
+fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 |
|
+w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc |
|
+G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k |
|
+epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q |
|
+laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ |
|
+QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU |
|
+fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 |
|
+YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w |
|
+ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY |
|
+gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe |
|
+MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 |
|
+IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy |
|
+dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw |
|
+czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 |
|
+dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl |
|
+aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC |
|
+AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg |
|
+b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB |
|
+ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc |
|
+nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg |
|
+18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c |
|
+gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl |
|
+Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY |
|
+sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T |
|
+SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF |
|
+CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum |
|
+GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk |
|
+zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW |
|
+omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/capath/6e88d7b8.0 b/Lib/test/capath/6e88d7b8.0 |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/capath/6e88d7b8.0 |
|
@@ -0,0 +1,14 @@ |
|
+-----BEGIN CERTIFICATE----- |
|
+MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD |
|
+VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv |
|
+bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy |
|
+dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X |
|
+DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw |
|
+EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l |
|
+dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT |
|
+EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp |
|
+MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw |
|
+L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN |
|
+BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX |
|
+9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4= |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/capath/99d0fa06.0 b/Lib/test/capath/99d0fa06.0 |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/capath/99d0fa06.0 |
|
@@ -0,0 +1,41 @@ |
|
+-----BEGIN CERTIFICATE----- |
|
+MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 |
|
+IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB |
|
+IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA |
|
+Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO |
|
+BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi |
|
+MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ |
|
+ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC |
|
+CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ |
|
+8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 |
|
+zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y |
|
+fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 |
|
+w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc |
|
+G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k |
|
+epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q |
|
+laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ |
|
+QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU |
|
+fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 |
|
+YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w |
|
+ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY |
|
+gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe |
|
+MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 |
|
+IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy |
|
+dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw |
|
+czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 |
|
+dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl |
|
+aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC |
|
+AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg |
|
+b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB |
|
+ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc |
|
+nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg |
|
+18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c |
|
+gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl |
|
+Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY |
|
+sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T |
|
+SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF |
|
+CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum |
|
+GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk |
|
+zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW |
|
+omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/dh512.pem b/Lib/test/dh512.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/dh512.pem |
|
@@ -0,0 +1,9 @@ |
|
+-----BEGIN DH PARAMETERS----- |
|
+MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak |
|
+XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC |
|
+-----END DH PARAMETERS----- |
|
+ |
|
+These are the 512 bit DH parameters from "Assigned Number for SKIP Protocols" |
|
+(http://www.skip-vpn.org/spec/numbers.html). |
|
+See there for how they were generated. |
|
+Note that g is not a generator, but this is not a problem since p is a safe prime. |
|
diff --git a/Lib/test/keycert.passwd.pem b/Lib/test/keycert.passwd.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/keycert.passwd.pem |
|
@@ -0,0 +1,33 @@ |
|
+-----BEGIN RSA PRIVATE KEY----- |
|
+Proc-Type: 4,ENCRYPTED |
|
+DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A |
|
+ |
|
+kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c |
|
+u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA |
|
+AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr |
|
+Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+ |
|
+YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P |
|
+6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+ |
|
+noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1 |
|
+94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l |
|
+7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo |
|
+cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO |
|
+zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt |
|
+L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo |
|
+2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ== |
|
+-----END RSA PRIVATE KEY----- |
|
+-----BEGIN CERTIFICATE----- |
|
+MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV |
|
+BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u |
|
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw |
|
+MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH |
|
+Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k |
|
+YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw |
|
+gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7 |
|
+6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt |
|
+pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw |
|
+FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd |
|
+BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G |
|
+lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1 |
|
+CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/keycert3.pem b/Lib/test/keycert3.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/keycert3.pem |
|
@@ -0,0 +1,73 @@ |
|
+-----BEGIN PRIVATE KEY----- |
|
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMLgD0kAKDb5cFyP |
|
+jbwNfR5CtewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM |
|
+9z2j1OlaN+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZ |
|
+aggEdkj1TsSsv1zWIYKlPIjlvhuxAgMBAAECgYA0aH+T2Vf3WOPv8KdkcJg6gCRe |
|
+yJKXOWgWRcicx/CUzOEsTxmFIDPLxqAWA3k7v0B+3vjGw5Y9lycV/5XqXNoQI14j |
|
+y09iNsumds13u5AKkGdTJnZhQ7UKdoVHfuP44ZdOv/rJ5/VD6F4zWywpe90pcbK+ |
|
+AWDVtusgGQBSieEl1QJBAOyVrUG5l2yoUBtd2zr/kiGm/DYyXlIthQO/A3/LngDW |
|
+5/ydGxVsT7lAVOgCsoT+0L4efTh90PjzW8LPQrPBWVMCQQDS3h/FtYYd5lfz+FNL |
|
+9CEe1F1w9l8P749uNUD0g317zv1tatIqVCsQWHfVHNdVvfQ+vSFw38OORO00Xqs9 |
|
+1GJrAkBkoXXEkxCZoy4PteheO/8IWWLGGr6L7di6MzFl1lIqwT6D8L9oaV2vynFT |
|
+DnKop0pa09Unhjyw57KMNmSE2SUJAkEArloTEzpgRmCq4IK2/NpCeGdHS5uqRlbh |
|
+1VIa/xGps7EWQl5Mn8swQDel/YP3WGHTjfx7pgSegQfkyaRtGpZ9OQJAa9Vumj8m |
|
+JAAtI0Bnga8hgQx7BhTQY4CadDxyiRGOGYhwUzYVCqkb2sbVRH9HnwUaJT7cWBY3 |
|
+RnJdHOMXWem7/w== |
|
+-----END PRIVATE KEY----- |
|
+Certificate: |
|
+ Data: |
|
+ Version: 1 (0x0) |
|
+ Serial Number: 12723342612721443281 (0xb09264b1f2da21d1) |
|
+ Signature Algorithm: sha1WithRSAEncryption |
|
+ Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server |
|
+ Validity |
|
+ Not Before: Jan 4 19:47:07 2013 GMT |
|
+ Not After : Nov 13 19:47:07 2022 GMT |
|
+ Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=localhost |
|
+ Subject Public Key Info: |
|
+ Public Key Algorithm: rsaEncryption |
|
+ Public-Key: (1024 bit) |
|
+ Modulus: |
|
+ 00:c2:e0:0f:49:00:28:36:f9:70:5c:8f:8d:bc:0d: |
|
+ 7d:1e:42:b5:ec:1d:5c:2f:a4:31:70:16:0f:c0:cb: |
|
+ c6:24:d3:be:13:16:ee:a5:67:97:03:a6:df:a9:99: |
|
+ 96:cc:c7:2a:fb:11:7f:4e:65:4f:8a:5e:82:21:4c: |
|
+ f7:3d:a3:d4:e9:5a:37:e7:22:fd:7e:cd:53:6d:93: |
|
+ 34:de:9c:ad:84:a2:37:be:c5:8d:82:4f:e3:ae:23: |
|
+ f3:be:a7:75:2c:72:0f:ea:f3:ca:cd:fc:e9:3f:b5: |
|
+ af:56:99:6a:08:04:76:48:f5:4e:c4:ac:bf:5c:d6: |
|
+ 21:82:a5:3c:88:e5:be:1b:b1 |
|
+ Exponent: 65537 (0x10001) |
|
+ Signature Algorithm: sha1WithRSAEncryption |
|
+ 2f:42:5f:a3:09:2c:fa:51:88:c7:37:7f:ea:0e:63:f0:a2:9a: |
|
+ e5:5a:e2:c8:20:f0:3f:60:bc:c8:0f:b6:c6:76:ce:db:83:93: |
|
+ f5:a3:33:67:01:8e:04:cd:00:9a:73:fd:f3:35:86:fa:d7:13: |
|
+ e2:46:c6:9d:c0:29:53:d4:a9:90:b8:77:4b:e6:83:76:e4:92: |
|
+ d6:9c:50:cf:43:d0:c6:01:77:61:9a:de:9b:70:f7:72:cd:59: |
|
+ 00:31:69:d9:b4:ca:06:9c:6d:c3:c7:80:8c:68:e6:b5:a2:f8: |
|
+ ef:1d:bb:16:9f:77:77:ef:87:62:22:9b:4d:69:a4:3a:1a:f1: |
|
+ 21:5e:8c:32:ac:92:fd:15:6b:18:c2:7f:15:0d:98:30:ca:75: |
|
+ 8f:1a:71:df:da:1d:b2:ef:9a:e8:2d:2e:02:fd:4a:3c:aa:96: |
|
+ 0b:06:5d:35:b3:3d:24:87:4b:e0:b0:58:60:2f:45:ac:2e:48: |
|
+ 8a:b0:99:10:65:27:ff:cc:b1:d8:fd:bd:26:6b:b9:0c:05:2a: |
|
+ f4:45:63:35:51:07:ed:83:85:fe:6f:69:cb:bb:40:a8:ae:b6: |
|
+ 3b:56:4a:2d:a4:ed:6d:11:2c:4d:ed:17:24:fd:47:bc:d3:41: |
|
+ a2:d3:06:fe:0c:90:d8:d8:94:26:c4:ff:cc:a1:d8:42:77:eb: |
|
+ fc:a9:94:71 |
|
+-----BEGIN CERTIFICATE----- |
|
+MIICpDCCAYwCCQCwkmSx8toh0TANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY |
|
+WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV |
|
+BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3 |
|
+WjBfMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV |
|
+BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRIwEAYDVQQDEwlsb2NhbGhv |
|
+c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMLgD0kAKDb5cFyPjbwNfR5C |
|
+tewdXC+kMXAWD8DLxiTTvhMW7qVnlwOm36mZlszHKvsRf05lT4pegiFM9z2j1Ola |
|
+N+ci/X7NU22TNN6crYSiN77FjYJP464j876ndSxyD+rzys386T+1r1aZaggEdkj1 |
|
+TsSsv1zWIYKlPIjlvhuxAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAC9CX6MJLPpR |
|
+iMc3f+oOY/CimuVa4sgg8D9gvMgPtsZ2ztuDk/WjM2cBjgTNAJpz/fM1hvrXE+JG |
|
+xp3AKVPUqZC4d0vmg3bkktacUM9D0MYBd2Ga3ptw93LNWQAxadm0ygacbcPHgIxo |
|
+5rWi+O8duxafd3fvh2Iim01ppDoa8SFejDKskv0VaxjCfxUNmDDKdY8acd/aHbLv |
|
+mugtLgL9SjyqlgsGXTWzPSSHS+CwWGAvRawuSIqwmRBlJ//Msdj9vSZruQwFKvRF |
|
+YzVRB+2Dhf5vacu7QKiutjtWSi2k7W0RLE3tFyT9R7zTQaLTBv4MkNjYlCbE/8yh |
|
+2EJ36/yplHE= |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/keycert4.pem b/Lib/test/keycert4.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/keycert4.pem |
|
@@ -0,0 +1,73 @@ |
|
+-----BEGIN PRIVATE KEY----- |
|
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK5UQiMI5VkNs2Qv |
|
+L7gUaiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2 |
|
+NkX0ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1 |
|
+L2OQhEx1GM6RydHdgX69G64LXcY5AgMBAAECgYAhsRMfJkb9ERLMl/oG/5sLQu9L |
|
+pWDKt6+ZwdxzlZbggQ85CMYshjLKIod2DLL/sLf2x1PRXyRG131M1E3k8zkkz6de |
|
+R1uDrIN/x91iuYzfLQZGh8bMY7Yjd2eoroa6R/7DjpElGejLxOAaDWO0ST2IFQy9 |
|
+myTGS2jSM97wcXfsSQJBANP3jelJoS5X6BRjTSneY21wcocxVuQh8pXpErALVNsT |
|
+drrFTeaBuZp7KvbtnIM5g2WRNvaxLZlAY/hXPJvi6ncCQQDSix1cebml6EmPlEZS |
|
+Mm8gwI2F9ufUunwJmBJcz826Do0ZNGByWDAM/JQZH4FX4GfAFNuj8PUb+GQfadkx |
|
+i1DPAkEA0lVsNHojvuDsIo8HGuzarNZQT2beWjJ1jdxh9t7HrTx7LIps6rb/fhOK |
|
+Zs0R6gVAJaEbcWAPZ2tFyECInAdnsQJAUjaeXXjuxFkjOFym5PvqpvhpivEx78Bu |
|
+JPTr3rAKXmfGMxxfuOa0xK1wSyshP6ZR/RBn/+lcXPKubhHQDOegwwJAJF1DBQnN |
|
++/tLmOPULtDwfP4Zixn+/8GmGOahFoRcu6VIGHmRilJTn6MOButw7Glv2YdeC6l/ |
|
+e83Gq6ffLVfKNQ== |
|
+-----END PRIVATE KEY----- |
|
+Certificate: |
|
+ Data: |
|
+ Version: 1 (0x0) |
|
+ Serial Number: 12723342612721443282 (0xb09264b1f2da21d2) |
|
+ Signature Algorithm: sha1WithRSAEncryption |
|
+ Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server |
|
+ Validity |
|
+ Not Before: Jan 4 19:47:07 2013 GMT |
|
+ Not After : Nov 13 19:47:07 2022 GMT |
|
+ Subject: C=XY, L=Castle Anthrax, O=Python Software Foundation, CN=fakehostname |
|
+ Subject Public Key Info: |
|
+ Public Key Algorithm: rsaEncryption |
|
+ Public-Key: (1024 bit) |
|
+ Modulus: |
|
+ 00:ae:54:42:23:08:e5:59:0d:b3:64:2f:2f:b8:14: |
|
+ 6a:20:dd:15:eb:cd:51:74:63:53:80:c7:01:ed:d9: |
|
+ cf:36:0b:64:d1:3a:f6:1f:60:3b:d5:42:49:2d:7a: |
|
+ b4:9e:5f:4f:95:44:bb:41:19:c8:6a:f4:7b:75:76: |
|
+ 36:45:f4:66:85:34:1d:cf:d4:69:8e:2a:c7:b2:c7: |
|
+ 9a:7e:52:61:9a:48:c6:12:67:91:fe:d2:c8:72:4a: |
|
+ d7:35:1a:1a:55:34:fc:bc:58:a8:8b:86:0a:d1:79: |
|
+ 76:ac:75:2f:63:90:84:4c:75:18:ce:91:c9:d1:dd: |
|
+ 81:7e:bd:1b:ae:0b:5d:c6:39 |
|
+ Exponent: 65537 (0x10001) |
|
+ Signature Algorithm: sha1WithRSAEncryption |
|
+ ad:45:8a:8e:ef:c6:ef:04:41:5c:2c:4a:84:dc:02:76:0c:d0: |
|
+ 66:0f:f0:16:04:58:4d:fd:68:b7:b8:d3:a8:41:a5:5c:3c:6f: |
|
+ 65:3c:d1:f8:ce:43:35:e7:41:5f:53:3d:c9:2c:c3:7d:fc:56: |
|
+ 4a:fa:47:77:38:9d:bb:97:28:0a:3b:91:19:7f:bc:74:ae:15: |
|
+ 6b:bd:20:36:67:45:a5:1e:79:d7:75:e6:89:5c:6d:54:84:d1: |
|
+ 95:d7:a7:b4:33:3c:af:37:c4:79:8f:5e:75:dc:75:c2:18:fb: |
|
+ 61:6f:2d:dc:38:65:5b:ba:67:28:d0:88:d7:8d:b9:23:5a:8e: |
|
+ e8:c6:bb:db:ce:d5:b8:41:2a:ce:93:08:b6:95:ad:34:20:18: |
|
+ d5:3b:37:52:74:50:0b:07:2c:b0:6d:a4:4c:7b:f4:e0:fd:d1: |
|
+ af:17:aa:20:cd:62:e3:f0:9d:37:69:db:41:bd:d4:1c:fb:53: |
|
+ 20:da:88:9d:76:26:67:ce:01:90:a7:80:1d:a9:5b:39:73:68: |
|
+ 54:0a:d1:2a:03:1b:8f:3c:43:5d:5d:c4:51:f1:a7:e7:11:da: |
|
+ 31:2c:49:06:af:04:f4:b8:3c:99:c4:20:b9:06:36:a2:00:92: |
|
+ 61:1d:0c:6d:24:05:e2:82:e1:47:db:a0:5f:ba:b9:fb:ba:fa: |
|
+ 49:12:1e:ce |
|
+-----BEGIN CERTIFICATE----- |
|
+MIICpzCCAY8CCQCwkmSx8toh0jANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJY |
|
+WTEmMCQGA1UECgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNV |
|
+BAMMDW91ci1jYS1zZXJ2ZXIwHhcNMTMwMTA0MTk0NzA3WhcNMjIxMTEzMTk0NzA3 |
|
+WjBiMQswCQYDVQQGEwJYWTEXMBUGA1UEBxMOQ2FzdGxlIEFudGhyYXgxIzAhBgNV |
|
+BAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMRUwEwYDVQQDEwxmYWtlaG9z |
|
+dG5hbWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK5UQiMI5VkNs2QvL7gU |
|
+aiDdFevNUXRjU4DHAe3ZzzYLZNE69h9gO9VCSS16tJ5fT5VEu0EZyGr0e3V2NkX0 |
|
+ZoU0Hc/UaY4qx7LHmn5SYZpIxhJnkf7SyHJK1zUaGlU0/LxYqIuGCtF5dqx1L2OQ |
|
+hEx1GM6RydHdgX69G64LXcY5AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAK1Fio7v |
|
+xu8EQVwsSoTcAnYM0GYP8BYEWE39aLe406hBpVw8b2U80fjOQzXnQV9TPcksw338 |
|
+Vkr6R3c4nbuXKAo7kRl/vHSuFWu9IDZnRaUeedd15olcbVSE0ZXXp7QzPK83xHmP |
|
+XnXcdcIY+2FvLdw4ZVu6ZyjQiNeNuSNajujGu9vO1bhBKs6TCLaVrTQgGNU7N1J0 |
|
+UAsHLLBtpEx79OD90a8XqiDNYuPwnTdp20G91Bz7UyDaiJ12JmfOAZCngB2pWzlz |
|
+aFQK0SoDG488Q11dxFHxp+cR2jEsSQavBPS4PJnEILkGNqIAkmEdDG0kBeKC4Ufb |
|
+oF+6ufu6+kkSHs4= |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/make_ssl_certs.py |
|
@@ -0,0 +1,176 @@ |
|
+"""Make the custom certificate and private key files used by test_ssl |
|
+and friends.""" |
|
+ |
|
+import os |
|
+import shutil |
|
+import sys |
|
+import tempfile |
|
+from subprocess import * |
|
+ |
|
+req_template = """ |
|
+ [req] |
|
+ distinguished_name = req_distinguished_name |
|
+ x509_extensions = req_x509_extensions |
|
+ prompt = no |
|
+ |
|
+ [req_distinguished_name] |
|
+ C = XY |
|
+ L = Castle Anthrax |
|
+ O = Python Software Foundation |
|
+ CN = {hostname} |
|
+ |
|
+ [req_x509_extensions] |
|
+ subjectAltName = DNS:{hostname} |
|
+ |
|
+ [ ca ] |
|
+ default_ca = CA_default |
|
+ |
|
+ [ CA_default ] |
|
+ dir = cadir |
|
+ database = $dir/index.txt |
|
+ crlnumber = $dir/crl.txt |
|
+ default_md = sha1 |
|
+ default_days = 3600 |
|
+ default_crl_days = 3600 |
|
+ certificate = pycacert.pem |
|
+ private_key = pycakey.pem |
|
+ serial = $dir/serial |
|
+ RANDFILE = $dir/.rand |
|
+ |
|
+ policy = policy_match |
|
+ |
|
+ [ policy_match ] |
|
+ countryName = match |
|
+ stateOrProvinceName = optional |
|
+ organizationName = match |
|
+ organizationalUnitName = optional |
|
+ commonName = supplied |
|
+ emailAddress = optional |
|
+ |
|
+ [ policy_anything ] |
|
+ countryName = optional |
|
+ stateOrProvinceName = optional |
|
+ localityName = optional |
|
+ organizationName = optional |
|
+ organizationalUnitName = optional |
|
+ commonName = supplied |
|
+ emailAddress = optional |
|
+ |
|
+ |
|
+ [ v3_ca ] |
|
+ |
|
+ subjectKeyIdentifier=hash |
|
+ authorityKeyIdentifier=keyid:always,issuer |
|
+ basicConstraints = CA:true |
|
+ |
|
+ """ |
|
+ |
|
+here = os.path.abspath(os.path.dirname(__file__)) |
|
+ |
|
+def make_cert_key(hostname, sign=False): |
|
+ print("creating cert for " + hostname) |
|
+ tempnames = [] |
|
+ for i in range(3): |
|
+ with tempfile.NamedTemporaryFile(delete=False) as f: |
|
+ tempnames.append(f.name) |
|
+ req_file, cert_file, key_file = tempnames |
|
+ try: |
|
+ with open(req_file, 'w') as f: |
|
+ f.write(req_template.format(hostname=hostname)) |
|
+ args = ['req', '-new', '-days', '3650', '-nodes', |
|
+ '-newkey', 'rsa:1024', '-keyout', key_file, |
|
+ '-config', req_file] |
|
+ if sign: |
|
+ with tempfile.NamedTemporaryFile(delete=False) as f: |
|
+ tempnames.append(f.name) |
|
+ reqfile = f.name |
|
+ args += ['-out', reqfile ] |
|
+ |
|
+ else: |
|
+ args += ['-x509', '-out', cert_file ] |
|
+ check_call(['openssl'] + args) |
|
+ |
|
+ if sign: |
|
+ args = ['ca', '-config', req_file, '-out', cert_file, '-outdir', 'cadir', |
|
+ '-policy', 'policy_anything', '-batch', '-infiles', reqfile ] |
|
+ check_call(['openssl'] + args) |
|
+ |
|
+ |
|
+ with open(cert_file, 'r') as f: |
|
+ cert = f.read() |
|
+ with open(key_file, 'r') as f: |
|
+ key = f.read() |
|
+ return cert, key |
|
+ finally: |
|
+ for name in tempnames: |
|
+ os.remove(name) |
|
+ |
|
+TMP_CADIR = 'cadir' |
|
+ |
|
+def unmake_ca(): |
|
+ shutil.rmtree(TMP_CADIR) |
|
+ |
|
+def make_ca(): |
|
+ os.mkdir(TMP_CADIR) |
|
+ with open(os.path.join('cadir','index.txt'),'a+') as f: |
|
+ pass # empty file |
|
+ with open(os.path.join('cadir','crl.txt'),'a+') as f: |
|
+ f.write("00") |
|
+ with open(os.path.join('cadir','index.txt.attr'),'w+') as f: |
|
+ f.write('unique_subject = no') |
|
+ |
|
+ with tempfile.NamedTemporaryFile("w") as t: |
|
+ t.write(req_template.format(hostname='our-ca-server')) |
|
+ t.flush() |
|
+ with tempfile.NamedTemporaryFile() as f: |
|
+ args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes', |
|
+ '-newkey', 'rsa:2048', '-keyout', 'pycakey.pem', |
|
+ '-out', f.name, |
|
+ '-subj', '/C=XY/L=Castle Anthrax/O=Python Software Foundation CA/CN=our-ca-server'] |
|
+ check_call(['openssl'] + args) |
|
+ args = ['ca', '-config', t.name, '-create_serial', |
|
+ '-out', 'pycacert.pem', '-batch', '-outdir', TMP_CADIR, |
|
+ '-keyfile', 'pycakey.pem', '-days', '3650', |
|
+ '-selfsign', '-extensions', 'v3_ca', '-infiles', f.name ] |
|
+ check_call(['openssl'] + args) |
|
+ args = ['ca', '-config', t.name, '-gencrl', '-out', 'revocation.crl'] |
|
+ check_call(['openssl'] + args) |
|
+ |
|
+if __name__ == '__main__': |
|
+ os.chdir(here) |
|
+ cert, key = make_cert_key('localhost') |
|
+ with open('ssl_cert.pem', 'w') as f: |
|
+ f.write(cert) |
|
+ with open('ssl_key.pem', 'w') as f: |
|
+ f.write(key) |
|
+ print("password protecting ssl_key.pem in ssl_key.passwd.pem") |
|
+ check_call(['openssl','rsa','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-des3','-passout','pass:somepass']) |
|
+ check_call(['openssl','rsa','-in','ssl_key.pem','-out','keycert.passwd.pem','-des3','-passout','pass:somepass']) |
|
+ |
|
+ with open('keycert.pem', 'w') as f: |
|
+ f.write(key) |
|
+ f.write(cert) |
|
+ |
|
+ with open('keycert.passwd.pem', 'a+') as f: |
|
+ f.write(cert) |
|
+ |
|
+ # For certificate matching tests |
|
+ make_ca() |
|
+ cert, key = make_cert_key('fakehostname') |
|
+ with open('keycert2.pem', 'w') as f: |
|
+ f.write(key) |
|
+ f.write(cert) |
|
+ |
|
+ cert, key = make_cert_key('localhost', True) |
|
+ with open('keycert3.pem', 'w') as f: |
|
+ f.write(key) |
|
+ f.write(cert) |
|
+ |
|
+ cert, key = make_cert_key('fakehostname', True) |
|
+ with open('keycert4.pem', 'w') as f: |
|
+ f.write(key) |
|
+ f.write(cert) |
|
+ |
|
+ unmake_ca() |
|
+ print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber") |
|
+ check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout']) |
|
diff --git a/Lib/test/pycacert.pem b/Lib/test/pycacert.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/pycacert.pem |
|
@@ -0,0 +1,78 @@ |
|
+Certificate: |
|
+ Data: |
|
+ Version: 3 (0x2) |
|
+ Serial Number: 12723342612721443280 (0xb09264b1f2da21d0) |
|
+ Signature Algorithm: sha1WithRSAEncryption |
|
+ Issuer: C=XY, O=Python Software Foundation CA, CN=our-ca-server |
|
+ Validity |
|
+ Not Before: Jan 4 19:47:07 2013 GMT |
|
+ Not After : Jan 2 19:47:07 2023 GMT |
|
+ Subject: C=XY, O=Python Software Foundation CA, CN=our-ca-server |
|
+ Subject Public Key Info: |
|
+ Public Key Algorithm: rsaEncryption |
|
+ Public-Key: (2048 bit) |
|
+ Modulus: |
|
+ 00:e7:de:e9:e3:0c:9f:00:b6:a1:fd:2b:5b:96:d2: |
|
+ 6f:cc:e0:be:86:b9:20:5e:ec:03:7a:55:ab:ea:a4: |
|
+ e9:f9:49:85:d2:66:d5:ed:c7:7a:ea:56:8e:2d:8f: |
|
+ e7:42:e2:62:28:a9:9f:d6:1b:8e:eb:b5:b4:9c:9f: |
|
+ 14:ab:df:e6:94:8b:76:1d:3e:6d:24:61:ed:0c:bf: |
|
+ 00:8a:61:0c:df:5c:c8:36:73:16:00:cd:47:ba:6d: |
|
+ a4:a4:74:88:83:23:0a:19:fc:09:a7:3c:4a:4b:d3: |
|
+ e7:1d:2d:e4:ea:4c:54:21:f3:26:db:89:37:18:d4: |
|
+ 02:bb:40:32:5f:a4:ff:2d:1c:f7:d4:bb:ec:8e:cf: |
|
+ 5c:82:ac:e6:7c:08:6c:48:85:61:07:7f:25:e0:5c: |
|
+ e0:bc:34:5f:e0:b9:04:47:75:c8:47:0b:8d:bc:d6: |
|
+ c8:68:5f:33:83:62:d2:20:44:35:b1:ad:81:1a:8a: |
|
+ cd:bc:35:b0:5c:8b:47:d6:18:e9:9c:18:97:cc:01: |
|
+ 3c:29:cc:e8:1e:e4:e4:c1:b8:de:e7:c2:11:18:87: |
|
+ 5a:93:34:d8:a6:25:f7:14:71:eb:e4:21:a2:d2:0f: |
|
+ 2e:2e:d4:62:00:35:d3:d6:ef:5c:60:4b:4c:a9:14: |
|
+ e2:dd:15:58:46:37:33:26:b7:e7:2e:5d:ed:42:e4: |
|
+ c5:4d |
|
+ Exponent: 65537 (0x10001) |
|
+ X509v3 extensions: |
|
+ X509v3 Subject Key Identifier: |
|
+ BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B |
|
+ X509v3 Authority Key Identifier: |
|
+ keyid:BC:DD:62:D9:76:DA:1B:D2:54:6B:CF:E0:66:9B:1E:1E:7B:56:0C:0B |
|
+ |
|
+ X509v3 Basic Constraints: |
|
+ CA:TRUE |
|
+ Signature Algorithm: sha1WithRSAEncryption |
|
+ 7d:0a:f5:cb:8d:d3:5d:bd:99:8e:f8:2b:0f:ba:eb:c2:d9:a6: |
|
+ 27:4f:2e:7b:2f:0e:64:d8:1c:35:50:4e:ee:fc:90:b9:8d:6d: |
|
+ a8:c5:c6:06:b0:af:f3:2d:bf:3b:b8:42:07:dd:18:7d:6d:95: |
|
+ 54:57:85:18:60:47:2f:eb:78:1b:f9:e8:17:fd:5a:0d:87:17: |
|
+ 28:ac:4c:6a:e6:bc:29:f4:f4:55:70:29:42:de:85:ea:ab:6c: |
|
+ 23:06:64:30:75:02:8e:53:bc:5e:01:33:37:cc:1e:cd:b8:a4: |
|
+ fd:ca:e4:5f:65:3b:83:1c:86:f1:55:02:a0:3a:8f:db:91:b7: |
|
+ 40:14:b4:e7:8d:d2:ee:73:ba:e3:e5:34:2d:bc:94:6f:4e:24: |
|
+ 06:f7:5f:8b:0e:a7:8e:6b:de:5e:75:f4:32:9a:50:b1:44:33: |
|
+ 9a:d0:05:e2:78:82:ff:db:da:8a:63:eb:a9:dd:d1:bf:a0:61: |
|
+ ad:e3:9e:8a:24:5d:62:0e:e7:4c:91:7f:ef:df:34:36:3b:2f: |
|
+ 5d:f5:84:b2:2f:c4:6d:93:96:1a:6f:30:28:f1:da:12:9a:64: |
|
+ b4:40:33:1d:bd:de:2b:53:a8:ea:be:d6:bc:4e:96:f5:44:fb: |
|
+ 32:18:ae:d5:1f:f6:69:af:b6:4e:7b:1d:58:ec:3b:a9:53:a3: |
|
+ 5e:58:c8:9e |
|
+-----BEGIN CERTIFICATE----- |
|
+MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV |
|
+BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW |
|
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx |
|
+OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg |
|
+Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI |
|
+hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV |
|
+q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/ |
|
+AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA |
|
+Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni |
|
+0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx |
|
+6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w |
|
+HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2 |
|
+2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB |
|
+AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4 |
|
+QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1 |
|
+Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O |
|
+JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR |
|
+f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf |
|
+9mmvtk57HVjsO6lTo15YyJ4= |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/revocation.crl b/Lib/test/revocation.crl |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/revocation.crl |
|
@@ -0,0 +1,11 @@ |
|
+-----BEGIN X509 CRL----- |
|
+MIIBpjCBjwIBATANBgkqhkiG9w0BAQUFADBNMQswCQYDVQQGEwJYWTEmMCQGA1UE |
|
+CgwdUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24gQ0ExFjAUBgNVBAMMDW91ci1j |
|
+YS1zZXJ2ZXIXDTEzMTEyMTE3MDg0N1oXDTIzMDkzMDE3MDg0N1qgDjAMMAoGA1Ud |
|
+FAQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQCNJXC2mVKauEeN3LlQ3ZtM5gkH3ExH |
|
++i4bmJjtJn497WwvvoIeUdrmVXgJQR93RtV37hZwN0SXMLlNmUZPH4rHhihayw4m |
|
+unCzVj/OhCCY7/TPjKuJ1O/0XhaLBpBVjQN7R/1ujoRKbSia/CD3vcn7Fqxzw7LK |
|
+fSRCKRGTj1CZiuxrphtFchwALXSiFDy9mr2ZKhImcyq1PydfgEzU78APpOkMQsIC |
|
+UNJ/cf3c9emzf+dUtcMEcejQ3mynBo4eIGg1EW42bz4q4hSjzQlKcBV0muw5qXhc |
|
+HOxH2iTFhQ7SrvVuK/dM14rYM4B5mSX3nRC1kNmXpS9j3wJDhuwmjHed |
|
+-----END X509 CRL----- |
|
diff --git a/Lib/test/sha256.pem b/Lib/test/sha256.pem |
|
--- a/Lib/test/sha256.pem |
|
+++ b/Lib/test/sha256.pem |
|
@@ -1,128 +1,128 @@ |
|
# Certificate chain for https://sha256.tbs-internet.com |
|
- 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=Certificats TBS X509/CN=ecom.tbs-x509.com |
|
- i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business |
|
+ 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com |
|
+ i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC |
|
-----BEGIN CERTIFICATE----- |
|
-MIIGTjCCBTagAwIBAgIQOh3d9dNDPq1cSdJmEiMpqDANBgkqhkiG9w0BAQUFADCB |
|
-yTELMAkGA1UEBhMCRlIxETAPBgNVBAgTCENhbHZhZG9zMQ0wCwYDVQQHEwRDYWVu |
|
-MRUwEwYDVQQKEwxUQlMgSU5URVJORVQxSDBGBgNVBAsTP1Rlcm1zIGFuZCBDb25k |
|
-aXRpb25zOiBodHRwOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0EvcmVwb3NpdG9y |
|
-eTEYMBYGA1UECxMPVEJTIElOVEVSTkVUIENBMR0wGwYDVQQDExRUQlMgWDUwOSBD |
|
-QSBidXNpbmVzczAeFw0xMTAxMjUwMDAwMDBaFw0xMzAyMDUyMzU5NTlaMIHHMQsw |
|
-CQYDVQQGEwJGUjEOMAwGA1UEERMFMTQwMDAxETAPBgNVBAgTCENhbHZhZG9zMQ0w |
|
-CwYDVQQHEwRDQUVOMRswGQYDVQQJExIyMiBydWUgZGUgQnJldGFnbmUxFTATBgNV |
|
-BAoTDFRCUyBJTlRFUk5FVDEXMBUGA1UECxMOMDAwMiA0NDA0NDM4MTAxHTAbBgNV |
|
-BAsTFENlcnRpZmljYXRzIFRCUyBYNTA5MRowGAYDVQQDExFlY29tLnRicy14NTA5 |
|
-LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKRrlHUnJ++1lpcg |
|
-jtYco7cdmRe+EEfTmwPfCdfV3G1QfsTSvY6FfMpm/83pqHfT+4ANwr18wD9ZrAEN |
|
-G16mf9VdCGK12+TP7DmqeZyGIqlFFoahQnmb8EarvE43/1UeQ2CV9XmzwZvpqeli |
|
-LfXsFonawrY3H6ZnMwS64St61Z+9gdyuZ/RbsoZBbT5KUjDEG844QRU4OT1IGeEI |
|
-eY5NM5RNIh6ZNhVtqeeCxMS7afONkHQrOco73RdSTRck/Hj96Ofl3MHNHryr+AMK |
|
-DGFk1kLCZGpPdXtkxXvaDeQoiYDlil26CWc+YK6xyDPMdsWvoG14ZLyCpzMXA7/7 |
|
-4YAQRH0CAwEAAaOCAjAwggIsMB8GA1UdIwQYMBaAFBoJBMz5CY+7HqDO1KQUf0vV |
|
-I1jNMB0GA1UdDgQWBBQgOU8HsWzbmD4WZP5Wtdw7jca2WDAOBgNVHQ8BAf8EBAMC |
|
-BaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw |
|
-TAYDVR0gBEUwQzBBBgsrBgEEAYDlNwIBATAyMDAGCCsGAQUFBwIBFiRodHRwczov |
|
-L3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL0NQUzEwdwYDVR0fBHAwbjA3oDWgM4Yx |
|
-aHR0cDovL2NybC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNy |
|
-bDAzoDGgL4YtaHR0cDovL2NybC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5l |
|
-c3MuY3JsMIGwBggrBgEFBQcBAQSBozCBoDA9BggrBgEFBQcwAoYxaHR0cDovL2Ny |
|
-dC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQWJ1c2luZXNzLmNydDA5BggrBgEF |
|
-BQcwAoYtaHR0cDovL2NydC50YnMteDUwOS5jb20vVEJTWDUwOUNBYnVzaW5lc3Mu |
|
-Y3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wMwYDVR0R |
|
-BCwwKoIRZWNvbS50YnMteDUwOS5jb22CFXd3dy5lY29tLnRicy14NTA5LmNvbTAN |
|
-BgkqhkiG9w0BAQUFAAOCAQEArT4NHfbY87bGAw8lPV4DmHlmuDuVp/y7ltO3Ynse |
|
-3Rz8RxW2AzuO0Oy2F0Cu4yWKtMyEyMXyHqWtae7ElRbdTu5w5GwVBLJHClCzC8S9 |
|
-SpgMMQTx3Rgn8vjkHuU9VZQlulZyiPK7yunjc7c310S9FRZ7XxOwf8Nnx4WnB+No |
|
-WrfApzhhQl31w+RyrNxZe58hCfDDHmevRvwLjQ785ZoQXJDj2j3qAD4aI2yB8lB5 |
|
-oaE1jlCJzC7Kmz/Y9jzfmv/zAs1LQTm9ktevv4BTUFaGjv9jxnQ1xnS862ZiouLW |
|
-zZYIlYPf4F6JjXGiIQgQRglILUfq3ftJd9/ok9W9ZF8h8w== |
|
+MIIGXDCCBUSgAwIBAgIRAKpVmHgg9nfCodAVwcP4siwwDQYJKoZIhvcNAQELBQAw |
|
+gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl |
|
+bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u |
|
+ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv |
|
+cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg |
|
+Q0EgU0dDMB4XDTEyMDEwNDAwMDAwMFoXDTE0MDIxNzIzNTk1OVowgcsxCzAJBgNV |
|
+BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV |
|
+BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM |
|
+VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS |
|
+c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0 |
|
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKQIX/zdJcyxty0m |
|
+PM1XQSoSSifueS3AVcgqMsaIKS/u+rYzsv4hQ/qA6vLn5m5/ewUcZDj7zdi6rBVf |
|
+PaVNXJ6YinLX0tkaW8TEjeVuZG5yksGZlhCt1CJ1Ho9XLiLaP4uJ7MCoNUntpJ+E |
|
+LfrOdgsIj91kPmwjDJeztVcQCvKzhjVJA/KxdInc0JvOATn7rpaSmQI5bvIjufgo |
|
+qVsTPwVFzuUYULXBk7KxRT7MiEqnd5HvviNh0285QC478zl3v0I0Fb5El4yD3p49 |
|
+IthcRnxzMKc0UhU5ogi0SbONyBfm/mzONVfSxpM+MlyvZmJqrbuuLoEDzJD+t8PU |
|
+xSuzgbcCAwEAAaOCAj4wggI6MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf |
|
+2YIfMB0GA1UdDgQWBBT/qTGYdaj+f61c2IRFL/B1eEsM8DAOBgNVHQ8BAf8EBAMC |
|
+BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG |
|
+CisGAQQBgjcKAwMGCWCGSAGG+EIEATBLBgNVHSAERDBCMEAGCisGAQQB5TcCBAEw |
|
+MjAwBggrBgEFBQcCARYkaHR0cHM6Ly93d3cudGJzLWludGVybmV0LmNvbS9DQS9D |
|
+UFM0MG0GA1UdHwRmMGQwMqAwoC6GLGh0dHA6Ly9jcmwudGJzLWludGVybmV0LmNv |
|
+bS9UQlNYNTA5Q0FTR0MuY3JsMC6gLKAqhihodHRwOi8vY3JsLnRicy14NTA5LmNv |
|
+bS9UQlNYNTA5Q0FTR0MuY3JsMIGmBggrBgEFBQcBAQSBmTCBljA4BggrBgEFBQcw |
|
+AoYsaHR0cDovL2NydC50YnMtaW50ZXJuZXQuY29tL1RCU1g1MDlDQVNHQy5jcnQw |
|
+NAYIKwYBBQUHMAKGKGh0dHA6Ly9jcnQudGJzLXg1MDkuY29tL1RCU1g1MDlDQVNH |
|
+Qy5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnRicy14NTA5LmNvbTA/BgNV |
|
+HREEODA2ghdzaGEyNTYudGJzLWludGVybmV0LmNvbYIbd3d3LnNoYTI1Ni50YnMt |
|
+aW50ZXJuZXQuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQA0pOuL8QvAa5yksTbGShzX |
|
+ABApagunUGoEydv4YJT1MXy9tTp7DrWaozZSlsqBxrYAXP1d9r2fuKbEniYHxaQ0 |
|
+UYaf1VSIlDo1yuC8wE7wxbHDIpQ/E5KAyxiaJ8obtDhFstWAPAH+UoGXq0kj2teN |
|
+21sFQ5dXgA95nldvVFsFhrRUNB6xXAcaj0VZFhttI0ZfQZmQwEI/P+N9Jr40OGun |
|
+aa+Dn0TMeUH4U20YntfLbu2nDcJcYfyurm+8/0Tr4HznLnedXu9pCPYj0TaddrgT |
|
+XO0oFiyy7qGaY6+qKh71yD64Y3ycCJ/HR9Wm39mjZYc9ezYwT4noP6r7Lk8YO7/q |
|
-----END CERTIFICATE----- |
|
- 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA business |
|
+ 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC |
|
i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root |
|
-----BEGIN CERTIFICATE----- |
|
-MIIFPzCCBCegAwIBAgIQDlBz/++iRSmLDeVRHT/hADANBgkqhkiG9w0BAQUFADBv |
|
+MIIFVjCCBD6gAwIBAgIQXpDZ0ETJMV02WTx3GTnhhTANBgkqhkiG9w0BAQUFADBv |
|
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk |
|
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF |
|
-eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDcwOTE4MTkyMlow |
|
-gckxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl |
|
+eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDYyNDE5MDYzMFow |
|
+gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl |
|
bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u |
|
ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv |
|
-cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEdMBsGA1UEAxMUVEJTIFg1MDkg |
|
-Q0EgYnVzaW5lc3MwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB1PAU |
|
-qudCcz3tmyGcf+u6EkZqonKKHrV4gZYbvVkIRojmmlhfi/jwvpHvo8bqSt/9Rj5S |
|
-jhCDW0pcbI+IPPtD1Jy+CHNSfnMqVDy6CKQ3p5maTzCMG6ZT+XjnvcND5v+FtaiB |
|
-xk1iCX6uvt0jeUtdZvYbyytsSDE6c3Y5//wRxOF8tM1JxibwO3pyER26jbbN2gQz |
|
-m/EkdGjLdJ4svPk23WDAvQ6G0/z2LcAaJB+XLfqRwfQpHQvfKa1uTi8PivC8qtip |
|
-rmNQMMPMjxSK2azX8cKjjTDJiUKaCb4VHlJDWKEsCFRpgJAoAuX8f7Yfs1M4esGo |
|
-sWb3PGspK3O22uIlAgMBAAGjggF6MIIBdjAdBgNVHQ4EFgQUGgkEzPkJj7seoM7U |
|
-pBR/S9UjWM0wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwGAYD |
|
-VR0gBBEwDzANBgsrBgEEAYDlNwIBATB7BgNVHR8EdDByMDigNqA0hjJodHRwOi8v |
|
-Y3JsLmNvbW9kb2NhLmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDA2oDSg |
|
-MoYwaHR0cDovL2NybC5jb21vZG8ubmV0L0FkZFRydXN0RXh0ZXJuYWxDQVJvb3Qu |
|
-Y3JsMIGGBggrBgEFBQcBAQR6MHgwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29t |
|
-b2RvY2EuY29tL0FkZFRydXN0VVROU2VydmVyQ0EuY3J0MDkGCCsGAQUFBzAChi1o |
|
-dHRwOi8vY3J0LmNvbW9kby5uZXQvQWRkVHJ1c3RVVE5TZXJ2ZXJDQS5jcnQwEQYJ |
|
-YIZIAYb4QgEBBAQDAgIEMA0GCSqGSIb3DQEBBQUAA4IBAQA7mqrMgk/MrE6QnbNA |
|
-h4nRCn2ti4bg4w2C3lB6bSvRPnYwuNw9Jb8vuKkNFzRDxNJXqVDZdfFW5CVQJuyd |
|
-nfAx83+wk+spzvFaE1KhFYfN9G9pQfXUfvDRoIcJgPEKUXL1wRiOG+IjU3VVI8pg |
|
-IgqHkr7ylln5i5zCiFAPuIJmYUSFg/gxH5xkCNcjJqqrHrHatJr6Qrrke93joupw |
|
-oU1njfAcZtYp6fbiK6u2b1pJqwkVBE8RsfLnPhRj+SFbpvjv8Od7o/ieJhFIYQNU |
|
-k2jX2u8qZnAiNw93LZW9lpYjtuvMXq8QQppENNja5b53q7UwI+lU7ZGjZ7quuESp |
|
-J6/5 |
|
+cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg |
|
+Q0EgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgOkO3f7wzN6 |
|
+rOjg45tR5vjBfzK7qmV9IBxb/QW9EEXxG+E7FNhZqQLtwGBKoSsHTnQqV75wWMk0 |
|
+9tinWvftBkSpj5sTi/8cbzJfUvTSVYh3Qxv6AVVjMMH/ruLjE6y+4PoaPs8WoYAQ |
|
+ts5R4Z1g8c/WnTepLst2x0/Wv7GmuoQi+gXvHU6YrBiu7XkeYhzc95QdviWSJRDk |
|
+owhb5K43qhcvjRmBfO/paGlCliDGZp8mHwrI21mwobWpVjTxZRwYO3bd4+TGcI4G |
|
+Ie5wmHwE8F7SK1tgSqbBacKjDa93j7txKkfz/Yd2n7TGqOXiHPsJpG655vrKtnXk |
|
+9vs1zoDeJQIDAQABo4IBljCCAZIwHQYDVR0OBBYEFAdEdoWTKLx/bXjSCuv6TEvf |
|
+2YIfMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMCAGA1UdJQQZ |
|
+MBcGCisGAQQBgjcKAwMGCWCGSAGG+EIEATAYBgNVHSAEETAPMA0GCysGAQQBgOU3 |
|
+AgQBMHsGA1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0Fk |
|
+ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9k |
|
+by5uZXQvQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwgYAGCCsGAQUFBwEBBHQw |
|
+cjA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21vZG9jYS5jb20vQWRkVHJ1c3RV |
|
+VE5TR0NDQS5jcnQwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvLm5ldC9B |
|
+ZGRUcnVzdFVUTlNHQ0NBLmNydDARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcN |
|
+AQEFBQADggEBAK2zEzs+jcIrVK9oDkdDZNvhuBYTdCfpxfFs+OAujW0bIfJAy232 |
|
+euVsnJm6u/+OrqKudD2tad2BbejLLXhMZViaCmK7D9nrXHx4te5EP8rL19SUVqLY |
|
+1pTnv5dhNgEgvA7n5lIzDSYs7yRLsr7HJsYPr6SeYSuZizyX1SNz7ooJ32/F3X98 |
|
+RB0Mlc/E0OyOrkQ9/y5IrnpnaSora8CnUrV5XNOg+kyCz9edCyx4D5wXYcwZPVWz |
|
+8aDqquESrezPyjtfi4WRO4s/VD3HLZvOxzMrWAVYCDG9FxaOhF0QGuuG1F7F3GKV |
|
+v6prNyCl016kRl2j1UT+a7gLd8fA25A4C9E= |
|
-----END CERTIFICATE----- |
|
2 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root |
|
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware |
|
+ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC |
|
-----BEGIN CERTIFICATE----- |
|
-MIIETzCCAzegAwIBAgIQHM5EYpUZep1jUvnyI6m2mDANBgkqhkiG9w0BAQUFADCB |
|
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug |
|
+MIIEZjCCA06gAwIBAgIQUSYKkxzif5zDpV954HKugjANBgkqhkiG9w0BAQUFADCB |
|
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug |
|
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho |
|
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt |
|
-SGFyZHdhcmUwHhcNMDUwNjA3MDgwOTEwWhcNMTkwNzA5MTgxOTIyWjBvMQswCQYD |
|
-VQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0 |
|
-IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h |
|
-bCBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt/caM+by |
|
-AAQtOeBOW+0fvGwPzbX6I7bO3psRM5ekKUx9k5+9SryT7QMa44/P5W1QWtaXKZRa |
|
-gLBJetsulf24yr83OC0ePpFBrXBWx/BPP+gynnTKyJBU6cZfD3idmkA8Dqxhql4U |
|
-j56HoWpQ3NeaTq8Fs6ZxlJxxs1BgCscTnTgHhgKo6ahpJhiQq0ywTyOrOk+E2N/O |
|
-n+Fpb7vXQtdrROTHre5tQV9yWnEIN7N5ZaRZoJQ39wAvDcKSctrQOHLbFKhFxF0q |
|
-fbe01sTurM0TRLfJK91DACX6YblpalgjEbenM49WdVn1zSnXRrcKK2W200JvFbK4 |
|
-e/vv6V1T1TRaJwIDAQABo4G9MIG6MB8GA1UdIwQYMBaAFKFyXyYbKJhDlV0HN9WF |
|
-lp1L0sNFMB0GA1UdDgQWBBStvZh6NLQm9/rEJlTvA73gJMtUGjAOBgNVHQ8BAf8E |
|
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQIwRAYDVR0f |
|
-BD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly |
|
-c3QtSGFyZHdhcmUuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQByQhANOs4kClrwF8BW |
|
-onvUOGCSjRK52zYZgDXYNjDtmr5rJ6NyPFDNn+JxkLpjYetIFMTbSRe679Bt8m7a |
|
-gIAoQYFQtxMuyLnJegB2aEbQiIxh/tC21UcFF7ktdnDoTlA6w3pLuvunaI84Of3o |
|
-2YBrhzkTbCfaYk5JRlTpudW9DkUkHBsyx3nknPKnplkIGaK0jgn8E0n+SFabYaHk |
|
-I9LroYT/+JtLefh9lgBdAgVv0UPbzoGfuDsrk/Zh+UrgbLFpHoVnElhzbkh64Z0X |
|
-OGaJunQc68cCZu5HTn/aK7fBGMcVflRCXLVEQpU9PIAdGA8Ynvg684t8GMaKsRl1 |
|
-jIGZ |
|
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw |
|
+IFNHQzAeFw0wNTA2MDcwODA5MTBaFw0xOTA2MjQxOTA2MzBaMG8xCzAJBgNVBAYT |
|
+AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0 |
|
+ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB |
|
+IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39xoz5vIABC05 |
|
+4E5b7R+8bA/Ntfojts7emxEzl6QpTH2Tn71KvJPtAxrjj8/lbVBa1pcplFqAsEl6 |
|
+2y6V/bjKvzc4LR4+kUGtcFbH8E8/6DKedMrIkFTpxl8PeJ2aQDwOrGGqXhSPnoeh |
|
+alDc15pOrwWzpnGUnHGzUGAKxxOdOAeGAqjpqGkmGJCrTLBPI6s6T4TY386f4Wlv |
|
+u9dC12tE5Met7m1BX3JacQg3s3llpFmglDf3AC8NwpJy2tA4ctsUqEXEXSp9t7TW |
|
+xO6szRNEt8kr3UMAJfphuWlqWCMRt6czj1Z1WfXNKddGtworZbbTQm8Vsrh7++/p |
|
+XVPVNFonAgMBAAGjgdgwgdUwHwYDVR0jBBgwFoAUUzLRs89/+uDxoF2FTpLSnkUd |
|
+tE8wHQYDVR0OBBYEFK29mHo0tCb3+sQmVO8DveAky1QaMA4GA1UdDwEB/wQEAwIB |
|
+BjAPBgNVHRMBAf8EBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIBAjAgBgNVHSUEGTAX |
|
+BgorBgEEAYI3CgMDBglghkgBhvhCBAEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov |
|
+L2NybC51c2VydHJ1c3QuY29tL1VUTi1EQVRBQ29ycFNHQy5jcmwwDQYJKoZIhvcN |
|
+AQEFBQADggEBAMbuUxdoFLJRIh6QWA2U/b3xcOWGLcM2MY9USEbnLQg3vGwKYOEO |
|
+rVE04BKT6b64q7gmtOmWPSiPrmQH/uAB7MXjkesYoPF1ftsK5p+R26+udd8jkWjd |
|
+FwBaS/9kbHDrARrQkNnHptZt9hPk/7XJ0h4qy7ElQyZ42TCbTg0evmnv3+r+LbPM |
|
++bDdtRTKkdSytaX7ARmjR3mfnYyVhzT4HziS2jamEfpr62vp3EV4FTkG101B5CHI |
|
+3C+H0be/SGB1pWLLJN47YaApIKa+xWycxOkKaSLvkTr6Jq/RW0GnOuL4OAdCq8Fb |
|
++M5tug8EPzI0rNwEKNdwMBQmBsTkm5jVz3g= |
|
-----END CERTIFICATE----- |
|
- 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware |
|
- i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware |
|
+ 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC |
|
+ i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC |
|
-----BEGIN CERTIFICATE----- |
|
-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB |
|
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug |
|
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB |
|
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug |
|
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho |
|
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt |
|
-SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG |
|
-A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe |
|
-MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v |
|
-d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh |
|
-cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn |
|
-0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ |
|
-M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a |
|
-MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd |
|
-oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI |
|
-DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy |
|
-oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD |
|
-VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 |
|
-dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy |
|
-bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF |
|
-BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM |
|
-//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli |
|
-CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE |
|
-CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t |
|
-3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS |
|
-KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== |
|
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw |
|
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG |
|
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD |
|
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu |
|
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN |
|
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 |
|
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ |
|
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK |
|
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq |
|
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW |
|
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB |
|
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT |
|
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js |
|
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr |
|
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB |
|
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft |
|
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj |
|
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH |
|
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv |
|
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 |
|
+mfnGV/TJVTl4uix5yaaIK/QI |
|
-----END CERTIFICATE----- |
|
diff --git a/Lib/test/ssl_cert.pem b/Lib/test/ssl_cert.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/ssl_cert.pem |
|
@@ -0,0 +1,15 @@ |
|
+-----BEGIN CERTIFICATE----- |
|
+MIICVDCCAb2gAwIBAgIJANfHOBkZr8JOMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV |
|
+BAYTAlhZMRcwFQYDVQQHEw5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9u |
|
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMDEw |
|
+MDgyMzAxNTZaFw0yMDEwMDUyMzAxNTZaMF8xCzAJBgNVBAYTAlhZMRcwFQYDVQQH |
|
+Ew5DYXN0bGUgQW50aHJheDEjMCEGA1UEChMaUHl0aG9uIFNvZnR3YXJlIEZvdW5k |
|
+YXRpb24xEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw |
|
+gYkCgYEA21vT5isq7F68amYuuNpSFlKDPrMUCa4YWYqZRt2OZ+/3NKaZ2xAiSwr7 |
|
+6MrQF70t5nLbSPpqE5+5VrS58SY+g/sXLiFd6AplH1wJZwh78DofbFYXUggktFMt |
|
+pTyiX8jtP66bkcPkDADA089RI1TQR6Ca+n7HFa7c1fabVV6i3zkCAwEAAaMYMBYw |
|
+FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBBQUAA4GBAHPctQBEQ4wd |
|
+BJ6+JcpIraopLn8BGhbjNWj40mmRqWB/NAWF6M5ne7KpGAu7tLeG4hb1zLaldK8G |
|
+lxy2GPSRF6LFS48dpEj2HbMv2nvv6xxalDMJ9+DicWgAKTQ6bcX2j3GUkCR0g/T1 |
|
+CRlNBAAlvhKzO7Clpf9l0YKBEfraJByX |
|
+-----END CERTIFICATE----- |
|
diff --git a/Lib/test/ssl_key.passwd.pem b/Lib/test/ssl_key.passwd.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/ssl_key.passwd.pem |
|
@@ -0,0 +1,18 @@ |
|
+-----BEGIN RSA PRIVATE KEY----- |
|
+Proc-Type: 4,ENCRYPTED |
|
+DEK-Info: DES-EDE3-CBC,1A8D9D2A02EC698A |
|
+ |
|
+kJYbfZ8L0sfe9Oty3gw0aloNnY5E8fegRfQLZlNoxTl6jNt0nIwI8kDJ36CZgR9c |
|
+u3FDJm/KqrfUoz8vW+qEnWhSG7QPX2wWGPHd4K94Yz/FgrRzZ0DoK7XxXq9gOtVA |
|
+AVGQhnz32p+6WhfGsCr9ArXEwRZrTk/FvzEPaU5fHcoSkrNVAGX8IpSVkSDwEDQr |
|
+Gv17+cfk99UV1OCza6yKHoFkTtrC+PZU71LomBabivS2Oc4B9hYuSR2hF01wTHP+ |
|
+YlWNagZOOVtNz4oKK9x9eNQpmfQXQvPPTfusexKIbKfZrMvJoxcm1gfcZ0H/wK6P |
|
+6wmXSG35qMOOztCZNtperjs1wzEBXznyK8QmLcAJBjkfarABJX9vBEzZV0OUKhy+ |
|
+noORFwHTllphbmydLhu6ehLUZMHPhzAS5UN7srtpSN81eerDMy0RMUAwA7/PofX1 |
|
+94Me85Q8jP0PC9ETdsJcPqLzAPETEYu0ELewKRcrdyWi+tlLFrpE5KT/s5ecbl9l |
|
+7B61U4Kfd1PIXc/siINhU3A3bYK+845YyUArUOnKf1kEox7p1RpD7yFqVT04lRTo |
|
+cibNKATBusXSuBrp2G6GNuhWEOSafWCKJQAzgCYIp6ZTV2khhMUGppc/2H3CF6cO |
|
+zX0KtlPVZC7hLkB6HT8SxYUwF1zqWY7+/XPPdc37MeEZ87Q3UuZwqORLY+Z0hpgt |
|
+L5JXBCoklZhCAaN2GqwFLXtGiRSRFGY7xXIhbDTlE65Wv1WGGgDLMKGE1gOz3yAo |
|
+2jjG1+yAHJUdE69XTFHSqSkvaloA1W03LdMXZ9VuQJ/ySXCie6ABAQ== |
|
+-----END RSA PRIVATE KEY----- |
|
diff --git a/Lib/test/ssl_key.pem b/Lib/test/ssl_key.pem |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/ssl_key.pem |
|
@@ -0,0 +1,16 @@ |
|
+-----BEGIN PRIVATE KEY----- |
|
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANtb0+YrKuxevGpm |
|
+LrjaUhZSgz6zFAmuGFmKmUbdjmfv9zSmmdsQIksK++jK0Be9LeZy20j6ahOfuVa0 |
|
+ufEmPoP7Fy4hXegKZR9cCWcIe/A6H2xWF1IIJLRTLaU8ol/I7T+um5HD5AwAwNPP |
|
+USNU0Eegmvp+xxWu3NX2m1Veot85AgMBAAECgYA3ZdZ673X0oexFlq7AAmrutkHt |
|
+CL7LvwrpOiaBjhyTxTeSNWzvtQBkIU8DOI0bIazA4UreAFffwtvEuPmonDb3F+Iq |
|
+SMAu42XcGyVZEl+gHlTPU9XRX7nTOXVt+MlRRRxL6t9GkGfUAXI3XxJDXW3c0vBK |
|
+UL9xqD8cORXOfE06rQJBAP8mEX1ERkR64Ptsoe4281vjTlNfIbs7NMPkUnrn9N/Y |
|
+BLhjNIfQ3HFZG8BTMLfX7kCS9D593DW5tV4Z9BP/c6cCQQDcFzCcVArNh2JSywOQ |
|
+ZfTfRbJg/Z5Lt9Fkngv1meeGNPgIMLN8Sg679pAOOWmzdMO3V706rNPzSVMME7E5 |
|
+oPIfAkEA8pDddarP5tCvTTgUpmTFbakm0KoTZm2+FzHcnA4jRh+XNTjTOv98Y6Ik |
|
+eO5d1ZnKXseWvkZncQgxfdnMqqpj5wJAcNq/RVne1DbYlwWchT2Si65MYmmJ8t+F |
|
+0mcsULqjOnEMwf5e+ptq5LzwbyrHZYq5FNk7ocufPv/ZQrcSSC+cFwJBAKvOJByS |
|
+x56qyGeZLOQlWS2JS3KJo59XuLFGqcbgN9Om9xFa41Yb4N9NvplFivsvZdw3m1Q/ |
|
+SPIXQuT8RMPDVNQ= |
|
+-----END PRIVATE KEY----- |
|
diff --git a/Lib/test/ssl_servers.py b/Lib/test/ssl_servers.py |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Lib/test/ssl_servers.py |
|
@@ -0,0 +1,209 @@ |
|
+import os |
|
+import sys |
|
+import ssl |
|
+import pprint |
|
+import urllib |
|
+import urlparse |
|
+# Rename HTTPServer to _HTTPServer so as to avoid confusion with HTTPSServer. |
|
+from BaseHTTPServer import HTTPServer as _HTTPServer, BaseHTTPRequestHandler |
|
+from SimpleHTTPServer import SimpleHTTPRequestHandler |
|
+ |
|
+from test import test_support as support |
|
+threading = support.import_module("threading") |
|
+ |
|
+here = os.path.dirname(__file__) |
|
+ |
|
+HOST = support.HOST |
|
+CERTFILE = os.path.join(here, 'keycert.pem') |
|
+ |
|
+# This one's based on HTTPServer, which is based on SocketServer |
|
+ |
|
+class HTTPSServer(_HTTPServer): |
|
+ |
|
+ def __init__(self, server_address, handler_class, context): |
|
+ _HTTPServer.__init__(self, server_address, handler_class) |
|
+ self.context = context |
|
+ |
|
+ def __str__(self): |
|
+ return ('<%s %s:%s>' % |
|
+ (self.__class__.__name__, |
|
+ self.server_name, |
|
+ self.server_port)) |
|
+ |
|
+ def get_request(self): |
|
+ # override this to wrap socket with SSL |
|
+ try: |
|
+ sock, addr = self.socket.accept() |
|
+ sslconn = self.context.wrap_socket(sock, server_side=True) |
|
+ except OSError as e: |
|
+ # socket errors are silenced by the caller, print them here |
|
+ if support.verbose: |
|
+ sys.stderr.write("Got an error:\n%s\n" % e) |
|
+ raise |
|
+ return sslconn, addr |
|
+ |
|
+class RootedHTTPRequestHandler(SimpleHTTPRequestHandler): |
|
+ # need to override translate_path to get a known root, |
|
+ # instead of using os.curdir, since the test could be |
|
+ # run from anywhere |
|
+ |
|
+ server_version = "TestHTTPS/1.0" |
|
+ root = here |
|
+ # Avoid hanging when a request gets interrupted by the client |
|
+ timeout = 5 |
|
+ |
|
+ def translate_path(self, path): |
|
+ """Translate a /-separated PATH to the local filename syntax. |
|
+ |
|
+ Components that mean special things to the local file system |
|
+ (e.g. drive or directory names) are ignored. (XXX They should |
|
+ probably be diagnosed.) |
|
+ |
|
+ """ |
|
+ # abandon query parameters |
|
+ path = urlparse.urlparse(path)[2] |
|
+ path = os.path.normpath(urllib.unquote(path)) |
|
+ words = path.split('/') |
|
+ words = filter(None, words) |
|
+ path = self.root |
|
+ for word in words: |
|
+ drive, word = os.path.splitdrive(word) |
|
+ head, word = os.path.split(word) |
|
+ path = os.path.join(path, word) |
|
+ return path |
|
+ |
|
+ def log_message(self, format, *args): |
|
+ # we override this to suppress logging unless "verbose" |
|
+ if support.verbose: |
|
+ sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" % |
|
+ (self.server.server_address, |
|
+ self.server.server_port, |
|
+ self.request.cipher(), |
|
+ self.log_date_time_string(), |
|
+ format%args)) |
|
+ |
|
+ |
|
+class StatsRequestHandler(BaseHTTPRequestHandler): |
|
+ """Example HTTP request handler which returns SSL statistics on GET |
|
+ requests. |
|
+ """ |
|
+ |
|
+ server_version = "StatsHTTPS/1.0" |
|
+ |
|
+ def do_GET(self, send_body=True): |
|
+ """Serve a GET request.""" |
|
+ sock = self.rfile.raw._sock |
|
+ context = sock.context |
|
+ stats = { |
|
+ 'session_cache': context.session_stats(), |
|
+ 'cipher': sock.cipher(), |
|
+ 'compression': sock.compression(), |
|
+ } |
|
+ body = pprint.pformat(stats) |
|
+ body = body.encode('utf-8') |
|
+ self.send_response(200) |
|
+ self.send_header("Content-type", "text/plain; charset=utf-8") |
|
+ self.send_header("Content-Length", str(len(body))) |
|
+ self.end_headers() |
|
+ if send_body: |
|
+ self.wfile.write(body) |
|
+ |
|
+ def do_HEAD(self): |
|
+ """Serve a HEAD request.""" |
|
+ self.do_GET(send_body=False) |
|
+ |
|
+ def log_request(self, format, *args): |
|
+ if support.verbose: |
|
+ BaseHTTPRequestHandler.log_request(self, format, *args) |
|
+ |
|
+ |
|
+class HTTPSServerThread(threading.Thread): |
|
+ |
|
+ def __init__(self, context, host=HOST, handler_class=None): |
|
+ self.flag = None |
|
+ self.server = HTTPSServer((host, 0), |
|
+ handler_class or RootedHTTPRequestHandler, |
|
+ context) |
|
+ self.port = self.server.server_port |
|
+ threading.Thread.__init__(self) |
|
+ self.daemon = True |
|
+ |
|
+ def __str__(self): |
|
+ return "<%s %s>" % (self.__class__.__name__, self.server) |
|
+ |
|
+ def start(self, flag=None): |
|
+ self.flag = flag |
|
+ threading.Thread.start(self) |
|
+ |
|
+ def run(self): |
|
+ if self.flag: |
|
+ self.flag.set() |
|
+ try: |
|
+ self.server.serve_forever(0.05) |
|
+ finally: |
|
+ self.server.server_close() |
|
+ |
|
+ def stop(self): |
|
+ self.server.shutdown() |
|
+ |
|
+ |
|
+def make_https_server(case, context=None, certfile=CERTFILE, |
|
+ host=HOST, handler_class=None): |
|
+ if context is None: |
|
+ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) |
|
+ # We assume the certfile contains both private key and certificate |
|
+ context.load_cert_chain(certfile) |
|
+ server = HTTPSServerThread(context, host, handler_class) |
|
+ flag = threading.Event() |
|
+ server.start(flag) |
|
+ flag.wait() |
|
+ def cleanup(): |
|
+ if support.verbose: |
|
+ sys.stdout.write('stopping HTTPS server\n') |
|
+ server.stop() |
|
+ if support.verbose: |
|
+ sys.stdout.write('joining HTTPS thread\n') |
|
+ server.join() |
|
+ case.addCleanup(cleanup) |
|
+ return server |
|
+ |
|
+ |
|
+if __name__ == "__main__": |
|
+ import argparse |
|
+ parser = argparse.ArgumentParser( |
|
+ description='Run a test HTTPS server. ' |
|
+ 'By default, the current directory is served.') |
|
+ parser.add_argument('-p', '--port', type=int, default=4433, |
|
+ help='port to listen on (default: %(default)s)') |
|
+ parser.add_argument('-q', '--quiet', dest='verbose', default=True, |
|
+ action='store_false', help='be less verbose') |
|
+ parser.add_argument('-s', '--stats', dest='use_stats_handler', default=False, |
|
+ action='store_true', help='always return stats page') |
|
+ parser.add_argument('--curve-name', dest='curve_name', type=str, |
|
+ action='store', |
|
+ help='curve name for EC-based Diffie-Hellman') |
|
+ parser.add_argument('--ciphers', dest='ciphers', type=str, |
|
+ help='allowed cipher list') |
|
+ parser.add_argument('--dh', dest='dh_file', type=str, action='store', |
|
+ help='PEM file containing DH parameters') |
|
+ args = parser.parse_args() |
|
+ |
|
+ support.verbose = args.verbose |
|
+ if args.use_stats_handler: |
|
+ handler_class = StatsRequestHandler |
|
+ else: |
|
+ handler_class = RootedHTTPRequestHandler |
|
+ handler_class.root = os.getcwd() |
|
+ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ if args.curve_name: |
|
+ context.set_ecdh_curve(args.curve_name) |
|
+ if args.dh_file: |
|
+ context.load_dh_params(args.dh_file) |
|
+ if args.ciphers: |
|
+ context.set_ciphers(args.ciphers) |
|
+ |
|
+ server = HTTPSServer(("", args.port), handler_class, context) |
|
+ if args.verbose: |
|
+ print("Listening on https://localhost:{0.port}".format(args)) |
|
+ server.serve_forever(0.1) |
|
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py |
|
--- a/Lib/test/test_support.py |
|
+++ b/Lib/test/test_support.py |
|
@@ -39,7 +39,7 @@ except ImportError: |
|
"threading_cleanup", "reap_children", "cpython_only", |
|
"check_impl_detail", "get_attribute", "py3k_bytes", |
|
"import_fresh_module", "threading_cleanup", "reap_children", |
|
- "strip_python_stderr"] |
|
+ "strip_python_stderr", "IPV6_ENABLED"] |
|
|
|
class Error(Exception): |
|
"""Base class for regression test exceptions.""" |
|
@@ -465,6 +465,23 @@ def bind_port(sock, host=HOST): |
|
port = sock.getsockname()[1] |
|
return port |
|
|
|
+def _is_ipv6_enabled(): |
|
+ """Check whether IPv6 is enabled on this host.""" |
|
+ if socket.has_ipv6: |
|
+ sock = None |
|
+ try: |
|
+ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) |
|
+ sock.bind((HOSTv6, 0)) |
|
+ return True |
|
+ except OSError: |
|
+ pass |
|
+ finally: |
|
+ if sock: |
|
+ sock.close() |
|
+ return False |
|
+ |
|
+IPV6_ENABLED = _is_ipv6_enabled() |
|
+ |
|
FUZZ = 1e-6 |
|
|
|
def fcmp(x, y): # fuzzy comparison function |
|
diff --git a/Tools/ssl/make_ssl_data.py b/Tools/ssl/make_ssl_data.py |
|
new file mode 100755 |
|
--- /dev/null |
|
+++ b/Tools/ssl/make_ssl_data.py |
|
@@ -0,0 +1,68 @@ |
|
+#! /usr/bin/env python3 |
|
+ |
|
+""" |
|
+This script should be called *manually* when we want to upgrade SSLError |
|
+`library` and `reason` mnemnonics to a more recent OpenSSL version. |
|
+ |
|
+It takes two arguments: |
|
+- the path to the OpenSSL include files' directory |
|
+ (e.g. openssl-1.0.1-beta3/include/openssl/) |
|
+- the path to the C file to be generated |
|
+ (probably Modules/_ssl_data.h) |
|
+""" |
|
+ |
|
+import datetime |
|
+import os |
|
+import re |
|
+import sys |
|
+ |
|
+ |
|
+def parse_error_codes(h_file, prefix): |
|
+ pat = re.compile(r"#define\W+(%s([\w]+))\W+(\d+)\b" % re.escape(prefix)) |
|
+ codes = [] |
|
+ with open(h_file, "r", encoding="latin1") as f: |
|
+ for line in f: |
|
+ match = pat.search(line) |
|
+ if match: |
|
+ code, name, num = match.groups() |
|
+ num = int(num) |
|
+ codes.append((code, name, num)) |
|
+ return codes |
|
+ |
|
+if __name__ == "__main__": |
|
+ openssl_inc = sys.argv[1] |
|
+ outfile = sys.argv[2] |
|
+ use_stdout = outfile == '-' |
|
+ f = sys.stdout if use_stdout else open(outfile, "w") |
|
+ error_libraries = ( |
|
+ # (library code, mnemonic, error prefix, header file) |
|
+ ('ERR_LIB_PEM', 'PEM', 'PEM_R_', 'pem.h'), |
|
+ ('ERR_LIB_SSL', 'SSL', 'SSL_R_', 'ssl.h'), |
|
+ ('ERR_LIB_X509', 'X509', 'X509_R_', 'x509.h'), |
|
+ ) |
|
+ def w(l): |
|
+ f.write(l + "\n") |
|
+ w("/* File generated by Tools/ssl/make_ssl_data.py */") |
|
+ w("/* Generated on %s */" % datetime.datetime.now().isoformat()) |
|
+ w("") |
|
+ |
|
+ w("static struct py_ssl_library_code library_codes[] = {") |
|
+ for libcode, mnemo, _, _ in error_libraries: |
|
+ w(' {"%s", %s},' % (mnemo, libcode)) |
|
+ w(' { NULL }') |
|
+ w('};') |
|
+ w("") |
|
+ |
|
+ w("static struct py_ssl_error_code error_codes[] = {") |
|
+ for libcode, _, prefix, h_file in error_libraries: |
|
+ codes = parse_error_codes(os.path.join(openssl_inc, h_file), prefix) |
|
+ for code, name, num in sorted(codes): |
|
+ w(' #ifdef %s' % (code)) |
|
+ w(' {"%s", %s, %s},' % (name, libcode, code)) |
|
+ w(' #else') |
|
+ w(' {"%s", %s, %d},' % (name, libcode, num)) |
|
+ w(' #endif') |
|
+ w(' { NULL }') |
|
+ w('};') |
|
+ if not use_stdout: |
|
+ f.close() |
|
diff --git a/Tools/ssl/test_multiple_versions.py b/Tools/ssl/test_multiple_versions.py |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Tools/ssl/test_multiple_versions.py |
|
@@ -0,0 +1,241 @@ |
|
+#./python |
|
+"""Run Python tests with multiple installations of OpenSSL |
|
+ |
|
+The script |
|
+ |
|
+ (1) downloads OpenSSL tar bundle |
|
+ (2) extracts it to ../openssl/src/openssl-VERSION/ |
|
+ (3) compiles OpenSSL |
|
+ (4) installs OpenSSL into ../openssl/VERSION/ |
|
+ (5) forces a recompilation of Python modules using the |
|
+ header and library files from ../openssl/VERSION/ |
|
+ (6) runs Python's test suite |
|
+ |
|
+The script must be run with Python's build directory as current working |
|
+directory: |
|
+ |
|
+ ./python Tools/ssl/test_multiple_versions.py |
|
+ |
|
+The script uses LD_RUN_PATH, LD_LIBRARY_PATH, CPPFLAGS and LDFLAGS to bend |
|
+search paths for header files and shared libraries. It's known to work on |
|
+Linux with GCC 4.x. |
|
+ |
|
+(c) 2013 Christian Heimes <christian@python.org> |
|
+""" |
|
+import logging |
|
+import os |
|
+import tarfile |
|
+import shutil |
|
+import subprocess |
|
+import sys |
|
+from urllib import urlopen |
|
+ |
|
+log = logging.getLogger("multissl") |
|
+ |
|
+OPENSSL_VERSIONS = [ |
|
+ "0.9.7m", "0.9.8i", "0.9.8l", "0.9.8m", "0.9.8y", "1.0.0k", "1.0.1e" |
|
+] |
|
+FULL_TESTS = [ |
|
+ "test_asyncio", "test_ftplib", "test_hashlib", "test_httplib", |
|
+ "test_imaplib", "test_nntplib", "test_poplib", "test_smtplib", |
|
+ "test_smtpnet", "test_urllib2_localnet", "test_venv" |
|
+] |
|
+MINIMAL_TESTS = ["test_ssl", "test_hashlib"] |
|
+CADEFAULT = True |
|
+HERE = os.path.abspath(os.getcwd()) |
|
+DEST_DIR = os.path.abspath(os.path.join(HERE, os.pardir, "openssl")) |
|
+ |
|
+ |
|
+class BuildSSL(object): |
|
+ url_template = "https://www.openssl.org/source/openssl-{}.tar.gz" |
|
+ |
|
+ module_files = ["Modules/_ssl.c", |
|
+ "Modules/socketmodule.c", |
|
+ "Modules/_hashopenssl.c"] |
|
+ |
|
+ def __init__(self, version, openssl_compile_args=(), destdir=DEST_DIR): |
|
+ self._check_python_builddir() |
|
+ self.version = version |
|
+ self.openssl_compile_args = openssl_compile_args |
|
+ # installation directory |
|
+ self.install_dir = os.path.join(destdir, version) |
|
+ # source file |
|
+ self.src_file = os.path.join(destdir, "src", |
|
+ "openssl-{}.tar.gz".format(version)) |
|
+ # build directory (removed after install) |
|
+ self.build_dir = os.path.join(destdir, "src", |
|
+ "openssl-{}".format(version)) |
|
+ |
|
+ @property |
|
+ def openssl_cli(self): |
|
+ """openssl CLI binary""" |
|
+ return os.path.join(self.install_dir, "bin", "openssl") |
|
+ |
|
+ @property |
|
+ def openssl_version(self): |
|
+ """output of 'bin/openssl version'""" |
|
+ env = os.environ.copy() |
|
+ env["LD_LIBRARY_PATH"] = self.lib_dir |
|
+ cmd = [self.openssl_cli, "version"] |
|
+ return self._subprocess_output(cmd, env=env) |
|
+ |
|
+ @property |
|
+ def pyssl_version(self): |
|
+ """Value of ssl.OPENSSL_VERSION""" |
|
+ env = os.environ.copy() |
|
+ env["LD_LIBRARY_PATH"] = self.lib_dir |
|
+ cmd = ["./python", "-c", "import ssl; print(ssl.OPENSSL_VERSION)"] |
|
+ return self._subprocess_output(cmd, env=env) |
|
+ |
|
+ @property |
|
+ def include_dir(self): |
|
+ return os.path.join(self.install_dir, "include") |
|
+ |
|
+ @property |
|
+ def lib_dir(self): |
|
+ return os.path.join(self.install_dir, "lib") |
|
+ |
|
+ @property |
|
+ def has_openssl(self): |
|
+ return os.path.isfile(self.openssl_cli) |
|
+ |
|
+ @property |
|
+ def has_src(self): |
|
+ return os.path.isfile(self.src_file) |
|
+ |
|
+ def _subprocess_call(self, cmd, stdout=subprocess.DEVNULL, env=None, |
|
+ **kwargs): |
|
+ log.debug("Call '{}'".format(" ".join(cmd))) |
|
+ return subprocess.check_call(cmd, stdout=stdout, env=env, **kwargs) |
|
+ |
|
+ def _subprocess_output(self, cmd, env=None, **kwargs): |
|
+ log.debug("Call '{}'".format(" ".join(cmd))) |
|
+ out = subprocess.check_output(cmd, env=env) |
|
+ return out.strip().decode("utf-8") |
|
+ |
|
+ def _check_python_builddir(self): |
|
+ if not os.path.isfile("python") or not os.path.isfile("setup.py"): |
|
+ raise ValueError("Script must be run in Python build directory") |
|
+ |
|
+ def _download_openssl(self): |
|
+ """Download OpenSSL source dist""" |
|
+ src_dir = os.path.dirname(self.src_file) |
|
+ if not os.path.isdir(src_dir): |
|
+ os.makedirs(src_dir) |
|
+ url = self.url_template.format(self.version) |
|
+ log.info("Downloading OpenSSL from {}".format(url)) |
|
+ req = urlopen(url, cadefault=CADEFAULT) |
|
+ # KISS, read all, write all |
|
+ data = req.read() |
|
+ log.info("Storing {}".format(self.src_file)) |
|
+ with open(self.src_file, "wb") as f: |
|
+ f.write(data) |
|
+ |
|
+ def _unpack_openssl(self): |
|
+ """Unpack tar.gz bundle""" |
|
+ # cleanup |
|
+ if os.path.isdir(self.build_dir): |
|
+ shutil.rmtree(self.build_dir) |
|
+ os.makedirs(self.build_dir) |
|
+ |
|
+ tf = tarfile.open(self.src_file) |
|
+ base = "openssl-{}/".format(self.version) |
|
+ # force extraction into build dir |
|
+ members = tf.getmembers() |
|
+ for member in members: |
|
+ if not member.name.startswith(base): |
|
+ raise ValueError(member.name) |
|
+ member.name = member.name[len(base):] |
|
+ log.info("Unpacking files to {}".format(self.build_dir)) |
|
+ tf.extractall(self.build_dir, members) |
|
+ |
|
+ def _build_openssl(self): |
|
+ """Now build openssl""" |
|
+ log.info("Running build in {}".format(self.install_dir)) |
|
+ cwd = self.build_dir |
|
+ cmd = ["./config", "shared", "--prefix={}".format(self.install_dir)] |
|
+ cmd.extend(self.openssl_compile_args) |
|
+ self._subprocess_call(cmd, cwd=cwd) |
|
+ self._subprocess_call(["make"], cwd=cwd) |
|
+ |
|
+ def _install_openssl(self, remove=True): |
|
+ self._subprocess_call(["make", "install"], cwd=self.build_dir) |
|
+ if remove: |
|
+ shutil.rmtree(self.build_dir) |
|
+ |
|
+ def install_openssl(self): |
|
+ if not self.has_openssl: |
|
+ if not self.has_src: |
|
+ self._download_openssl() |
|
+ else: |
|
+ log.debug("Already has src {}".format(self.src_file)) |
|
+ self._unpack_openssl() |
|
+ self._build_openssl() |
|
+ self._install_openssl() |
|
+ else: |
|
+ log.info("Already has installation {}".format(self.install_dir)) |
|
+ # validate installation |
|
+ version = self.openssl_version |
|
+ if self.version not in version: |
|
+ raise ValueError(version) |
|
+ |
|
+ def touch_pymods(self): |
|
+ # force a rebuild of all modules that use OpenSSL APIs |
|
+ for fname in self.module_files: |
|
+ os.utime(fname) |
|
+ |
|
+ def recompile_pymods(self): |
|
+ log.info("Using OpenSSL build from {}".format(self.build_dir)) |
|
+ # overwrite header and library search paths |
|
+ env = os.environ.copy() |
|
+ env["CPPFLAGS"] = "-I{}".format(self.include_dir) |
|
+ env["LDFLAGS"] = "-L{}".format(self.lib_dir) |
|
+ # set rpath |
|
+ env["LD_RUN_PATH"] = self.lib_dir |
|
+ |
|
+ log.info("Rebuilding Python modules") |
|
+ self.touch_pymods() |
|
+ cmd = ["./python", "setup.py", "build"] |
|
+ self._subprocess_call(cmd, env=env) |
|
+ |
|
+ def check_pyssl(self): |
|
+ version = self.pyssl_version |
|
+ if self.version not in version: |
|
+ raise ValueError(version) |
|
+ |
|
+ def run_pytests(self, *args): |
|
+ cmd = ["./python", "-m", "test"] |
|
+ cmd.extend(args) |
|
+ self._subprocess_call(cmd, stdout=None) |
|
+ |
|
+ def run_python_tests(self, *args): |
|
+ self.recompile_pymods() |
|
+ self.check_pyssl() |
|
+ self.run_pytests(*args) |
|
+ |
|
+ |
|
+def main(*args): |
|
+ builders = [] |
|
+ for version in OPENSSL_VERSIONS: |
|
+ if version in ("0.9.8i", "0.9.8l"): |
|
+ openssl_compile_args = ("no-asm",) |
|
+ else: |
|
+ openssl_compile_args = () |
|
+ builder = BuildSSL(version, openssl_compile_args) |
|
+ builder.install_openssl() |
|
+ builders.append(builder) |
|
+ |
|
+ for builder in builders: |
|
+ builder.run_python_tests(*args) |
|
+ # final touch |
|
+ builder.touch_pymods() |
|
+ |
|
+ |
|
+if __name__ == "__main__": |
|
+ logging.basicConfig(level=logging.INFO, |
|
+ format="*** %(levelname)s %(message)s") |
|
+ args = sys.argv[1:] |
|
+ if not args: |
|
+ args = ["-unetwork", "-v"] |
|
+ args.extend(FULL_TESTS) |
|
+ main(*args) |
|
|
|
diff -up Python-2.7.5/Doc/library/ssl.rst.ssl Python-2.7.5/Doc/library/ssl.rst |
|
--- Python-2.7.5/Doc/library/ssl.rst.ssl 2015-02-24 11:37:44.278196135 +0100 |
|
+++ Python-2.7.5/Doc/library/ssl.rst 2015-02-24 09:24:25.135911989 +0100 |
|
@@ -28,7 +28,8 @@ probably additional platforms, as long a |
|
|
|
Some behavior may be platform dependent, since calls are made to the |
|
operating system socket APIs. The installed version of OpenSSL may also |
|
- cause variations in behavior. |
|
+ cause variations in behavior. For example, TLSv1.1 and TLSv1.2 come with |
|
+ openssl version 1.0.1. |
|
|
|
This section documents the objects and functions in the ``ssl`` module; for more |
|
general information about TLS, SSL, and certificates, the reader is referred to |
|
@@ -37,23 +38,101 @@ the documents in the "See Also" section |
|
This module provides a class, :class:`ssl.SSLSocket`, which is derived from the |
|
:class:`socket.socket` type, and provides a socket-like wrapper that also |
|
encrypts and decrypts the data going over the socket with SSL. It supports |
|
-additional :meth:`read` and :meth:`write` methods, along with a method, |
|
-:meth:`getpeercert`, to retrieve the certificate of the other side of the |
|
-connection, and a method, :meth:`cipher`, to retrieve the cipher being used for |
|
-the secure connection. |
|
+additional methods such as :meth:`getpeercert`, which retrieves the |
|
+certificate of the other side of the connection, and :meth:`cipher`,which |
|
+retrieves the cipher being used for the secure connection. |
|
+ |
|
+For more sophisticated applications, the :class:`ssl.SSLContext` class |
|
+helps manage settings and certificates, which can then be inherited |
|
+by SSL sockets created through the :meth:`SSLContext.wrap_socket` method. |
|
+ |
|
|
|
Functions, Constants, and Exceptions |
|
------------------------------------ |
|
|
|
.. exception:: SSLError |
|
|
|
- Raised to signal an error from the underlying SSL implementation. This |
|
- signifies some problem in the higher-level encryption and authentication |
|
- layer that's superimposed on the underlying network connection. This error |
|
- is a subtype of :exc:`socket.error`, which in turn is a subtype of |
|
- :exc:`IOError`. |
|
+ Raised to signal an error from the underlying SSL implementation (currently |
|
+ provided by the OpenSSL library). This signifies some problem in the |
|
+ higher-level encryption and authentication layer that's superimposed on the |
|
+ underlying network connection. This error is a subtype of |
|
+ :exc:`socket.error`, which in turn is a subtype of :exc:`IOError`. The |
|
+ error code and message of :exc:`SSLError` instances are provided by the |
|
+ OpenSSL library. |
|
+ |
|
+ .. attribute:: library |
|
+ |
|
+ A string mnemonic designating the OpenSSL submodule in which the error |
|
+ occurred, such as ``SSL``, ``PEM`` or ``X509``. The range of possible |
|
+ values depends on the OpenSSL version. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+ .. attribute:: reason |
|
+ |
|
+ A string mnemonic designating the reason this error occurred, for |
|
+ example ``CERTIFICATE_VERIFY_FAILED``. The range of possible |
|
+ values depends on the OpenSSL version. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. exception:: SSLZeroReturnError |
|
+ |
|
+ A subclass of :exc:`SSLError` raised when trying to read or write and |
|
+ the SSL connection has been closed cleanly. Note that this doesn't |
|
+ mean that the underlying transport (read TCP) has been closed. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. exception:: SSLWantReadError |
|
+ |
|
+ A subclass of :exc:`SSLError` raised by a :ref:`non-blocking SSL socket |
|
+ <ssl-nonblocking>` when trying to read or write data, but more data needs |
|
+ to be received on the underlying TCP transport before the request can be |
|
+ fulfilled. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. exception:: SSLWantWriteError |
|
+ |
|
+ A subclass of :exc:`SSLError` raised by a :ref:`non-blocking SSL socket |
|
+ <ssl-nonblocking>` when trying to read or write data, but more data needs |
|
+ to be sent on the underlying TCP transport before the request can be |
|
+ fulfilled. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
|
|
-.. function:: wrap_socket (sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None) |
|
+.. exception:: SSLSyscallError |
|
+ |
|
+ A subclass of :exc:`SSLError` raised when a system error was encountered |
|
+ while trying to fulfill an operation on a SSL socket. Unfortunately, |
|
+ there is no easy way to inspect the original errno number. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. exception:: SSLEOFError |
|
+ |
|
+ A subclass of :exc:`SSLError` raised when the SSL connection has been |
|
+ terminated abruptly. Generally, you shouldn't try to reuse the underlying |
|
+ transport when this error is encountered. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. exception:: CertificateError |
|
+ |
|
+ Raised to signal an error with a certificate (such as mismatching |
|
+ hostname). Certificate errors detected by OpenSSL, though, raise |
|
+ an :exc:`SSLError`. |
|
+ |
|
+ |
|
+Socket creation |
|
+^^^^^^^^^^^^^^^ |
|
+ |
|
+The following function allows for standalone socket creation. Starting from |
|
+Python 2.7.9, it can be more flexible to use :meth:`SSLContext.wrap_socket` |
|
+instead. |
|
+ |
|
+.. function:: wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version={see docs}, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None) |
|
|
|
Takes an instance ``sock`` of :class:`socket.socket`, and returns an instance |
|
of :class:`ssl.SSLSocket`, a subtype of :class:`socket.socket`, which wraps |
|
@@ -70,19 +149,6 @@ Functions, Constants, and Exceptions |
|
connection. See the discussion of :ref:`ssl-certificates` for more |
|
information on how the certificate is stored in the ``certfile``. |
|
|
|
- Often the private key is stored in the same file as the certificate; in this |
|
- case, only the ``certfile`` parameter need be passed. If the private key is |
|
- stored in a separate file, both parameters must be used. If the private key |
|
- is stored in the ``certfile``, it should come before the first certificate in |
|
- the certificate chain:: |
|
- |
|
- -----BEGIN RSA PRIVATE KEY----- |
|
- ... (private key in base64 encoding) ... |
|
- -----END RSA PRIVATE KEY----- |
|
- -----BEGIN CERTIFICATE----- |
|
- ... (certificate in base64 PEM encoding) ... |
|
- -----END CERTIFICATE----- |
|
- |
|
The parameter ``server_side`` is a boolean which identifies whether |
|
server-side or client-side behavior is desired from this socket. |
|
|
|
@@ -112,14 +178,16 @@ Functions, Constants, and Exceptions |
|
|
|
.. table:: |
|
|
|
- ======================== ========= ========= ========== ========= |
|
- *client* / **server** **SSLv2** **SSLv3** **SSLv23** **TLSv1** |
|
- ------------------------ --------- --------- ---------- --------- |
|
- *SSLv2* yes no yes no |
|
- *SSLv3* no yes yes no |
|
- *SSLv23* yes no yes no |
|
- *TLSv1* no no yes yes |
|
- ======================== ========= ========= ========== ========= |
|
+ ======================== ========= ========= ========== ========= =========== =========== |
|
+ *client* / **server** **SSLv2** **SSLv3** **SSLv23** **TLSv1** **TLSv1.1** **TLSv1.2** |
|
+ ------------------------ --------- --------- ---------- --------- ----------- ----------- |
|
+ *SSLv2* yes no yes no no no |
|
+ *SSLv3* no yes yes no no no |
|
+ *SSLv23* yes no yes no no no |
|
+ *TLSv1* no no yes yes no no |
|
+ *TLSv1.1* no no yes no yes no |
|
+ *TLSv1.2* no no yes no no yes |
|
+ ======================== ========= ========= ========== ========= =========== =========== |
|
|
|
.. note:: |
|
|
|
@@ -146,22 +214,79 @@ Functions, Constants, and Exceptions |
|
The parameter ``suppress_ragged_eofs`` specifies how the |
|
:meth:`SSLSocket.read` method should signal unexpected EOF from the other end |
|
of the connection. If specified as :const:`True` (the default), it returns a |
|
- normal EOF in response to unexpected EOF errors raised from the underlying |
|
- socket; if :const:`False`, it will raise the exceptions back to the caller. |
|
+ normal EOF (an empty bytes object) in response to unexpected EOF errors |
|
+ raised from the underlying socket; if :const:`False`, it will raise the |
|
+ exceptions back to the caller. |
|
|
|
.. versionchanged:: 2.7 |
|
New optional argument *ciphers*. |
|
|
|
+ |
|
+Context creation |
|
+^^^^^^^^^^^^^^^^ |
|
+ |
|
+A convenience function helps create :class:`SSLContext` objects for common |
|
+purposes. |
|
+ |
|
+.. function:: create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None) |
|
+ |
|
+ Return a new :class:`SSLContext` object with default settings for |
|
+ the given *purpose*. The settings are chosen by the :mod:`ssl` module, |
|
+ and usually represent a higher security level than when calling the |
|
+ :class:`SSLContext` constructor directly. |
|
+ |
|
+ *cafile*, *capath*, *cadata* represent optional CA certificates to |
|
+ trust for certificate verification, as in |
|
+ :meth:`SSLContext.load_verify_locations`. If all three are |
|
+ :const:`None`, this function can choose to trust the system's default |
|
+ CA certificates instead. |
|
+ |
|
+ The settings in Python 2.7.9 are: :data:`PROTOCOL_SSLv23`, |
|
+ :data:`OP_NO_SSLv2`, and :data:`OP_NO_SSLv3` with high encryption cipher |
|
+ suites without RC4 and without unauthenticated cipher suites. Passing |
|
+ :data:`~Purpose.SERVER_AUTH` as *purpose* sets |
|
+ :data:`~SSLContext.verify_mode` to :data:`CERT_REQUIRED` and either loads CA |
|
+ certificates (when at least one of *cafile*, *capath* or *cadata* is given) |
|
+ or uses :meth:`SSLContext.load_default_certs` to load default CA |
|
+ certificates. |
|
+ |
|
+ .. note:: |
|
+ The protocol, options, cipher and other settings may change to more |
|
+ restrictive values anytime without prior deprecation. The values |
|
+ represent a fair balance between compatibility and security. |
|
+ |
|
+ If your application needs specific settings, you should create a |
|
+ :class:`SSLContext` and apply the settings yourself. |
|
+ |
|
+ .. note:: |
|
+ If you find that when certain older clients or servers attempt to connect |
|
+ with a :class:`SSLContext` created by this function that they get an |
|
+ error stating "Protocol or cipher suite mismatch", it may be that they |
|
+ only support SSL3.0 which this function excludes using the |
|
+ :data:`OP_NO_SSLv3`. SSL3.0 has problematic security due to a number of |
|
+ poor implementations and it's reliance on MD5 within the protocol. If you |
|
+ wish to continue to use this function but still allow SSL 3.0 connections |
|
+ you can re-enable them using:: |
|
+ |
|
+ ctx = ssl.create_default_context(Purpose.CLIENT_AUTH) |
|
+ ctx.options &= ~ssl.OP_NO_SSLv3 |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+ |
|
+Random generation |
|
+^^^^^^^^^^^^^^^^^ |
|
+ |
|
.. function:: RAND_status() |
|
|
|
Returns True if the SSL pseudo-random number generator has been seeded with |
|
- 'enough' randomness, and False otherwise. You can use :func:`ssl.RAND_egd` |
|
+ 'enough' randomness, and ``False`` otherwise. You can use :func:`ssl.RAND_egd` |
|
and :func:`ssl.RAND_add` to increase the randomness of the pseudo-random |
|
number generator. |
|
|
|
.. function:: RAND_egd(path) |
|
|
|
- If you are running an entropy-gathering daemon (EGD) somewhere, and ``path`` |
|
+ If you are running an entropy-gathering daemon (EGD) somewhere, and *path* |
|
is the pathname of a socket connection open to it, this will read 256 bytes |
|
of randomness from the socket, and add it to the SSL pseudo-random number |
|
generator to increase the security of generated secret keys. This is |
|
@@ -172,28 +297,66 @@ Functions, Constants, and Exceptions |
|
|
|
.. function:: RAND_add(bytes, entropy) |
|
|
|
- Mixes the given ``bytes`` into the SSL pseudo-random number generator. The |
|
- parameter ``entropy`` (a float) is a lower bound on the entropy contained in |
|
+ Mixes the given *bytes* into the SSL pseudo-random number generator. The |
|
+ parameter *entropy* (a float) is a lower bound on the entropy contained in |
|
string (so you can always use :const:`0.0`). See :rfc:`1750` for more |
|
information on sources of entropy. |
|
|
|
-.. function:: cert_time_to_seconds(timestring) |
|
+Certificate handling |
|
+^^^^^^^^^^^^^^^^^^^^ |
|
+ |
|
+.. function:: match_hostname(cert, hostname) |
|
+ |
|
+ Verify that *cert* (in decoded format as returned by |
|
+ :meth:`SSLSocket.getpeercert`) matches the given *hostname*. The rules |
|
+ applied are those for checking the identity of HTTPS servers as outlined |
|
+ in :rfc:`2818` and :rfc:`6125`, except that IP addresses are not currently |
|
+ supported. In addition to HTTPS, this function should be suitable for |
|
+ checking the identity of servers in various SSL-based protocols such as |
|
+ FTPS, IMAPS, POPS and others. |
|
|
|
- Returns a floating-point value containing a normal seconds-after-the-epoch |
|
- time value, given the time-string representing the "notBefore" or "notAfter" |
|
- date from a certificate. |
|
- |
|
- Here's an example:: |
|
- |
|
- >>> import ssl |
|
- >>> ssl.cert_time_to_seconds("May 9 00:00:00 2007 GMT") |
|
- 1178694000.0 |
|
- >>> import time |
|
- >>> time.ctime(ssl.cert_time_to_seconds("May 9 00:00:00 2007 GMT")) |
|
- 'Wed May 9 00:00:00 2007' |
|
- >>> |
|
+ :exc:`CertificateError` is raised on failure. On success, the function |
|
+ returns nothing:: |
|
|
|
-.. function:: get_server_certificate (addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None) |
|
+ >>> cert = {'subject': ((('commonName', 'example.com'),),)} |
|
+ >>> ssl.match_hostname(cert, "example.com") |
|
+ >>> ssl.match_hostname(cert, "example.org") |
|
+ Traceback (most recent call last): |
|
+ File "<stdin>", line 1, in <module> |
|
+ File "/home/py3k/Lib/ssl.py", line 130, in match_hostname |
|
+ ssl.CertificateError: hostname 'example.org' doesn't match 'example.com' |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+ |
|
+.. function:: cert_time_to_seconds(cert_time) |
|
+ |
|
+ Return the time in seconds since the Epoch, given the ``cert_time`` |
|
+ string representing the "notBefore" or "notAfter" date from a |
|
+ certificate in ``"%b %d %H:%M:%S %Y %Z"`` strptime format (C |
|
+ locale). |
|
+ |
|
+ Here's an example: |
|
+ |
|
+ .. doctest:: newcontext |
|
+ |
|
+ >>> import ssl |
|
+ >>> timestamp = ssl.cert_time_to_seconds("Jan 5 09:34:43 2018 GMT") |
|
+ >>> timestamp |
|
+ 1515144883 |
|
+ >>> from datetime import datetime |
|
+ >>> print(datetime.utcfromtimestamp(timestamp)) |
|
+ 2018-01-05 09:34:43 |
|
+ |
|
+ "notBefore" or "notAfter" dates must use GMT (:rfc:`5280`). |
|
+ |
|
+ .. versionchanged:: 2.7.9 |
|
+ Interpret the input time as a time in UTC as specified by 'GMT' |
|
+ timezone in the input string. Local timezone was used |
|
+ previously. Return an integer (no fractions of a second in the |
|
+ input format) |
|
+ |
|
+.. function:: get_server_certificate(addr, ssl_version=PROTOCOL_SSLv23, ca_certs=None) |
|
|
|
Given the address ``addr`` of an SSL-protected server, as a (*hostname*, |
|
*port-number*) pair, fetches the server's certificate, and returns it as a |
|
@@ -204,36 +367,144 @@ Functions, Constants, and Exceptions |
|
will attempt to validate the server certificate against that set of root |
|
certificates, and will fail if the validation attempt fails. |
|
|
|
-.. function:: DER_cert_to_PEM_cert (DER_cert_bytes) |
|
+ .. versionchanged:: 2.7.9 |
|
+ |
|
+ This function is now IPv6-compatible, and the default *ssl_version* is |
|
+ changed from :data:`PROTOCOL_SSLv3` to :data:`PROTOCOL_SSLv23` for |
|
+ maximum compatibility with modern servers. |
|
+ |
|
+.. function:: DER_cert_to_PEM_cert(DER_cert_bytes) |
|
|
|
Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded |
|
string version of the same certificate. |
|
|
|
-.. function:: PEM_cert_to_DER_cert (PEM_cert_string) |
|
+.. function:: PEM_cert_to_DER_cert(PEM_cert_string) |
|
|
|
Given a certificate as an ASCII PEM string, returns a DER-encoded sequence of |
|
bytes for that same certificate. |
|
|
|
+.. function:: get_default_verify_paths() |
|
+ |
|
+ Returns a named tuple with paths to OpenSSL's default cafile and capath. |
|
+ The paths are the same as used by |
|
+ :meth:`SSLContext.set_default_verify_paths`. The return value is a |
|
+ :term:`named tuple` ``DefaultVerifyPaths``: |
|
+ |
|
+ * :attr:`cafile` - resolved path to cafile or None if the file doesn't exist, |
|
+ * :attr:`capath` - resolved path to capath or None if the directory doesn't exist, |
|
+ * :attr:`openssl_cafile_env` - OpenSSL's environment key that points to a cafile, |
|
+ * :attr:`openssl_cafile` - hard coded path to a cafile, |
|
+ * :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath, |
|
+ * :attr:`openssl_capath` - hard coded path to a capath directory |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. function:: enum_certificates(store_name) |
|
+ |
|
+ Retrieve certificates from Windows' system cert store. *store_name* may be |
|
+ one of ``CA``, ``ROOT`` or ``MY``. Windows may provide additional cert |
|
+ stores, too. |
|
+ |
|
+ The function returns a list of (cert_bytes, encoding_type, trust) tuples. |
|
+ The encoding_type specifies the encoding of cert_bytes. It is either |
|
+ :const:`x509_asn` for X.509 ASN.1 data or :const:`pkcs_7_asn` for |
|
+ PKCS#7 ASN.1 data. Trust specifies the purpose of the certificate as a set |
|
+ of OIDS or exactly ``True`` if the certificate is trustworthy for all |
|
+ purposes. |
|
+ |
|
+ Example:: |
|
+ |
|
+ >>> ssl.enum_certificates("CA") |
|
+ [(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}), |
|
+ (b'data...', 'x509_asn', True)] |
|
+ |
|
+ Availability: Windows. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. function:: enum_crls(store_name) |
|
+ |
|
+ Retrieve CRLs from Windows' system cert store. *store_name* may be |
|
+ one of ``CA``, ``ROOT`` or ``MY``. Windows may provide additional cert |
|
+ stores, too. |
|
+ |
|
+ The function returns a list of (cert_bytes, encoding_type, trust) tuples. |
|
+ The encoding_type specifies the encoding of cert_bytes. It is either |
|
+ :const:`x509_asn` for X.509 ASN.1 data or :const:`pkcs_7_asn` for |
|
+ PKCS#7 ASN.1 data. |
|
+ |
|
+ Availability: Windows. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+ |
|
+Constants |
|
+^^^^^^^^^ |
|
+ |
|
.. data:: CERT_NONE |
|
|
|
- Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no |
|
- certificates will be required or validated from the other side of the socket |
|
- connection. |
|
+ Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` |
|
+ parameter to :func:`wrap_socket`. In this mode (the default), no |
|
+ certificates will be required from the other side of the socket connection. |
|
+ If a certificate is received from the other end, no attempt to validate it |
|
+ is made. |
|
+ |
|
+ See the discussion of :ref:`ssl-security` below. |
|
|
|
.. data:: CERT_OPTIONAL |
|
|
|
- Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no |
|
- certificates will be required from the other side of the socket connection, |
|
- but if they are provided, will be validated. Note that use of this setting |
|
- requires a valid certificate validation file also be passed as a value of the |
|
- ``ca_certs`` parameter. |
|
+ Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` |
|
+ parameter to :func:`wrap_socket`. In this mode no certificates will be |
|
+ required from the other side of the socket connection; but if they |
|
+ are provided, validation will be attempted and an :class:`SSLError` |
|
+ will be raised on failure. |
|
+ |
|
+ Use of this setting requires a valid set of CA certificates to |
|
+ be passed, either to :meth:`SSLContext.load_verify_locations` or as a |
|
+ value of the ``ca_certs`` parameter to :func:`wrap_socket`. |
|
|
|
.. data:: CERT_REQUIRED |
|
|
|
- Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when |
|
- certificates will be required from the other side of the socket connection. |
|
- Note that use of this setting requires a valid certificate validation file |
|
- also be passed as a value of the ``ca_certs`` parameter. |
|
+ Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs`` |
|
+ parameter to :func:`wrap_socket`. In this mode, certificates are |
|
+ required from the other side of the socket connection; an :class:`SSLError` |
|
+ will be raised if no certificate is provided, or if its validation fails. |
|
+ |
|
+ Use of this setting requires a valid set of CA certificates to |
|
+ be passed, either to :meth:`SSLContext.load_verify_locations` or as a |
|
+ value of the ``ca_certs`` parameter to :func:`wrap_socket`. |
|
+ |
|
+.. data:: VERIFY_DEFAULT |
|
+ |
|
+ Possible value for :attr:`SSLContext.verify_flags`. In this mode, |
|
+ certificate revocation lists (CRLs) are not checked. By default OpenSSL |
|
+ does neither require nor verify CRLs. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: VERIFY_CRL_CHECK_LEAF |
|
+ |
|
+ Possible value for :attr:`SSLContext.verify_flags`. In this mode, only the |
|
+ peer cert is check but non of the intermediate CA certificates. The mode |
|
+ requires a valid CRL that is signed by the peer cert's issuer (its direct |
|
+ ancestor CA). If no proper has been loaded |
|
+ :attr:`SSLContext.load_verify_locations`, validation will fail. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: VERIFY_CRL_CHECK_CHAIN |
|
+ |
|
+ Possible value for :attr:`SSLContext.verify_flags`. In this mode, CRLs of |
|
+ all certificates in the peer cert chain are checked. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: VERIFY_X509_STRICT |
|
+ |
|
+ Possible value for :attr:`SSLContext.verify_flags` to disable workarounds |
|
+ for broken X.509 certificates. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
|
|
.. data:: PROTOCOL_SSLv2 |
|
|
|
@@ -260,9 +531,136 @@ Functions, Constants, and Exceptions |
|
|
|
.. data:: PROTOCOL_TLSv1 |
|
|
|
- Selects TLS version 1 as the channel encryption protocol. This is the most |
|
+ Selects TLS version 1.0 as the channel encryption protocol. |
|
+ |
|
+.. data:: PROTOCOL_TLSv1_1 |
|
+ |
|
+ Selects TLS version 1.1 as the channel encryption protocol. |
|
+ Available only with openssl version 1.0.1+. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: PROTOCOL_TLSv1_2 |
|
+ |
|
+ Selects TLS version 1.2 as the channel encryption protocol. This is the most |
|
modern version, and probably the best choice for maximum protection, if both |
|
- sides can speak it. |
|
+ sides can speak it. Available only with openssl version 1.0.1+. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_ALL |
|
+ |
|
+ Enables workarounds for various bugs present in other SSL implementations. |
|
+ This option is set by default. It does not necessarily set the same |
|
+ flags as OpenSSL's ``SSL_OP_ALL`` constant. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_NO_SSLv2 |
|
+ |
|
+ Prevents an SSLv2 connection. This option is only applicable in |
|
+ conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from |
|
+ choosing SSLv2 as the protocol version. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_NO_SSLv3 |
|
+ |
|
+ Prevents an SSLv3 connection. This option is only applicable in |
|
+ conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from |
|
+ choosing SSLv3 as the protocol version. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_NO_TLSv1 |
|
+ |
|
+ Prevents a TLSv1 connection. This option is only applicable in |
|
+ conjunction with :const:`PROTOCOL_SSLv23`. It prevents the peers from |
|
+ choosing TLSv1 as the protocol version. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_NO_TLSv1_1 |
|
+ |
|
+ Prevents a TLSv1.1 connection. This option is only applicable in conjunction |
|
+ with :const:`PROTOCOL_SSLv23`. It prevents the peers from choosing TLSv1.1 as |
|
+ the protocol version. Available only with openssl version 1.0.1+. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_NO_TLSv1_2 |
|
+ |
|
+ Prevents a TLSv1.2 connection. This option is only applicable in conjunction |
|
+ with :const:`PROTOCOL_SSLv23`. It prevents the peers from choosing TLSv1.2 as |
|
+ the protocol version. Available only with openssl version 1.0.1+. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_CIPHER_SERVER_PREFERENCE |
|
+ |
|
+ Use the server's cipher ordering preference, rather than the client's. |
|
+ This option has no effect on client sockets and SSLv2 server sockets. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_SINGLE_DH_USE |
|
+ |
|
+ Prevents re-use of the same DH key for distinct SSL sessions. This |
|
+ improves forward secrecy but requires more computational resources. |
|
+ This option only applies to server sockets. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_SINGLE_ECDH_USE |
|
+ |
|
+ Prevents re-use of the same ECDH key for distinct SSL sessions. This |
|
+ improves forward secrecy but requires more computational resources. |
|
+ This option only applies to server sockets. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: OP_NO_COMPRESSION |
|
+ |
|
+ Disable compression on the SSL channel. This is useful if the application |
|
+ protocol supports its own compression scheme. |
|
+ |
|
+ This option is only available with OpenSSL 1.0.0 and later. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: HAS_ECDH |
|
+ |
|
+ Whether the OpenSSL library has built-in support for Elliptic Curve-based |
|
+ Diffie-Hellman key exchange. This should be true unless the feature was |
|
+ explicitly disabled by the distributor. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: HAS_SNI |
|
+ |
|
+ Whether the OpenSSL library has built-in support for the *Server Name |
|
+ Indication* extension to the SSLv3 and TLSv1 protocols (as defined in |
|
+ :rfc:`4366`). When true, you can use the *server_hostname* argument to |
|
+ :meth:`SSLContext.wrap_socket`. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: HAS_NPN |
|
+ |
|
+ Whether the OpenSSL library has built-in support for *Next Protocol |
|
+ Negotiation* as described in the `NPN draft specification |
|
+ <http://tools.ietf.org/html/draft-agl-tls-nextprotoneg>`_. When true, |
|
+ you can use the :meth:`SSLContext.set_npn_protocols` method to advertise |
|
+ which protocols you want to support. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: CHANNEL_BINDING_TYPES |
|
+ |
|
+ List of supported TLS channel binding types. Strings in this list |
|
+ can be used as arguments to :meth:`SSLSocket.get_channel_binding`. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
|
|
.. data:: OPENSSL_VERSION |
|
|
|
@@ -294,9 +692,40 @@ Functions, Constants, and Exceptions |
|
|
|
.. versionadded:: 2.7 |
|
|
|
+.. data:: ALERT_DESCRIPTION_HANDSHAKE_FAILURE |
|
+ ALERT_DESCRIPTION_INTERNAL_ERROR |
|
+ ALERT_DESCRIPTION_* |
|
+ |
|
+ Alert Descriptions from :rfc:`5246` and others. The `IANA TLS Alert Registry |
|
+ <http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6>`_ |
|
+ contains this list and references to the RFCs where their meaning is defined. |
|
+ |
|
+ Used as the return value of the callback function in |
|
+ :meth:`SSLContext.set_servername_callback`. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. data:: Purpose.SERVER_AUTH |
|
+ |
|
+ Option for :func:`create_default_context` and |
|
+ :meth:`SSLContext.load_default_certs`. This value indicates that the |
|
+ context may be used to authenticate Web servers (therefore, it will |
|
+ be used to create client-side sockets). |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
|
|
-SSLSocket Objects |
|
------------------ |
|
+.. data:: Purpose.CLIENT_AUTH |
|
+ |
|
+ Option for :func:`create_default_context` and |
|
+ :meth:`SSLContext.load_default_certs`. This value indicates that the |
|
+ context may be used to authenticate Web clients (therefore, it will |
|
+ be used to create server-side sockets). |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+ |
|
+SSL Sockets |
|
+----------- |
|
|
|
SSL sockets provide the following methods of :ref:`socket-objects`: |
|
|
|
@@ -319,37 +748,64 @@ SSL sockets provide the following method |
|
|
|
However, since the SSL (and TLS) protocol has its own framing atop |
|
of TCP, the SSL sockets abstraction can, in certain respects, diverge from |
|
-the specification of normal, OS-level sockets. |
|
+the specification of normal, OS-level sockets. See especially the |
|
+:ref:`notes on non-blocking sockets <ssl-nonblocking>`. |
|
|
|
SSL sockets also have the following additional methods and attributes: |
|
|
|
+.. method:: SSLSocket.do_handshake() |
|
+ |
|
+ Perform the SSL setup handshake. |
|
+ |
|
+ .. versionchanged:: 2.7.9 |
|
+ |
|
+ The handshake method also performs :func:`match_hostname` when the |
|
+ :attr:`~SSLContext.check_hostname` attribute of the socket's |
|
+ :attr:`~SSLSocket.context` is true. |
|
+ |
|
.. method:: SSLSocket.getpeercert(binary_form=False) |
|
|
|
If there is no certificate for the peer on the other end of the connection, |
|
- returns ``None``. |
|
+ return ``None``. If the SSL handshake hasn't been done yet, raise |
|
+ :exc:`ValueError`. |
|
|
|
If the ``binary_form`` parameter is :const:`False`, and a certificate was |
|
received from the peer, this method returns a :class:`dict` instance. If the |
|
certificate was not validated, the dict is empty. If the certificate was |
|
- validated, it returns a dict with the keys ``subject`` (the principal for |
|
- which the certificate was issued), and ``notAfter`` (the time after which the |
|
- certificate should not be trusted). The certificate was already validated, |
|
- so the ``notBefore`` and ``issuer`` fields are not returned. If a |
|
- certificate contains an instance of the *Subject Alternative Name* extension |
|
- (see :rfc:`3280`), there will also be a ``subjectAltName`` key in the |
|
- dictionary. |
|
- |
|
- The "subject" field is a tuple containing the sequence of relative |
|
- distinguished names (RDNs) given in the certificate's data structure for the |
|
- principal, and each RDN is a sequence of name-value pairs:: |
|
- |
|
- {'notAfter': 'Feb 16 16:54:50 2013 GMT', |
|
- 'subject': ((('countryName', u'US'),), |
|
- (('stateOrProvinceName', u'Delaware'),), |
|
- (('localityName', u'Wilmington'),), |
|
- (('organizationName', u'Python Software Foundation'),), |
|
- (('organizationalUnitName', u'SSL'),), |
|
- (('commonName', u'somemachine.python.org'),))} |
|
+ validated, it returns a dict with several keys, amongst them ``subject`` |
|
+ (the principal for which the certificate was issued) and ``issuer`` |
|
+ (the principal issuing the certificate). If a certificate contains an |
|
+ instance of the *Subject Alternative Name* extension (see :rfc:`3280`), |
|
+ there will also be a ``subjectAltName`` key in the dictionary. |
|
+ |
|
+ The ``subject`` and ``issuer`` fields are tuples containing the sequence |
|
+ of relative distinguished names (RDNs) given in the certificate's data |
|
+ structure for the respective fields, and each RDN is a sequence of |
|
+ name-value pairs. Here is a real-world example:: |
|
+ |
|
+ {'issuer': ((('countryName', 'IL'),), |
|
+ (('organizationName', 'StartCom Ltd.'),), |
|
+ (('organizationalUnitName', |
|
+ 'Secure Digital Certificate Signing'),), |
|
+ (('commonName', |
|
+ 'StartCom Class 2 Primary Intermediate Server CA'),)), |
|
+ 'notAfter': 'Nov 22 08:15:19 2013 GMT', |
|
+ 'notBefore': 'Nov 21 03:09:52 2011 GMT', |
|
+ 'serialNumber': '95F0', |
|
+ 'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),), |
|
+ (('countryName', 'US'),), |
|
+ (('stateOrProvinceName', 'California'),), |
|
+ (('localityName', 'San Francisco'),), |
|
+ (('organizationName', 'Electronic Frontier Foundation, Inc.'),), |
|
+ (('commonName', '*.eff.org'),), |
|
+ (('emailAddress', 'hostmaster@eff.org'),)), |
|
+ 'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')), |
|
+ 'version': 3} |
|
+ |
|
+ .. note:: |
|
+ |
|
+ To validate a certificate for a particular service, you can use the |
|
+ :func:`match_hostname` function. |
|
|
|
If the ``binary_form`` parameter is :const:`True`, and a certificate was |
|
provided, this method returns the DER-encoded form of the entire certificate |
|
@@ -365,40 +821,388 @@ SSL sockets also have the following addi |
|
:const:`None` if you used :const:`CERT_NONE` (rather than |
|
:const:`CERT_OPTIONAL` or :const:`CERT_REQUIRED`). |
|
|
|
+ .. versionchanged:: 2.7.9 |
|
+ The returned dictionary includes additional items such as ``issuer`` and |
|
+ ``notBefore``. Additionall :exc:`ValueError` is raised when the handshake |
|
+ isn't done. The returned dictionary includes additional X509v3 extension |
|
+ items such as ``crlDistributionPoints``, ``caIssuers`` and ``OCSP`` URIs. |
|
+ |
|
.. method:: SSLSocket.cipher() |
|
|
|
Returns a three-value tuple containing the name of the cipher being used, the |
|
version of the SSL protocol that defines its use, and the number of secret |
|
bits being used. If no connection has been established, returns ``None``. |
|
|
|
-.. method:: SSLSocket.do_handshake() |
|
+.. method:: SSLSocket.compression() |
|
+ |
|
+ Return the compression algorithm being used as a string, or ``None`` |
|
+ if the connection isn't compressed. |
|
+ |
|
+ If the higher-level protocol supports its own compression mechanism, |
|
+ you can use :data:`OP_NO_COMPRESSION` to disable SSL-level compression. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. method:: SSLSocket.get_channel_binding(cb_type="tls-unique") |
|
+ |
|
+ Get channel binding data for current connection, as a bytes object. Returns |
|
+ ``None`` if not connected or the handshake has not been completed. |
|
+ |
|
+ The *cb_type* parameter allow selection of the desired channel binding |
|
+ type. Valid channel binding types are listed in the |
|
+ :data:`CHANNEL_BINDING_TYPES` list. Currently only the 'tls-unique' channel |
|
+ binding, defined by :rfc:`5929`, is supported. :exc:`ValueError` will be |
|
+ raised if an unsupported channel binding type is requested. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+.. method:: SSLSocket.selected_npn_protocol() |
|
+ |
|
+ Returns the protocol that was selected during the TLS/SSL handshake. If |
|
+ :meth:`SSLContext.set_npn_protocols` was not called, or if the other party |
|
+ does not support NPN, or if the handshake has not yet happened, this will |
|
+ return ``None``. |
|
|
|
- Perform a TLS/SSL handshake. If this is used with a non-blocking socket, it |
|
- may raise :exc:`SSLError` with an ``arg[0]`` of :const:`SSL_ERROR_WANT_READ` |
|
- or :const:`SSL_ERROR_WANT_WRITE`, in which case it must be called again until |
|
- it completes successfully. For example, to simulate the behavior of a |
|
- blocking socket, one might write:: |
|
- |
|
- while True: |
|
- try: |
|
- s.do_handshake() |
|
- break |
|
- except ssl.SSLError as err: |
|
- if err.args[0] == ssl.SSL_ERROR_WANT_READ: |
|
- select.select([s], [], []) |
|
- elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: |
|
- select.select([], [s], []) |
|
- else: |
|
- raise |
|
+ .. versionadded:: 2.7.9 |
|
|
|
.. method:: SSLSocket.unwrap() |
|
|
|
Performs the SSL shutdown handshake, which removes the TLS layer from the |
|
underlying socket, and returns the underlying socket object. This can be |
|
used to go from encrypted operation over a connection to unencrypted. The |
|
- socket instance returned should always be used for further communication with |
|
- the other side of the connection, rather than the original socket instance |
|
- (which may not function properly after the unwrap). |
|
+ returned socket should always be used for further communication with the |
|
+ other side of the connection, rather than the original socket. |
|
+ |
|
+.. attribute:: SSLSocket.context |
|
+ |
|
+ The :class:`SSLContext` object this SSL socket is tied to. If the SSL |
|
+ socket was created using the top-level :func:`wrap_socket` function |
|
+ (rather than :meth:`SSLContext.wrap_socket`), this is a custom context |
|
+ object created for this SSL socket. |
|
+ |
|
+ .. versionadded:: 2.7.9 |
|
+ |
|
+ |
|
+SSL Contexts |
|
+------------ |
|
+ |
|
+.. versionadded:: 2.7.9 |
|
+ |
|
+An SSL context holds various data longer-lived than single SSL connections, |
|
+such as SSL configuration options, certificate(s) and private key(s). |
|
+It also manages a cache of SSL sessions for server-side sockets, in order |
|
+to speed up repeated connections from the same clients. |
|
+ |
|
+.. class:: SSLContext(protocol) |
|
+ |
|
+ Create a new SSL context. You must pass *protocol* which must be one |
|
+ of the ``PROTOCOL_*`` constants defined in this module. |
|
+ :data:`PROTOCOL_SSLv23` is currently recommended for maximum |
|
+ interoperability. |
|
+ |
|
+ .. seealso:: |
|
+ :func:`create_default_context` lets the :mod:`ssl` module choose |
|
+ security settings for a given purpose. |
|
+ |
|
+ |
|
+:class:`SSLContext` objects have the following methods and attributes: |
|
+ |
|
+.. method:: SSLContext.cert_store_stats() |
|
+ |
|
+ Get statistics about quantities of loaded X.509 certificates, count of |
|
+ X.509 certificates flagged as CA certificates and certificate revocation |
|
+ lists as dictionary. |
|
+ |
|
+ Example for a context with one CA cert and one other cert:: |
|
+ |
|
+ >>> context.cert_store_stats() |
|
+ {'crl': 0, 'x509_ca': 1, 'x509': 2} |
|
+ |
|
+ |
|
+.. method:: SSLContext.load_cert_chain(certfile, keyfile=None, password=None) |
|
+ |
|
+ Load a private key and the corresponding certificate. The *certfile* |
|
+ string must be the path to a single file in PEM format containing the |
|
+ certificate as well as any number of CA certificates needed to establish |
|
+ the certificate's authenticity. The *keyfile* string, if present, must |
|
+ point to a file containing the private key in. Otherwise the private |
|
+ key will be taken from *certfile* as well. See the discussion of |
|
+ :ref:`ssl-certificates` for more information on how the certificate |
|
+ is stored in the *certfile*. |
|
+ |
|
+ The *password* argument may be a function to call to get the password for |
|
+ decrypting the private key. It will only be called if the private key is |
|
+ encrypted and a password is necessary. It will be called with no arguments, |
|
+ and it should return a string, bytes, or bytearray. If the return value is |
|
+ a string it will be encoded as UTF-8 before using it to decrypt the key. |
|
+ Alternatively a string, bytes, or bytearray value may be supplied directly |
|
+ as the *password* argument. It will be ignored if the private key is not |
|
+ encrypted and no password is needed. |
|
+ |
|
+ If the *password* argument is not specified and a password is required, |
|
+ OpenSSL's built-in password prompting mechanism will be used to |
|
+ interactively prompt the user for a password. |
|
+ |
|
+ An :class:`SSLError` is raised if the private key doesn't |
|
+ match with the certificate. |
|
+ |
|
+.. method:: SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH) |
|
+ |
|
+ Load a set of default "certification authority" (CA) certificates from |
|
+ default locations. On Windows it loads CA certs from the ``CA`` and |
|
+ ``ROOT`` system stores. On other systems it calls |
|
+ :meth:`SSLContext.set_default_verify_paths`. In the future the method may |
|
+ load CA certificates from other locations, too. |
|
+ |
|
+ The *purpose* flag specifies what kind of CA certificates are loaded. The |
|
+ default settings :data:`Purpose.SERVER_AUTH` loads certificates, that are |
|
+ flagged and trusted for TLS web server authentication (client side |
|
+ sockets). :data:`Purpose.CLIENT_AUTH` loads CA certificates for client |
|
+ certificate verification on the server side. |
|
+ |
|
+.. method:: SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None) |
|
+ |
|
+ Load a set of "certification authority" (CA) certificates used to validate |
|
+ other peers' certificates when :data:`verify_mode` is other than |
|
+ :data:`CERT_NONE`. At least one of *cafile* or *capath* must be specified. |
|
+ |
|
+ This method can also load certification revocation lists (CRLs) in PEM or |
|
+ DER format. In order to make use of CRLs, :attr:`SSLContext.verify_flags` |
|
+ must be configured properly. |
|
+ |
|
+ The *cafile* string, if present, is the path to a file of concatenated |
|
+ CA certificates in PEM format. See the discussion of |
|
+ :ref:`ssl-certificates` for more information about how to arrange the |
|
+ certificates in this file. |
|
+ |
|
+ The *capath* string, if present, is |
|
+ the path to a directory containing several CA certificates in PEM format, |
|
+ following an `OpenSSL specific layout |
|
+ <http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html>`_. |
|
+ |
|
+ The *cadata* object, if present, is either an ASCII string of one or more |
|
+ PEM-encoded certificates or a bytes-like object of DER-encoded |
|
+ certificates. Like with *capath* extra lines around PEM-encoded |
|
+ certificates are ignored but at least one certificate must be present. |
|
+ |
|
+.. method:: SSLContext.get_ca_certs(binary_form=False) |
|
+ |
|
+ Get a list of loaded "certification authority" (CA) certificates. If the |
|
+ ``binary_form`` parameter is :const:`False` each list |
|
+ entry is a dict like the output of :meth:`SSLSocket.getpeercert`. Otherwise |
|
+ the method returns a list of DER-encoded certificates. The returned list |
|
+ does not contain certificates from *capath* unless a certificate was |
|
+ requested and loaded by a SSL connection. |
|
+ |
|
+.. method:: SSLContext.set_default_verify_paths() |
|
+ |
|
+ Load a set of default "certification authority" (CA) certificates from |
|
+ a filesystem path defined when building the OpenSSL library. Unfortunately, |
|
+ there's no easy way to know whether this method succeeds: no error is |
|
+ returned if no certificates are to be found. When the OpenSSL library is |
|
+ provided as part of the operating system, though, it is likely to be |
|
+ configured properly. |
|
+ |
|
+.. method:: SSLContext.set_ciphers(ciphers) |
|
+ |
|
+ Set the available ciphers for sockets created with this context. |
|
+ It should be a string in the `OpenSSL cipher list format |
|
+ <http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_. |
|
+ If no cipher can be selected (because compile-time options or other |
|
+ configuration forbids use of all the specified ciphers), an |
|
+ :class:`SSLError` will be raised. |
|
+ |
|
+ .. note:: |
|
+ when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will |
|
+ give the currently selected cipher. |
|
+ |
|
+.. method:: SSLContext.set_npn_protocols(protocols) |
|
+ |
|
+ Specify which protocols the socket should advertise during the SSL/TLS |
|
+ handshake. It should be a list of strings, like ``['http/1.1', 'spdy/2']``, |
|
+ ordered by preference. The selection of a protocol will happen during the |
|
+ handshake, and will play out according to the `NPN draft specification |
|
+ <http://tools.ietf.org/html/draft-agl-tls-nextprotoneg>`_. After a |
|
+ successful handshake, the :meth:`SSLSocket.selected_npn_protocol` method will |
|
+ return the agreed-upon protocol. |
|
+ |
|
+ This method will raise :exc:`NotImplementedError` if :data:`HAS_NPN` is |
|
+ False. |
|
+ |
|
+.. method:: SSLContext.set_servername_callback(server_name_callback) |
|
+ |
|
+ Register a callback function that will be called after the TLS Client Hello |
|
+ handshake message has been received by the SSL/TLS server when the TLS client |
|
+ specifies a server name indication. The server name indication mechanism |
|
+ is specified in :rfc:`6066` section 3 - Server Name Indication. |
|
+ |
|
+ Only one callback can be set per ``SSLContext``. If *server_name_callback* |
|
+ is ``None`` then the callback is disabled. Calling this function a |
|
+ subsequent time will disable the previously registered callback. |
|
+ |
|
+ The callback function, *server_name_callback*, will be called with three |
|
+ arguments; the first being the :class:`ssl.SSLSocket`, the second is a string |
|
+ that represents the server name that the client is intending to communicate |
|
+ (or :const:`None` if the TLS Client Hello does not contain a server name) |
|
+ and the third argument is the original :class:`SSLContext`. The server name |
|
+ argument is the IDNA decoded server name. |
|
+ |
|
+ A typical use of this callback is to change the :class:`ssl.SSLSocket`'s |
|
+ :attr:`SSLSocket.context` attribute to a new object of type |
|
+ :class:`SSLContext` representing a certificate chain that matches the server |
|
+ name. |
|
+ |
|
+ Due to the early negotiation phase of the TLS connection, only limited |
|
+ methods and attributes are usable like |
|
+ :meth:`SSLSocket.selected_npn_protocol` and :attr:`SSLSocket.context`. |
|
+ :meth:`SSLSocket.getpeercert`, :meth:`SSLSocket.getpeercert`, |
|
+ :meth:`SSLSocket.cipher` and :meth:`SSLSocket.compress` methods require that |
|
+ the TLS connection has progressed beyond the TLS Client Hello and therefore |
|
+ will not contain return meaningful values nor can they be called safely. |
|
+ |
|
+ The *server_name_callback* function must return ``None`` to allow the |
|
+ TLS negotiation to continue. If a TLS failure is required, a constant |
|
+ :const:`ALERT_DESCRIPTION_* <ALERT_DESCRIPTION_INTERNAL_ERROR>` can be |
|
+ returned. Other return values will result in a TLS fatal error with |
|
+ :const:`ALERT_DESCRIPTION_INTERNAL_ERROR`. |
|
+ |
|
+ If there is an IDNA decoding error on the server name, the TLS connection |
|
+ will terminate with an :const:`ALERT_DESCRIPTION_INTERNAL_ERROR` fatal TLS |
|
+ alert message to the client. |
|
+ |
|
+ If an exception is raised from the *server_name_callback* function the TLS |
|
+ connection will terminate with a fatal TLS alert message |
|
+ :const:`ALERT_DESCRIPTION_HANDSHAKE_FAILURE`. |
|
+ |
|
+ This method will raise :exc:`NotImplementedError` if the OpenSSL library |
|
+ had OPENSSL_NO_TLSEXT defined when it was built. |
|
+ |
|
+.. method:: SSLContext.load_dh_params(dhfile) |
|
+ |
|
+ Load the key generation parameters for Diffie-Helman (DH) key exchange. |
|
+ Using DH key exchange improves forward secrecy at the expense of |
|
+ computational resources (both on the server and on the client). |
|
+ The *dhfile* parameter should be the path to a file containing DH |
|
+ parameters in PEM format. |
|
+ |
|
+ This setting doesn't apply to client sockets. You can also use the |
|
+ :data:`OP_SINGLE_DH_USE` option to further improve security. |
|
+ |
|
+.. method:: SSLContext.set_ecdh_curve(curve_name) |
|
+ |
|
+ Set the curve name for Elliptic Curve-based Diffie-Hellman (ECDH) key |
|
+ exchange. ECDH is significantly faster than regular DH while arguably |
|
+ as secure. The *curve_name* parameter should be a string describing |
|
+ a well-known elliptic curve, for example ``prime256v1`` for a widely |
|
+ supported curve. |
|
+ |
|
+ This setting doesn't apply to client sockets. You can also use the |
|
+ :data:`OP_SINGLE_ECDH_USE` option to further improve security. |
|
+ |
|
+ This method is not available if :data:`HAS_ECDH` is False. |
|
+ |
|
+ .. seealso:: |
|
+ `SSL/TLS & Perfect Forward Secrecy <http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html>`_ |
|
+ Vincent Bernat. |
|
+ |
|
+.. method:: SSLContext.wrap_socket(sock, server_side=False, \ |
|
+ do_handshake_on_connect=True, suppress_ragged_eofs=True, \ |
|
+ server_hostname=None) |
|
+ |
|
+ Wrap an existing Python socket *sock* and return an :class:`SSLSocket` |
|
+ object. *sock* must be a :data:`~socket.SOCK_STREAM` socket; other socket |
|
+ types are unsupported. |
|
+ |
|
+ The returned SSL socket is tied to the context, its settings and |
|
+ certificates. The parameters *server_side*, *do_handshake_on_connect* |
|
+ and *suppress_ragged_eofs* have the same meaning as in the top-level |
|
+ :func:`wrap_socket` function. |
|
+ |
|
+ On client connections, the optional parameter *server_hostname* specifies |
|
+ the hostname of the service which we are connecting to. This allows a |
|
+ single server to host multiple SSL-based services with distinct certificates, |
|
+ quite similarly to HTTP virtual hosts. Specifying *server_hostname* |
|
+ will raise a :exc:`ValueError` if the OpenSSL library doesn't have support |
|
+ for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying |
|
+ *server_hostname* will also raise a :exc:`ValueError` if *server_side* |
|
+ is true. |
|
+ |
|
+.. method:: SSLContext.session_stats() |
|
+ |
|
+ Get statistics about the SSL sessions created or managed by this context. |
|
+ A dictionary is returned which maps the names of each `piece of information |
|
+ <http://www.openssl.org/docs/ssl/SSL_CTX_sess_number.html>`_ to their |
|
+ numeric values. For example, here is the total number of hits and misses |
|
+ in the session cache since the context was created:: |
|
+ |
|
+ >>> stats = context.session_stats() |
|
+ >>> stats['hits'], stats['misses'] |
|
+ (0, 0) |
|
+ |
|
+.. method:: SSLContext.get_ca_certs(binary_form=False) |
|
+ |
|
+ Returns a list of dicts with information of loaded CA certs. If the |
|
+ optional argument is true, returns a DER-encoded copy of the CA |
|
+ certificate. |
|
+ |
|
+ .. note:: |
|
+ Certificates in a capath directory aren't loaded unless they have |
|
+ been used at least once. |
|
+ |
|
+.. attribute:: SSLContext.check_hostname |
|
+ |
|
+ Wether to match the peer cert's hostname with :func:`match_hostname` in |
|
+ :meth:`SSLSocket.do_handshake`. The context's |
|
+ :attr:`~SSLContext.verify_mode` must be set to :data:`CERT_OPTIONAL` or |
|
+ :data:`CERT_REQUIRED`, and you must pass *server_hostname* to |
|
+ :meth:`~SSLContext.wrap_socket` in order to match the hostname. |
|
+ |
|
+ Example:: |
|
+ |
|
+ import socket, ssl |
|
+ |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ context.verify_mode = ssl.CERT_REQUIRED |
|
+ context.check_hostname = True |
|
+ context.load_default_certs() |
|
+ |
|
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
+ ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com') |
|
+ ssl_sock.connect(('www.verisign.com', 443)) |
|
+ |
|
+ .. note:: |
|
+ |
|
+ This features requires OpenSSL 0.9.8f or newer. |
|
+ |
|
+.. attribute:: SSLContext.options |
|
+ |
|
+ An integer representing the set of SSL options enabled on this context. |
|
+ The default value is :data:`OP_ALL`, but you can specify other options |
|
+ such as :data:`OP_NO_SSLv2` by ORing them together. |
|
+ |
|
+ .. note:: |
|
+ With versions of OpenSSL older than 0.9.8m, it is only possible |
|
+ to set options, not to clear them. Attempting to clear an option |
|
+ (by resetting the corresponding bits) will raise a ``ValueError``. |
|
+ |
|
+.. attribute:: SSLContext.protocol |
|
+ |
|
+ The protocol version chosen when constructing the context. This attribute |
|
+ is read-only. |
|
+ |
|
+.. attribute:: SSLContext.verify_flags |
|
+ |
|
+ The flags for certificate verification operations. You can set flags like |
|
+ :data:`VERIFY_CRL_CHECK_LEAF` by ORing them together. By default OpenSSL |
|
+ does neither require nor verify certificate revocation lists (CRLs). |
|
+ Available only with openssl version 0.9.8+. |
|
+ |
|
+.. attribute:: SSLContext.verify_mode |
|
+ |
|
+ Whether to try to verify other peers' certificates and how to behave |
|
+ if verification fails. This attribute must be one of |
|
+ :data:`CERT_NONE`, :data:`CERT_OPTIONAL` or :data:`CERT_REQUIRED`. |
|
+ |
|
|
|
.. index:: single: certificates |
|
|
|
@@ -445,6 +1249,9 @@ and a footer line:: |
|
... (certificate in base64 PEM encoding) ... |
|
-----END CERTIFICATE----- |
|
|
|
+Certificate chains |
|
+^^^^^^^^^^^^^^^^^^ |
|
+ |
|
The Python files which contain certificates can contain a sequence of |
|
certificates, sometimes called a *certificate chain*. This chain should start |
|
with the specific certificate for the principal who "is" the client or server, |
|
@@ -468,25 +1275,35 @@ certification authority's certificate:: |
|
... (the root certificate for the CA's issuer)... |
|
-----END CERTIFICATE----- |
|
|
|
+CA certificates |
|
+^^^^^^^^^^^^^^^ |
|
+ |
|
If you are going to require validation of the other side of the connection's |
|
certificate, you need to provide a "CA certs" file, filled with the certificate |
|
chains for each issuer you are willing to trust. Again, this file just contains |
|
these chains concatenated together. For validation, Python will use the first |
|
-chain it finds in the file which matches. |
|
+chain it finds in the file which matches. The platform's certificates file can |
|
+be used by calling :meth:`SSLContext.load_default_certs`, this is done |
|
+automatically with :func:`.create_default_context`. |
|
+ |
|
+Combined key and certificate |
|
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
+ |
|
+Often the private key is stored in the same file as the certificate; in this |
|
+case, only the ``certfile`` parameter to :meth:`SSLContext.load_cert_chain` |
|
+and :func:`wrap_socket` needs to be passed. If the private key is stored |
|
+with the certificate, it should come before the first certificate in |
|
+the certificate chain:: |
|
+ |
|
+ -----BEGIN RSA PRIVATE KEY----- |
|
+ ... (private key in base64 encoding) ... |
|
+ -----END RSA PRIVATE KEY----- |
|
+ -----BEGIN CERTIFICATE----- |
|
+ ... (certificate in base64 PEM encoding) ... |
|
+ -----END CERTIFICATE----- |
|
|
|
-Some "standard" root certificates are available from various certification |
|
-authorities: `CACert.org <http://www.cacert.org/index.php?id=3>`_, `Thawte |
|
-<http://www.thawte.com/roots/>`_, `Verisign |
|
-<http://www.verisign.com/support/roots.html>`_, `Positive SSL |
|
-<http://www.PositiveSSL.com/ssl-certificate-support/cert_installation/UTN-USERFirst-Hardware.crt>`_ |
|
-(used by python.org), `Equifax and GeoTrust |
|
-<http://www.geotrust.com/resources/root_certificates/index.asp>`_. |
|
- |
|
-In general, if you are using SSL3 or TLS1, you don't need to put the full chain |
|
-in your "CA certs" file; you only need the root certificates, and the remote |
|
-peer is supposed to furnish the other certificates necessary to chain from its |
|
-certificate to a root certificate. See :rfc:`4158` for more discussion of the |
|
-way in which certification chains can be built. |
|
+Self-signed certificates |
|
+^^^^^^^^^^^^^^^^^^^^^^^^ |
|
|
|
If you are going to create a server that provides SSL-encrypted connection |
|
services, you will need to acquire a certificate for that service. There are |
|
@@ -541,87 +1358,156 @@ should use the following idiom:: |
|
Client-side operation |
|
^^^^^^^^^^^^^^^^^^^^^ |
|
|
|
-This example connects to an SSL server, prints the server's address and |
|
-certificate, sends some bytes, and reads part of the response:: |
|
+This example connects to an SSL server and prints the server's certificate:: |
|
|
|
import socket, ssl, pprint |
|
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
- |
|
# require a certificate from the server |
|
ssl_sock = ssl.wrap_socket(s, |
|
ca_certs="/etc/ca_certs_file", |
|
cert_reqs=ssl.CERT_REQUIRED) |
|
- |
|
ssl_sock.connect(('www.verisign.com', 443)) |
|
|
|
- print repr(ssl_sock.getpeername()) |
|
- print ssl_sock.cipher() |
|
- print pprint.pformat(ssl_sock.getpeercert()) |
|
- |
|
- # Set a simple HTTP request -- use httplib in actual code. |
|
- ssl_sock.write("""GET / HTTP/1.0\r |
|
- Host: www.verisign.com\r\n\r\n""") |
|
- |
|
- # Read a chunk of data. Will not necessarily |
|
- # read all the data returned by the server. |
|
- data = ssl_sock.read() |
|
- |
|
+ pprint.pprint(ssl_sock.getpeercert()) |
|
# note that closing the SSLSocket will also close the underlying socket |
|
ssl_sock.close() |
|
|
|
-As of September 6, 2007, the certificate printed by this program looked like |
|
+As of January 6, 2012, the certificate printed by this program looks like |
|
this:: |
|
|
|
- {'notAfter': 'May 8 23:59:59 2009 GMT', |
|
- 'subject': ((('serialNumber', u'2497886'),), |
|
- (('1.3.6.1.4.1.311.60.2.1.3', u'US'),), |
|
- (('1.3.6.1.4.1.311.60.2.1.2', u'Delaware'),), |
|
- (('countryName', u'US'),), |
|
- (('postalCode', u'94043'),), |
|
- (('stateOrProvinceName', u'California'),), |
|
- (('localityName', u'Mountain View'),), |
|
- (('streetAddress', u'487 East Middlefield Road'),), |
|
- (('organizationName', u'VeriSign, Inc.'),), |
|
- (('organizationalUnitName', |
|
- u'Production Security Services'),), |
|
- (('organizationalUnitName', |
|
- u'Terms of use at www.verisign.com/rpa (c)06'),), |
|
- (('commonName', u'www.verisign.com'),))} |
|
+ {'issuer': ((('countryName', 'US'),), |
|
+ (('organizationName', 'VeriSign, Inc.'),), |
|
+ (('organizationalUnitName', 'VeriSign Trust Network'),), |
|
+ (('organizationalUnitName', |
|
+ 'Terms of use at https://www.verisign.com/rpa (c)06'),), |
|
+ (('commonName', |
|
+ 'VeriSign Class 3 Extended Validation SSL SGC CA'),)), |
|
+ 'notAfter': 'May 25 23:59:59 2012 GMT', |
|
+ 'notBefore': 'May 26 00:00:00 2010 GMT', |
|
+ 'serialNumber': '53D2BEF924A7245E83CA01E46CAA2477', |
|
+ 'subject': ((('1.3.6.1.4.1.311.60.2.1.3', 'US'),), |
|
+ (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),), |
|
+ (('businessCategory', 'V1.0, Clause 5.(b)'),), |
|
+ (('serialNumber', '2497886'),), |
|
+ (('countryName', 'US'),), |
|
+ (('postalCode', '94043'),), |
|
+ (('stateOrProvinceName', 'California'),), |
|
+ (('localityName', 'Mountain View'),), |
|
+ (('streetAddress', '487 East Middlefield Road'),), |
|
+ (('organizationName', 'VeriSign, Inc.'),), |
|
+ (('organizationalUnitName', ' Production Security Services'),), |
|
+ (('commonName', 'www.verisign.com'),)), |
|
+ 'subjectAltName': (('DNS', 'www.verisign.com'), |
|
+ ('DNS', 'verisign.com'), |
|
+ ('DNS', 'www.verisign.net'), |
|
+ ('DNS', 'verisign.net'), |
|
+ ('DNS', 'www.verisign.mobi'), |
|
+ ('DNS', 'verisign.mobi'), |
|
+ ('DNS', 'www.verisign.eu'), |
|
+ ('DNS', 'verisign.eu')), |
|
+ 'version': 3} |
|
+ |
|
+This other example first creates an SSL context, instructs it to verify |
|
+certificates sent by peers, and feeds it a set of recognized certificate |
|
+authorities (CA):: |
|
+ |
|
+ >>> context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ >>> context.verify_mode = ssl.CERT_REQUIRED |
|
+ >>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt") |
|
+ |
|
+(it is assumed your operating system places a bundle of all CA certificates |
|
+in ``/etc/ssl/certs/ca-bundle.crt``; if not, you'll get an error and have |
|
+to adjust the location) |
|
+ |
|
+When you use the context to connect to a server, :const:`CERT_REQUIRED` |
|
+validates the server certificate: it ensures that the server certificate |
|
+was signed with one of the CA certificates, and checks the signature for |
|
+correctness:: |
|
+ |
|
+ >>> conn = context.wrap_socket(socket.socket(socket.AF_INET)) |
|
+ >>> conn.connect(("linuxfr.org", 443)) |
|
+ |
|
+You should then fetch the certificate and check its fields for conformity:: |
|
+ |
|
+ >>> cert = conn.getpeercert() |
|
+ >>> ssl.match_hostname(cert, "linuxfr.org") |
|
+ |
|
+Visual inspection shows that the certificate does identify the desired service |
|
+(that is, the HTTPS host ``linuxfr.org``):: |
|
+ |
|
+ >>> pprint.pprint(cert) |
|
+ {'issuer': ((('organizationName', 'CAcert Inc.'),), |
|
+ (('organizationalUnitName', 'http://www.CAcert.org'),), |
|
+ (('commonName', 'CAcert Class 3 Root'),)), |
|
+ 'notAfter': 'Jun 7 21:02:24 2013 GMT', |
|
+ 'notBefore': 'Jun 8 21:02:24 2011 GMT', |
|
+ 'serialNumber': 'D3E9', |
|
+ 'subject': ((('commonName', 'linuxfr.org'),),), |
|
+ 'subjectAltName': (('DNS', 'linuxfr.org'), |
|
+ ('othername', '<unsupported>'), |
|
+ ('DNS', 'linuxfr.org'), |
|
+ ('othername', '<unsupported>'), |
|
+ ('DNS', 'dev.linuxfr.org'), |
|
+ ('othername', '<unsupported>'), |
|
+ ('DNS', 'prod.linuxfr.org'), |
|
+ ('othername', '<unsupported>'), |
|
+ ('DNS', 'alpha.linuxfr.org'), |
|
+ ('othername', '<unsupported>'), |
|
+ ('DNS', '*.linuxfr.org'), |
|
+ ('othername', '<unsupported>')), |
|
+ 'version': 3} |
|
+ |
|
+Now that you are assured of its authenticity, you can proceed to talk with |
|
+the server:: |
|
+ |
|
+ >>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n") |
|
+ >>> pprint.pprint(conn.recv(1024).split(b"\r\n")) |
|
+ [b'HTTP/1.1 302 Found', |
|
+ b'Date: Sun, 16 May 2010 13:43:28 GMT', |
|
+ b'Server: Apache/2.2', |
|
+ b'Location: https://linuxfr.org/pub/', |
|
+ b'Vary: Accept-Encoding', |
|
+ b'Connection: close', |
|
+ b'Content-Type: text/html; charset=iso-8859-1', |
|
+ b'', |
|
+ b''] |
|
+ |
|
+See the discussion of :ref:`ssl-security` below. |
|
|
|
-which is a fairly poorly-formed ``subject`` field. |
|
|
|
Server-side operation |
|
^^^^^^^^^^^^^^^^^^^^^ |
|
|
|
-For server operation, typically you'd need to have a server certificate, and |
|
-private key, each in a file. You'd open a socket, bind it to a port, call |
|
-:meth:`listen` on it, then start waiting for clients to connect:: |
|
+For server operation, typically you'll need to have a server certificate, and |
|
+private key, each in a file. You'll first create a context holding the key |
|
+and the certificate, so that clients can check your authenticity. Then |
|
+you'll open a socket, bind it to a port, call :meth:`listen` on it, and start |
|
+waiting for clients to connect:: |
|
|
|
import socket, ssl |
|
|
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile") |
|
+ |
|
bindsocket = socket.socket() |
|
bindsocket.bind(('myaddr.mydomain.com', 10023)) |
|
bindsocket.listen(5) |
|
|
|
-When one did, you'd call :meth:`accept` on the socket to get the new socket from |
|
-the other end, and use :func:`wrap_socket` to create a server-side SSL context |
|
-for it:: |
|
+When a client connects, you'll call :meth:`accept` on the socket to get the |
|
+new socket from the other end, and use the context's :meth:`SSLContext.wrap_socket` |
|
+method to create a server-side SSL socket for the connection:: |
|
|
|
while True: |
|
newsocket, fromaddr = bindsocket.accept() |
|
- connstream = ssl.wrap_socket(newsocket, |
|
- server_side=True, |
|
- certfile="mycertfile", |
|
- keyfile="mykeyfile", |
|
- ssl_version=ssl.PROTOCOL_TLSv1) |
|
+ connstream = context.wrap_socket(newsocket, server_side=True) |
|
try: |
|
deal_with_client(connstream) |
|
finally: |
|
connstream.shutdown(socket.SHUT_RDWR) |
|
connstream.close() |
|
|
|
-Then you'd read data from the ``connstream`` and do something with it till you |
|
+Then you'll read data from the ``connstream`` and do something with it till you |
|
are finished with the client (or the client is finished with you):: |
|
|
|
def deal_with_client(connstream): |
|
@@ -635,7 +1521,138 @@ are finished with the client (or the cli |
|
data = connstream.read() |
|
# finished with client |
|
|
|
-And go back to listening for new client connections. |
|
+And go back to listening for new client connections (of course, a real server |
|
+would probably handle each client connection in a separate thread, or put |
|
+the sockets in non-blocking mode and use an event loop). |
|
+ |
|
+ |
|
+.. _ssl-nonblocking: |
|
+ |
|
+Notes on non-blocking sockets |
|
+----------------------------- |
|
+ |
|
+When working with non-blocking sockets, there are several things you need |
|
+to be aware of: |
|
+ |
|
+- Calling :func:`~select.select` tells you that the OS-level socket can be |
|
+ read from (or written to), but it does not imply that there is sufficient |
|
+ data at the upper SSL layer. For example, only part of an SSL frame might |
|
+ have arrived. Therefore, you must be ready to handle :meth:`SSLSocket.recv` |
|
+ and :meth:`SSLSocket.send` failures, and retry after another call to |
|
+ :func:`~select.select`. |
|
+ |
|
+- Conversely, since the SSL layer has its own framing, a SSL socket may |
|
+ still have data available for reading without :func:`~select.select` |
|
+ being aware of it. Therefore, you should first call |
|
+ :meth:`SSLSocket.recv` to drain any potentially available data, and then |
|
+ only block on a :func:`~select.select` call if still necessary. |
|
+ |
|
+ (of course, similar provisions apply when using other primitives such as |
|
+ :func:`~select.poll`, or those in the :mod:`selectors` module) |
|
+ |
|
+- The SSL handshake itself will be non-blocking: the |
|
+ :meth:`SSLSocket.do_handshake` method has to be retried until it returns |
|
+ successfully. Here is a synopsis using :func:`~select.select` to wait for |
|
+ the socket's readiness:: |
|
+ |
|
+ while True: |
|
+ try: |
|
+ sock.do_handshake() |
|
+ break |
|
+ except ssl.SSLWantReadError: |
|
+ select.select([sock], [], []) |
|
+ except ssl.SSLWantWriteError: |
|
+ select.select([], [sock], []) |
|
+ |
|
+ |
|
+.. _ssl-security: |
|
+ |
|
+Security considerations |
|
+----------------------- |
|
+ |
|
+Best defaults |
|
+^^^^^^^^^^^^^ |
|
+ |
|
+For **client use**, if you don't have any special requirements for your |
|
+security policy, it is highly recommended that you use the |
|
+:func:`create_default_context` function to create your SSL context. |
|
+It will load the system's trusted CA certificates, enable certificate |
|
+validation and hostname checking, and try to choose reasonably secure |
|
+protocol and cipher settings. |
|
+ |
|
+If a client certificate is needed for the connection, it can be added with |
|
+:meth:`SSLContext.load_cert_chain`. |
|
+ |
|
+By contrast, if you create the SSL context by calling the :class:`SSLContext` |
|
+constructor yourself, it will not have certificate validation nor hostname |
|
+checking enabled by default. If you do so, please read the paragraphs below |
|
+to achieve a good security level. |
|
+ |
|
+Manual settings |
|
+^^^^^^^^^^^^^^^ |
|
+ |
|
+Verifying certificates |
|
+'''''''''''''''''''''' |
|
+ |
|
+When calling the :class:`SSLContext` constructor directly, |
|
+:const:`CERT_NONE` is the default. Since it does not authenticate the other |
|
+peer, it can be insecure, especially in client mode where most of time you |
|
+would like to ensure the authenticity of the server you're talking to. |
|
+Therefore, when in client mode, it is highly recommended to use |
|
+:const:`CERT_REQUIRED`. However, it is in itself not sufficient; you also |
|
+have to check that the server certificate, which can be obtained by calling |
|
+:meth:`SSLSocket.getpeercert`, matches the desired service. For many |
|
+protocols and applications, the service can be identified by the hostname; |
|
+in this case, the :func:`match_hostname` function can be used. This common |
|
+check is automatically performed when :attr:`SSLContext.check_hostname` is |
|
+enabled. |
|
+ |
|
+In server mode, if you want to authenticate your clients using the SSL layer |
|
+(rather than using a higher-level authentication mechanism), you'll also have |
|
+to specify :const:`CERT_REQUIRED` and similarly check the client certificate. |
|
+ |
|
+ .. note:: |
|
+ |
|
+ In client mode, :const:`CERT_OPTIONAL` and :const:`CERT_REQUIRED` are |
|
+ equivalent unless anonymous ciphers are enabled (they are disabled |
|
+ by default). |
|
+ |
|
+Protocol versions |
|
+''''''''''''''''' |
|
+ |
|
+SSL version 2 is considered insecure and is therefore dangerous to use. If |
|
+you want maximum compatibility between clients and servers, it is recommended |
|
+to use :const:`PROTOCOL_SSLv23` as the protocol version and then disable |
|
+SSLv2 explicitly using the :data:`SSLContext.options` attribute:: |
|
+ |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ context.options |= ssl.OP_NO_SSLv2 |
|
+ |
|
+The SSL context created above will allow SSLv3 and TLSv1 (and later, if |
|
+supported by your system) connections, but not SSLv2. |
|
+ |
|
+Cipher selection |
|
+'''''''''''''''' |
|
+ |
|
+If you have advanced security requirements, fine-tuning of the ciphers |
|
+enabled when negotiating a SSL session is possible through the |
|
+:meth:`SSLContext.set_ciphers` method. Starting from Python 2.7.9, the |
|
+ssl module disables certain weak ciphers by default, but you may want |
|
+to further restrict the cipher choice. Be sure to read OpenSSL's documentation |
|
+about the `cipher list format <http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_. |
|
+If you want to check which ciphers are enabled by a given cipher list, use the |
|
+``openssl ciphers`` command on your system. |
|
+ |
|
+Multi-processing |
|
+^^^^^^^^^^^^^^^^ |
|
+ |
|
+If using this module as part of a multi-processed application (using, |
|
+for example the :mod:`multiprocessing` or :mod:`concurrent.futures` modules), |
|
+be aware that OpenSSL's internal random number generator does not properly |
|
+handle forked processes. Applications must change the PRNG state of the |
|
+parent process if they use any SSL feature with :func:`os.fork`. Any |
|
+successful call of :func:`~ssl.RAND_add`, :func:`~ssl.RAND_bytes` or |
|
+:func:`~ssl.RAND_pseudo_bytes` is sufficient. |
|
|
|
|
|
.. seealso:: |
|
@@ -654,3 +1671,15 @@ And go back to listening for new client |
|
|
|
`RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile <http://www.ietf.org/rfc/rfc3280>`_ |
|
Housley et. al. |
|
+ |
|
+ `RFC 4366: Transport Layer Security (TLS) Extensions <http://www.ietf.org/rfc/rfc4366>`_ |
|
+ Blake-Wilson et. al. |
|
+ |
|
+ `RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 <http://www.ietf.org/rfc/rfc5246>`_ |
|
+ T. Dierks et. al. |
|
+ |
|
+ `RFC 6066: Transport Layer Security (TLS) Extensions <http://www.ietf.org/rfc/rfc6066>`_ |
|
+ D. Eastlake |
|
+ |
|
+ `IANA TLS: Transport Layer Security (TLS) Parameters <http://www.iana.org/assignments/tls-parameters/tls-parameters.xml>`_ |
|
+ IANA |
|
diff -up Python-2.7.5/Lib/test/test_ssl.py.ssl Python-2.7.5/Lib/test/test_ssl.py |
|
--- Python-2.7.5/Lib/test/test_ssl.py.ssl 2015-02-24 11:37:12.270937480 +0100 |
|
+++ Python-2.7.5/Lib/test/test_ssl.py 2015-02-24 10:17:44.084768602 +0100 |
|
@@ -1,35 +1,78 @@ |
|
+# -*- coding: utf-8 -*- |
|
# Test the support for SSL and sockets |
|
|
|
import sys |
|
import unittest |
|
-from test import test_support |
|
+from test import test_support as support |
|
import asyncore |
|
import socket |
|
import select |
|
import time |
|
+import datetime |
|
import gc |
|
import os |
|
import errno |
|
import pprint |
|
-import urllib, urlparse |
|
+import tempfile |
|
+import urllib |
|
import traceback |
|
import weakref |
|
-import functools |
|
import platform |
|
+import functools |
|
+from contextlib import closing |
|
+ |
|
+ssl = support.import_module("ssl") |
|
|
|
-from BaseHTTPServer import HTTPServer |
|
-from SimpleHTTPServer import SimpleHTTPRequestHandler |
|
+PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) |
|
+HOST = support.HOST |
|
|
|
-ssl = test_support.import_module("ssl") |
|
+def data_file(*name): |
|
+ return os.path.join(os.path.dirname(__file__), *name) |
|
+ |
|
+# The custom key and certificate files used in test_ssl are generated |
|
+# using Lib/test/make_ssl_certs.py. |
|
+# Other certificates are simply fetched from the Internet servers they |
|
+# are meant to authenticate. |
|
+ |
|
+CERTFILE = data_file("keycert.pem") |
|
+BYTES_CERTFILE = CERTFILE.encode(sys.getfilesystemencoding()) |
|
+ONLYCERT = data_file("ssl_cert.pem") |
|
+ONLYKEY = data_file("ssl_key.pem") |
|
+BYTES_ONLYCERT = ONLYCERT.encode(sys.getfilesystemencoding()) |
|
+BYTES_ONLYKEY = ONLYKEY.encode(sys.getfilesystemencoding()) |
|
+CERTFILE_PROTECTED = data_file("keycert.passwd.pem") |
|
+ONLYKEY_PROTECTED = data_file("ssl_key.passwd.pem") |
|
+KEY_PASSWORD = "somepass" |
|
+CAPATH = data_file("capath") |
|
+BYTES_CAPATH = CAPATH.encode(sys.getfilesystemencoding()) |
|
+CAFILE_NEURONIO = data_file("capath", "4e1295a3.0") |
|
+CAFILE_CACERT = data_file("capath", "5ed36f99.0") |
|
+ |
|
+ |
|
+# empty CRL |
|
+CRLFILE = data_file("revocation.crl") |
|
+ |
|
+# Two keys and certs signed by the same CA (for SNI tests) |
|
+SIGNED_CERTFILE = data_file("keycert3.pem") |
|
+SIGNED_CERTFILE2 = data_file("keycert4.pem") |
|
+SIGNING_CA = data_file("pycacert.pem") |
|
+ |
|
+SVN_PYTHON_ORG_ROOT_CERT = data_file("https_svn_python_org_root.pem") |
|
+ |
|
+EMPTYCERT = data_file("nullcert.pem") |
|
+BADCERT = data_file("badcert.pem") |
|
+WRONGCERT = data_file("XXXnonexisting.pem") |
|
+BADKEY = data_file("badkey.pem") |
|
+NOKIACERT = data_file("nokia.pem") |
|
+NULLBYTECERT = data_file("nullbytecert.pem") |
|
+ |
|
+DHFILE = data_file("dh512.pem") |
|
+BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding()) |
|
|
|
-HOST = test_support.HOST |
|
-CERTFILE = None |
|
-SVN_PYTHON_ORG_ROOT_CERT = None |
|
-NULLBYTECERT = None |
|
|
|
def handle_error(prefix): |
|
exc_format = ' '.join(traceback.format_exception(*sys.exc_info())) |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write(prefix + exc_format) |
|
|
|
|
|
@@ -51,48 +94,76 @@ class BasicTests(unittest.TestCase): |
|
pass |
|
else: |
|
raise |
|
+def can_clear_options(): |
|
+ # 0.9.8m or higher |
|
+ return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15) |
|
+ |
|
+def no_sslv2_implies_sslv3_hello(): |
|
+ # 0.9.7h or higher |
|
+ return ssl.OPENSSL_VERSION_INFO >= (0, 9, 7, 8, 15) |
|
+ |
|
+def have_verify_flags(): |
|
+ # 0.9.8 or higher |
|
+ return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15) |
|
+ |
|
+def utc_offset(): #NOTE: ignore issues like #1647654 |
|
+ # local time = utc time + utc offset |
|
+ if time.daylight and time.localtime().tm_isdst > 0: |
|
+ return -time.altzone # seconds |
|
+ return -time.timezone |
|
+ |
|
+def asn1time(cert_time): |
|
+ # Some versions of OpenSSL ignore seconds, see #18207 |
|
+ # 0.9.8.i |
|
+ if ssl._OPENSSL_API_VERSION == (0, 9, 8, 9, 15): |
|
+ fmt = "%b %d %H:%M:%S %Y GMT" |
|
+ dt = datetime.datetime.strptime(cert_time, fmt) |
|
+ dt = dt.replace(second=0) |
|
+ cert_time = dt.strftime(fmt) |
|
+ # %d adds leading zero but ASN1_TIME_print() uses leading space |
|
+ if cert_time[4] == "0": |
|
+ cert_time = cert_time[:4] + " " + cert_time[5:] |
|
+ |
|
+ return cert_time |
|
|
|
# Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2 |
|
def skip_if_broken_ubuntu_ssl(func): |
|
if hasattr(ssl, 'PROTOCOL_SSLv2'): |
|
- # We need to access the lower-level wrapper in order to create an |
|
- # implicit SSL context without trying to connect or listen. |
|
- try: |
|
- import _ssl |
|
- except ImportError: |
|
- # The returned function won't get executed, just ignore the error |
|
- pass |
|
@functools.wraps(func) |
|
def f(*args, **kwargs): |
|
try: |
|
- s = socket.socket(socket.AF_INET) |
|
- _ssl.sslwrap(s._sock, 0, None, None, |
|
- ssl.CERT_NONE, ssl.PROTOCOL_SSLv2, None, None) |
|
- except ssl.SSLError as e: |
|
+ ssl.SSLContext(ssl.PROTOCOL_SSLv2) |
|
+ except ssl.SSLError: |
|
if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and |
|
- platform.linux_distribution() == ('debian', 'squeeze/sid', '') |
|
- and 'Invalid SSL protocol variant specified' in str(e)): |
|
+ platform.linux_distribution() == ('debian', 'squeeze/sid', '')): |
|
raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") |
|
return func(*args, **kwargs) |
|
return f |
|
else: |
|
return func |
|
|
|
+needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test") |
|
+ |
|
|
|
class BasicSocketTests(unittest.TestCase): |
|
|
|
def test_constants(self): |
|
- #ssl.PROTOCOL_SSLv2 |
|
- ssl.PROTOCOL_SSLv23 |
|
- ssl.PROTOCOL_SSLv3 |
|
- ssl.PROTOCOL_TLSv1 |
|
ssl.CERT_NONE |
|
ssl.CERT_OPTIONAL |
|
ssl.CERT_REQUIRED |
|
+ ssl.OP_CIPHER_SERVER_PREFERENCE |
|
+ ssl.OP_SINGLE_DH_USE |
|
+ if ssl.HAS_ECDH: |
|
+ ssl.OP_SINGLE_ECDH_USE |
|
+ if ssl.OPENSSL_VERSION_INFO >= (1, 0): |
|
+ ssl.OP_NO_COMPRESSION |
|
+ self.assertIn(ssl.HAS_SNI, {True, False}) |
|
+ self.assertIn(ssl.HAS_ECDH, {True, False}) |
|
+ |
|
|
|
def test_random(self): |
|
v = ssl.RAND_status() |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n RAND_status is %d (%s)\n" |
|
% (v, (v and "sufficient randomness") or |
|
"insufficient randomness")) |
|
@@ -104,9 +175,19 @@ class BasicSocketTests(unittest.TestCase |
|
# note that this uses an 'unofficial' function in _ssl.c, |
|
# provided solely for this test, to exercise the certificate |
|
# parsing code |
|
- p = ssl._ssl._test_decode_cert(CERTFILE, False) |
|
- if test_support.verbose: |
|
+ p = ssl._ssl._test_decode_cert(CERTFILE) |
|
+ if support.verbose: |
|
sys.stdout.write("\n" + pprint.pformat(p) + "\n") |
|
+ self.assertEqual(p['issuer'], |
|
+ ((('countryName', 'XY'),), |
|
+ (('localityName', 'Castle Anthrax'),), |
|
+ (('organizationName', 'Python Software Foundation'),), |
|
+ (('commonName', 'localhost'),)) |
|
+ ) |
|
+ # Note the next three asserts will fail if the keys are regenerated |
|
+ self.assertEqual(p['notAfter'], asn1time('Oct 5 23:01:56 2020 GMT')) |
|
+ self.assertEqual(p['notBefore'], asn1time('Oct 8 23:01:56 2010 GMT')) |
|
+ self.assertEqual(p['serialNumber'], 'D7C7381919AFC24E') |
|
self.assertEqual(p['subject'], |
|
((('countryName', 'XY'),), |
|
(('localityName', 'Castle Anthrax'),), |
|
@@ -117,16 +198,23 @@ class BasicSocketTests(unittest.TestCase |
|
# Issue #13034: the subjectAltName in some certificates |
|
# (notably projects.developer.nokia.com:443) wasn't parsed |
|
p = ssl._ssl._test_decode_cert(NOKIACERT) |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n" + pprint.pformat(p) + "\n") |
|
self.assertEqual(p['subjectAltName'], |
|
(('DNS', 'projects.developer.nokia.com'), |
|
('DNS', 'projects.forum.nokia.com')) |
|
) |
|
+ # extra OCSP and AIA fields |
|
+ self.assertEqual(p['OCSP'], ('http://ocsp.verisign.com',)) |
|
+ self.assertEqual(p['caIssuers'], |
|
+ ('http://SVRIntl-G3-aia.verisign.com/SVRIntlG3.cer',)) |
|
+ self.assertEqual(p['crlDistributionPoints'], |
|
+ ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',)) |
|
+ |
|
|
|
def test_parse_cert_CVE_2013_4073(self): |
|
p = ssl._ssl._test_decode_cert(NULLBYTECERT) |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n" + pprint.pformat(p) + "\n") |
|
subject = ((('countryName', 'US'),), |
|
(('stateOrProvinceName', 'Oregon'),), |
|
@@ -184,25 +272,7 @@ class BasicSocketTests(unittest.TestCase |
|
self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)), |
|
(s, t)) |
|
|
|
- def test_ciphers(self): |
|
- if not test_support.is_resource_enabled('network'): |
|
- return |
|
- remote = ("svn.python.org", 443) |
|
- with test_support.transient_internet(remote[0]): |
|
- s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
- cert_reqs=ssl.CERT_NONE, ciphers="ALL") |
|
- s.connect(remote) |
|
- s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
- cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") |
|
- s.connect(remote) |
|
- # Error checking occurs when connecting, because the SSL context |
|
- # isn't created before. |
|
- s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
- cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") |
|
- with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): |
|
- s.connect(remote) |
|
- |
|
- @test_support.cpython_only |
|
+ @support.cpython_only |
|
def test_refcycle(self): |
|
# Issue #7943: an SSL object doesn't create reference cycles with |
|
# itself. |
|
@@ -213,53 +283,917 @@ class BasicSocketTests(unittest.TestCase |
|
self.assertEqual(wr(), None) |
|
|
|
def test_wrapped_unconnected(self): |
|
- # The _delegate_methods in socket.py are correctly delegated to by an |
|
- # unconnected SSLSocket, so they will raise a socket.error rather than |
|
- # something unexpected like TypeError. |
|
+ # Methods on an unconnected SSLSocket propagate the original |
|
+ # socket.error raise by the underlying socket object. |
|
s = socket.socket(socket.AF_INET) |
|
- ss = ssl.wrap_socket(s) |
|
- self.assertRaises(socket.error, ss.recv, 1) |
|
- self.assertRaises(socket.error, ss.recv_into, bytearray(b'x')) |
|
- self.assertRaises(socket.error, ss.recvfrom, 1) |
|
- self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1) |
|
- self.assertRaises(socket.error, ss.send, b'x') |
|
- self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0)) |
|
+ with closing(ssl.wrap_socket(s)) as ss: |
|
+ self.assertRaises(socket.error, ss.recv, 1) |
|
+ self.assertRaises(socket.error, ss.recv_into, bytearray(b'x')) |
|
+ self.assertRaises(socket.error, ss.recvfrom, 1) |
|
+ self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1) |
|
+ self.assertRaises(socket.error, ss.send, b'x') |
|
+ self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0)) |
|
+ |
|
+ def test_timeout(self): |
|
+ # Issue #8524: when creating an SSL socket, the timeout of the |
|
+ # original socket should be retained. |
|
+ for timeout in (None, 0.0, 5.0): |
|
+ s = socket.socket(socket.AF_INET) |
|
+ s.settimeout(timeout) |
|
+ with closing(ssl.wrap_socket(s)) as ss: |
|
+ self.assertEqual(timeout, ss.gettimeout()) |
|
+ |
|
+ def test_errors(self): |
|
+ sock = socket.socket() |
|
+ self.assertRaisesRegexp(ValueError, |
|
+ "certfile must be specified", |
|
+ ssl.wrap_socket, sock, keyfile=CERTFILE) |
|
+ self.assertRaisesRegexp(ValueError, |
|
+ "certfile must be specified for server-side operations", |
|
+ ssl.wrap_socket, sock, server_side=True) |
|
+ self.assertRaisesRegexp(ValueError, |
|
+ "certfile must be specified for server-side operations", |
|
+ ssl.wrap_socket, sock, server_side=True, certfile="") |
|
+ with closing(ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE)) as s: |
|
+ self.assertRaisesRegexp(ValueError, "can't connect in server-side mode", |
|
+ s.connect, (HOST, 8080)) |
|
+ with self.assertRaises(IOError) as cm: |
|
+ with closing(socket.socket()) as sock: |
|
+ ssl.wrap_socket(sock, certfile=WRONGCERT) |
|
+ self.assertEqual(cm.exception.errno, errno.ENOENT) |
|
+ with self.assertRaises(IOError) as cm: |
|
+ with closing(socket.socket()) as sock: |
|
+ ssl.wrap_socket(sock, certfile=CERTFILE, keyfile=WRONGCERT) |
|
+ self.assertEqual(cm.exception.errno, errno.ENOENT) |
|
+ with self.assertRaises(IOError) as cm: |
|
+ with closing(socket.socket()) as sock: |
|
+ ssl.wrap_socket(sock, certfile=WRONGCERT, keyfile=WRONGCERT) |
|
+ self.assertEqual(cm.exception.errno, errno.ENOENT) |
|
+ |
|
+ def test_match_hostname(self): |
|
+ def ok(cert, hostname): |
|
+ ssl.match_hostname(cert, hostname) |
|
+ def fail(cert, hostname): |
|
+ self.assertRaises(ssl.CertificateError, |
|
+ ssl.match_hostname, cert, hostname) |
|
+ |
|
+ cert = {'subject': ((('commonName', 'example.com'),),)} |
|
+ ok(cert, 'example.com') |
|
+ ok(cert, 'ExAmple.cOm') |
|
+ fail(cert, 'www.example.com') |
|
+ fail(cert, '.example.com') |
|
+ fail(cert, 'example.org') |
|
+ fail(cert, 'exampleXcom') |
|
+ |
|
+ cert = {'subject': ((('commonName', '*.a.com'),),)} |
|
+ ok(cert, 'foo.a.com') |
|
+ fail(cert, 'bar.foo.a.com') |
|
+ fail(cert, 'a.com') |
|
+ fail(cert, 'Xa.com') |
|
+ fail(cert, '.a.com') |
|
+ |
|
+ # only match one left-most wildcard |
|
+ cert = {'subject': ((('commonName', 'f*.com'),),)} |
|
+ ok(cert, 'foo.com') |
|
+ ok(cert, 'f.com') |
|
+ fail(cert, 'bar.com') |
|
+ fail(cert, 'foo.a.com') |
|
+ fail(cert, 'bar.foo.com') |
|
+ |
|
+ # NULL bytes are bad, CVE-2013-4073 |
|
+ cert = {'subject': ((('commonName', |
|
+ 'null.python.org\x00example.org'),),)} |
|
+ ok(cert, 'null.python.org\x00example.org') # or raise an error? |
|
+ fail(cert, 'example.org') |
|
+ fail(cert, 'null.python.org') |
|
+ |
|
+ # error cases with wildcards |
|
+ cert = {'subject': ((('commonName', '*.*.a.com'),),)} |
|
+ fail(cert, 'bar.foo.a.com') |
|
+ fail(cert, 'a.com') |
|
+ fail(cert, 'Xa.com') |
|
+ fail(cert, '.a.com') |
|
+ |
|
+ cert = {'subject': ((('commonName', 'a.*.com'),),)} |
|
+ fail(cert, 'a.foo.com') |
|
+ fail(cert, 'a..com') |
|
+ fail(cert, 'a.com') |
|
+ |
|
+ # wildcard doesn't match IDNA prefix 'xn--' |
|
+ idna = u'püthon.python.org'.encode("idna").decode("ascii") |
|
+ cert = {'subject': ((('commonName', idna),),)} |
|
+ ok(cert, idna) |
|
+ cert = {'subject': ((('commonName', 'x*.python.org'),),)} |
|
+ fail(cert, idna) |
|
+ cert = {'subject': ((('commonName', 'xn--p*.python.org'),),)} |
|
+ fail(cert, idna) |
|
+ |
|
+ # wildcard in first fragment and IDNA A-labels in sequent fragments |
|
+ # are supported. |
|
+ idna = u'www*.pythön.org'.encode("idna").decode("ascii") |
|
+ cert = {'subject': ((('commonName', idna),),)} |
|
+ ok(cert, u'www.pythön.org'.encode("idna").decode("ascii")) |
|
+ ok(cert, u'www1.pythön.org'.encode("idna").decode("ascii")) |
|
+ fail(cert, u'ftp.pythön.org'.encode("idna").decode("ascii")) |
|
+ fail(cert, u'pythön.org'.encode("idna").decode("ascii")) |
|
+ |
|
+ # Slightly fake real-world example |
|
+ cert = {'notAfter': 'Jun 26 21:41:46 2011 GMT', |
|
+ 'subject': ((('commonName', 'linuxfrz.org'),),), |
|
+ 'subjectAltName': (('DNS', 'linuxfr.org'), |
|
+ ('DNS', 'linuxfr.com'), |
|
+ ('othername', '<unsupported>'))} |
|
+ ok(cert, 'linuxfr.org') |
|
+ ok(cert, 'linuxfr.com') |
|
+ # Not a "DNS" entry |
|
+ fail(cert, '<unsupported>') |
|
+ # When there is a subjectAltName, commonName isn't used |
|
+ fail(cert, 'linuxfrz.org') |
|
+ |
|
+ # A pristine real-world example |
|
+ cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT', |
|
+ 'subject': ((('countryName', 'US'),), |
|
+ (('stateOrProvinceName', 'California'),), |
|
+ (('localityName', 'Mountain View'),), |
|
+ (('organizationName', 'Google Inc'),), |
|
+ (('commonName', 'mail.google.com'),))} |
|
+ ok(cert, 'mail.google.com') |
|
+ fail(cert, 'gmail.com') |
|
+ # Only commonName is considered |
|
+ fail(cert, 'California') |
|
+ |
|
+ # Neither commonName nor subjectAltName |
|
+ cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT', |
|
+ 'subject': ((('countryName', 'US'),), |
|
+ (('stateOrProvinceName', 'California'),), |
|
+ (('localityName', 'Mountain View'),), |
|
+ (('organizationName', 'Google Inc'),))} |
|
+ fail(cert, 'mail.google.com') |
|
+ |
|
+ # No DNS entry in subjectAltName but a commonName |
|
+ cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', |
|
+ 'subject': ((('countryName', 'US'),), |
|
+ (('stateOrProvinceName', 'California'),), |
|
+ (('localityName', 'Mountain View'),), |
|
+ (('commonName', 'mail.google.com'),)), |
|
+ 'subjectAltName': (('othername', 'blabla'), )} |
|
+ ok(cert, 'mail.google.com') |
|
+ |
|
+ # No DNS entry subjectAltName and no commonName |
|
+ cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT', |
|
+ 'subject': ((('countryName', 'US'),), |
|
+ (('stateOrProvinceName', 'California'),), |
|
+ (('localityName', 'Mountain View'),), |
|
+ (('organizationName', 'Google Inc'),)), |
|
+ 'subjectAltName': (('othername', 'blabla'),)} |
|
+ fail(cert, 'google.com') |
|
+ |
|
+ # Empty cert / no cert |
|
+ self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com') |
|
+ self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com') |
|
+ |
|
+ # Issue #17980: avoid denials of service by refusing more than one |
|
+ # wildcard per fragment. |
|
+ cert = {'subject': ((('commonName', 'a*b.com'),),)} |
|
+ ok(cert, 'axxb.com') |
|
+ cert = {'subject': ((('commonName', 'a*b.co*'),),)} |
|
+ fail(cert, 'axxb.com') |
|
+ cert = {'subject': ((('commonName', 'a*b*.com'),),)} |
|
+ with self.assertRaises(ssl.CertificateError) as cm: |
|
+ ssl.match_hostname(cert, 'axxbxxc.com') |
|
+ self.assertIn("too many wildcards", str(cm.exception)) |
|
+ |
|
+ def test_server_side(self): |
|
+ # server_hostname doesn't work for server sockets |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ with closing(socket.socket()) as sock: |
|
+ self.assertRaises(ValueError, ctx.wrap_socket, sock, True, |
|
+ server_hostname="some.hostname") |
|
+ |
|
+ def test_unknown_channel_binding(self): |
|
+ # should raise ValueError for unknown type |
|
+ s = socket.socket(socket.AF_INET) |
|
+ with closing(ssl.wrap_socket(s)) as ss: |
|
+ with self.assertRaises(ValueError): |
|
+ ss.get_channel_binding("unknown-type") |
|
+ |
|
+ @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES, |
|
+ "'tls-unique' channel binding not available") |
|
+ def test_tls_unique_channel_binding(self): |
|
+ # unconnected should return None for known type |
|
+ s = socket.socket(socket.AF_INET) |
|
+ with closing(ssl.wrap_socket(s)) as ss: |
|
+ self.assertIsNone(ss.get_channel_binding("tls-unique")) |
|
+ # the same for server-side |
|
+ s = socket.socket(socket.AF_INET) |
|
+ with closing(ssl.wrap_socket(s, server_side=True, certfile=CERTFILE)) as ss: |
|
+ self.assertIsNone(ss.get_channel_binding("tls-unique")) |
|
+ |
|
+ def test_get_default_verify_paths(self): |
|
+ paths = ssl.get_default_verify_paths() |
|
+ self.assertEqual(len(paths), 6) |
|
+ self.assertIsInstance(paths, ssl.DefaultVerifyPaths) |
|
+ |
|
+ with support.EnvironmentVarGuard() as env: |
|
+ env["SSL_CERT_DIR"] = CAPATH |
|
+ env["SSL_CERT_FILE"] = CERTFILE |
|
+ paths = ssl.get_default_verify_paths() |
|
+ self.assertEqual(paths.cafile, CERTFILE) |
|
+ self.assertEqual(paths.capath, CAPATH) |
|
+ |
|
+ @unittest.skipUnless(sys.platform == "win32", "Windows specific") |
|
+ def test_enum_certificates(self): |
|
+ self.assertTrue(ssl.enum_certificates("CA")) |
|
+ self.assertTrue(ssl.enum_certificates("ROOT")) |
|
+ |
|
+ self.assertRaises(TypeError, ssl.enum_certificates) |
|
+ self.assertRaises(WindowsError, ssl.enum_certificates, "") |
|
+ |
|
+ trust_oids = set() |
|
+ for storename in ("CA", "ROOT"): |
|
+ store = ssl.enum_certificates(storename) |
|
+ self.assertIsInstance(store, list) |
|
+ for element in store: |
|
+ self.assertIsInstance(element, tuple) |
|
+ self.assertEqual(len(element), 3) |
|
+ cert, enc, trust = element |
|
+ self.assertIsInstance(cert, bytes) |
|
+ self.assertIn(enc, {"x509_asn", "pkcs_7_asn"}) |
|
+ self.assertIsInstance(trust, (set, bool)) |
|
+ if isinstance(trust, set): |
|
+ trust_oids.update(trust) |
|
+ |
|
+ serverAuth = "1.3.6.1.5.5.7.3.1" |
|
+ self.assertIn(serverAuth, trust_oids) |
|
+ |
|
+ @unittest.skipUnless(sys.platform == "win32", "Windows specific") |
|
+ def test_enum_crls(self): |
|
+ self.assertTrue(ssl.enum_crls("CA")) |
|
+ self.assertRaises(TypeError, ssl.enum_crls) |
|
+ self.assertRaises(WindowsError, ssl.enum_crls, "") |
|
+ |
|
+ crls = ssl.enum_crls("CA") |
|
+ self.assertIsInstance(crls, list) |
|
+ for element in crls: |
|
+ self.assertIsInstance(element, tuple) |
|
+ self.assertEqual(len(element), 2) |
|
+ self.assertIsInstance(element[0], bytes) |
|
+ self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"}) |
|
+ |
|
+ |
|
+ def test_asn1object(self): |
|
+ expected = (129, 'serverAuth', 'TLS Web Server Authentication', |
|
+ '1.3.6.1.5.5.7.3.1') |
|
+ |
|
+ val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1') |
|
+ self.assertEqual(val, expected) |
|
+ self.assertEqual(val.nid, 129) |
|
+ self.assertEqual(val.shortname, 'serverAuth') |
|
+ self.assertEqual(val.longname, 'TLS Web Server Authentication') |
|
+ self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1') |
|
+ self.assertIsInstance(val, ssl._ASN1Object) |
|
+ self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth') |
|
+ |
|
+ val = ssl._ASN1Object.fromnid(129) |
|
+ self.assertEqual(val, expected) |
|
+ self.assertIsInstance(val, ssl._ASN1Object) |
|
+ self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1) |
|
+ with self.assertRaisesRegexp(ValueError, "unknown NID 100000"): |
|
+ ssl._ASN1Object.fromnid(100000) |
|
+ for i in range(1000): |
|
+ try: |
|
+ obj = ssl._ASN1Object.fromnid(i) |
|
+ except ValueError: |
|
+ pass |
|
+ else: |
|
+ self.assertIsInstance(obj.nid, int) |
|
+ self.assertIsInstance(obj.shortname, str) |
|
+ self.assertIsInstance(obj.longname, str) |
|
+ self.assertIsInstance(obj.oid, (str, type(None))) |
|
+ |
|
+ val = ssl._ASN1Object.fromname('TLS Web Server Authentication') |
|
+ self.assertEqual(val, expected) |
|
+ self.assertIsInstance(val, ssl._ASN1Object) |
|
+ self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected) |
|
+ self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'), |
|
+ expected) |
|
+ with self.assertRaisesRegexp(ValueError, "unknown object 'serverauth'"): |
|
+ ssl._ASN1Object.fromname('serverauth') |
|
+ |
|
+ def test_purpose_enum(self): |
|
+ val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1') |
|
+ self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object) |
|
+ self.assertEqual(ssl.Purpose.SERVER_AUTH, val) |
|
+ self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129) |
|
+ self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth') |
|
+ self.assertEqual(ssl.Purpose.SERVER_AUTH.oid, |
|
+ '1.3.6.1.5.5.7.3.1') |
|
+ |
|
+ val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2') |
|
+ self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object) |
|
+ self.assertEqual(ssl.Purpose.CLIENT_AUTH, val) |
|
+ self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130) |
|
+ self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth') |
|
+ self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid, |
|
+ '1.3.6.1.5.5.7.3.2') |
|
+ |
|
+ def cert_time_ok(self, timestring, timestamp): |
|
+ self.assertEqual(ssl.cert_time_to_seconds(timestring), timestamp) |
|
+ |
|
+ def cert_time_fail(self, timestring): |
|
+ with self.assertRaises(ValueError): |
|
+ ssl.cert_time_to_seconds(timestring) |
|
+ |
|
+ @unittest.skipUnless(utc_offset(), |
|
+ 'local time needs to be different from UTC') |
|
+ def test_cert_time_to_seconds_timezone(self): |
|
+ # Issue #19940: ssl.cert_time_to_seconds() returns wrong |
|
+ # results if local timezone is not UTC |
|
+ self.cert_time_ok("May 9 00:00:00 2007 GMT", 1178668800.0) |
|
+ self.cert_time_ok("Jan 5 09:34:43 2018 GMT", 1515144883.0) |
|
+ |
|
+ def test_cert_time_to_seconds(self): |
|
+ timestring = "Jan 5 09:34:43 2018 GMT" |
|
+ ts = 1515144883.0 |
|
+ self.cert_time_ok(timestring, ts) |
|
+ # accept keyword parameter, assert its name |
|
+ self.assertEqual(ssl.cert_time_to_seconds(cert_time=timestring), ts) |
|
+ # accept both %e and %d (space or zero generated by strftime) |
|
+ self.cert_time_ok("Jan 05 09:34:43 2018 GMT", ts) |
|
+ # case-insensitive |
|
+ self.cert_time_ok("JaN 5 09:34:43 2018 GmT", ts) |
|
+ self.cert_time_fail("Jan 5 09:34 2018 GMT") # no seconds |
|
+ self.cert_time_fail("Jan 5 09:34:43 2018") # no GMT |
|
+ self.cert_time_fail("Jan 5 09:34:43 2018 UTC") # not GMT timezone |
|
+ self.cert_time_fail("Jan 35 09:34:43 2018 GMT") # invalid day |
|
+ self.cert_time_fail("Jon 5 09:34:43 2018 GMT") # invalid month |
|
+ self.cert_time_fail("Jan 5 24:00:00 2018 GMT") # invalid hour |
|
+ self.cert_time_fail("Jan 5 09:60:43 2018 GMT") # invalid minute |
|
+ |
|
+ newyear_ts = 1230768000.0 |
|
+ # leap seconds |
|
+ self.cert_time_ok("Dec 31 23:59:60 2008 GMT", newyear_ts) |
|
+ # same timestamp |
|
+ self.cert_time_ok("Jan 1 00:00:00 2009 GMT", newyear_ts) |
|
+ |
|
+ self.cert_time_ok("Jan 5 09:34:59 2018 GMT", 1515144899) |
|
+ # allow 60th second (even if it is not a leap second) |
|
+ self.cert_time_ok("Jan 5 09:34:60 2018 GMT", 1515144900) |
|
+ # allow 2nd leap second for compatibility with time.strptime() |
|
+ self.cert_time_ok("Jan 5 09:34:61 2018 GMT", 1515144901) |
|
+ self.cert_time_fail("Jan 5 09:34:62 2018 GMT") # invalid seconds |
|
+ |
|
+ # no special treatement for the special value: |
|
+ # 99991231235959Z (rfc 5280) |
|
+ self.cert_time_ok("Dec 31 23:59:59 9999 GMT", 253402300799.0) |
|
+ |
|
+ @support.run_with_locale('LC_ALL', '') |
|
+ def test_cert_time_to_seconds_locale(self): |
|
+ # `cert_time_to_seconds()` should be locale independent |
|
+ |
|
+ def local_february_name(): |
|
+ return time.strftime('%b', (1, 2, 3, 4, 5, 6, 0, 0, 0)) |
|
+ |
|
+ if local_february_name().lower() == 'feb': |
|
+ self.skipTest("locale-specific month name needs to be " |
|
+ "different from C locale") |
|
+ |
|
+ # locale-independent |
|
+ self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0) |
|
+ self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT") |
|
+ |
|
+ |
|
+class ContextTests(unittest.TestCase): |
|
+ |
|
+ @skip_if_broken_ubuntu_ssl |
|
+ def test_constructor(self): |
|
+ for protocol in PROTOCOLS: |
|
+ ssl.SSLContext(protocol) |
|
+ self.assertRaises(TypeError, ssl.SSLContext) |
|
+ self.assertRaises(ValueError, ssl.SSLContext, -1) |
|
+ self.assertRaises(ValueError, ssl.SSLContext, 42) |
|
+ |
|
+ @skip_if_broken_ubuntu_ssl |
|
+ def test_protocol(self): |
|
+ for proto in PROTOCOLS: |
|
+ ctx = ssl.SSLContext(proto) |
|
+ self.assertEqual(ctx.protocol, proto) |
|
+ |
|
+ def test_ciphers(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.set_ciphers("ALL") |
|
+ ctx.set_ciphers("DEFAULT") |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): |
|
+ ctx.set_ciphers("^$:,;?*'dorothyx") |
|
+ |
|
+ @skip_if_broken_ubuntu_ssl |
|
+ def test_options(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ # OP_ALL | OP_NO_SSLv2 is the default value |
|
+ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, |
|
+ ctx.options) |
|
+ ctx.options |= ssl.OP_NO_SSLv3 |
|
+ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3, |
|
+ ctx.options) |
|
+ if can_clear_options(): |
|
+ ctx.options = (ctx.options & ~ssl.OP_NO_SSLv2) | ssl.OP_NO_TLSv1 |
|
+ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_TLSv1 | ssl.OP_NO_SSLv3, |
|
+ ctx.options) |
|
+ ctx.options = 0 |
|
+ self.assertEqual(0, ctx.options) |
|
+ else: |
|
+ with self.assertRaises(ValueError): |
|
+ ctx.options = 0 |
|
+ |
|
+ def test_verify_mode(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ # Default value |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) |
|
+ ctx.verify_mode = ssl.CERT_OPTIONAL |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL) |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) |
|
+ ctx.verify_mode = ssl.CERT_NONE |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) |
|
+ with self.assertRaises(TypeError): |
|
+ ctx.verify_mode = None |
|
+ with self.assertRaises(ValueError): |
|
+ ctx.verify_mode = 42 |
|
+ |
|
+ @unittest.skipUnless(have_verify_flags(), |
|
+ "verify_flags need OpenSSL > 0.9.8") |
|
+ def test_verify_flags(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ # default value by OpenSSL |
|
+ self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT) |
|
+ ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF |
|
+ self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_LEAF) |
|
+ ctx.verify_flags = ssl.VERIFY_CRL_CHECK_CHAIN |
|
+ self.assertEqual(ctx.verify_flags, ssl.VERIFY_CRL_CHECK_CHAIN) |
|
+ ctx.verify_flags = ssl.VERIFY_DEFAULT |
|
+ self.assertEqual(ctx.verify_flags, ssl.VERIFY_DEFAULT) |
|
+ # supports any value |
|
+ ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT |
|
+ self.assertEqual(ctx.verify_flags, |
|
+ ssl.VERIFY_CRL_CHECK_LEAF | ssl.VERIFY_X509_STRICT) |
|
+ with self.assertRaises(TypeError): |
|
+ ctx.verify_flags = None |
|
+ |
|
+ def test_load_cert_chain(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ # Combined key and cert in a single file |
|
+ ctx.load_cert_chain(CERTFILE) |
|
+ ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE) |
|
+ self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE) |
|
+ with self.assertRaises(IOError) as cm: |
|
+ ctx.load_cert_chain(WRONGCERT) |
|
+ self.assertEqual(cm.exception.errno, errno.ENOENT) |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): |
|
+ ctx.load_cert_chain(BADCERT) |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): |
|
+ ctx.load_cert_chain(EMPTYCERT) |
|
+ # Separate key and cert |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.load_cert_chain(ONLYCERT, ONLYKEY) |
|
+ ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY) |
|
+ ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY) |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): |
|
+ ctx.load_cert_chain(ONLYCERT) |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): |
|
+ ctx.load_cert_chain(ONLYKEY) |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): |
|
+ ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT) |
|
+ # Mismatching key and cert |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "key values mismatch"): |
|
+ ctx.load_cert_chain(SVN_PYTHON_ORG_ROOT_CERT, ONLYKEY) |
|
+ # Password protected key and cert |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD) |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=KEY_PASSWORD.encode()) |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, |
|
+ password=bytearray(KEY_PASSWORD.encode())) |
|
+ ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD) |
|
+ ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, KEY_PASSWORD.encode()) |
|
+ ctx.load_cert_chain(ONLYCERT, ONLYKEY_PROTECTED, |
|
+ bytearray(KEY_PASSWORD.encode())) |
|
+ with self.assertRaisesRegexp(TypeError, "should be a string"): |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=True) |
|
+ with self.assertRaises(ssl.SSLError): |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password="badpass") |
|
+ with self.assertRaisesRegexp(ValueError, "cannot be longer"): |
|
+ # openssl has a fixed limit on the password buffer. |
|
+ # PEM_BUFSIZE is generally set to 1kb. |
|
+ # Return a string larger than this. |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=b'a' * 102400) |
|
+ # Password callback |
|
+ def getpass_unicode(): |
|
+ return KEY_PASSWORD |
|
+ def getpass_bytes(): |
|
+ return KEY_PASSWORD.encode() |
|
+ def getpass_bytearray(): |
|
+ return bytearray(KEY_PASSWORD.encode()) |
|
+ def getpass_badpass(): |
|
+ return "badpass" |
|
+ def getpass_huge(): |
|
+ return b'a' * (1024 * 1024) |
|
+ def getpass_bad_type(): |
|
+ return 9 |
|
+ def getpass_exception(): |
|
+ raise Exception('getpass error') |
|
+ class GetPassCallable: |
|
+ def __call__(self): |
|
+ return KEY_PASSWORD |
|
+ def getpass(self): |
|
+ return KEY_PASSWORD |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_unicode) |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytes) |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bytearray) |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=GetPassCallable()) |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, |
|
+ password=GetPassCallable().getpass) |
|
+ with self.assertRaises(ssl.SSLError): |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_badpass) |
|
+ with self.assertRaisesRegexp(ValueError, "cannot be longer"): |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_huge) |
|
+ with self.assertRaisesRegexp(TypeError, "must return a string"): |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_bad_type) |
|
+ with self.assertRaisesRegexp(Exception, "getpass error"): |
|
+ ctx.load_cert_chain(CERTFILE_PROTECTED, password=getpass_exception) |
|
+ # Make sure the password function isn't called if it isn't needed |
|
+ ctx.load_cert_chain(CERTFILE, password=getpass_exception) |
|
+ |
|
+ def test_load_verify_locations(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.load_verify_locations(CERTFILE) |
|
+ ctx.load_verify_locations(cafile=CERTFILE, capath=None) |
|
+ ctx.load_verify_locations(BYTES_CERTFILE) |
|
+ ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None) |
|
+ self.assertRaises(TypeError, ctx.load_verify_locations) |
|
+ self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None) |
|
+ with self.assertRaises(IOError) as cm: |
|
+ ctx.load_verify_locations(WRONGCERT) |
|
+ self.assertEqual(cm.exception.errno, errno.ENOENT) |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): |
|
+ ctx.load_verify_locations(BADCERT) |
|
+ ctx.load_verify_locations(CERTFILE, CAPATH) |
|
+ ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH) |
|
+ |
|
+ # Issue #10989: crash if the second argument type is invalid |
|
+ self.assertRaises(TypeError, ctx.load_verify_locations, None, True) |
|
+ |
|
+ def test_load_verify_cadata(self): |
|
+ # test cadata |
|
+ with open(CAFILE_CACERT) as f: |
|
+ cacert_pem = f.read().decode("ascii") |
|
+ cacert_der = ssl.PEM_cert_to_DER_cert(cacert_pem) |
|
+ with open(CAFILE_NEURONIO) as f: |
|
+ neuronio_pem = f.read().decode("ascii") |
|
+ neuronio_der = ssl.PEM_cert_to_DER_cert(neuronio_pem) |
|
+ |
|
+ # test PEM |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 0) |
|
+ ctx.load_verify_locations(cadata=cacert_pem) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 1) |
|
+ ctx.load_verify_locations(cadata=neuronio_pem) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) |
|
+ # cert already in hash table |
|
+ ctx.load_verify_locations(cadata=neuronio_pem) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) |
|
+ |
|
+ # combined |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ combined = "\n".join((cacert_pem, neuronio_pem)) |
|
+ ctx.load_verify_locations(cadata=combined) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) |
|
+ |
|
+ # with junk around the certs |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ combined = ["head", cacert_pem, "other", neuronio_pem, "again", |
|
+ neuronio_pem, "tail"] |
|
+ ctx.load_verify_locations(cadata="\n".join(combined)) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) |
|
+ |
|
+ # test DER |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.load_verify_locations(cadata=cacert_der) |
|
+ ctx.load_verify_locations(cadata=neuronio_der) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) |
|
+ # cert already in hash table |
|
+ ctx.load_verify_locations(cadata=cacert_der) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) |
|
+ |
|
+ # combined |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ combined = b"".join((cacert_der, neuronio_der)) |
|
+ ctx.load_verify_locations(cadata=combined) |
|
+ self.assertEqual(ctx.cert_store_stats()["x509_ca"], 2) |
|
+ |
|
+ # error cases |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ self.assertRaises(TypeError, ctx.load_verify_locations, cadata=object) |
|
+ |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "no start line"): |
|
+ ctx.load_verify_locations(cadata=u"broken") |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "not enough data"): |
|
+ ctx.load_verify_locations(cadata=b"broken") |
|
+ |
|
+ |
|
+ def test_load_dh_params(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.load_dh_params(DHFILE) |
|
+ if os.name != 'nt': |
|
+ ctx.load_dh_params(BYTES_DHFILE) |
|
+ self.assertRaises(TypeError, ctx.load_dh_params) |
|
+ self.assertRaises(TypeError, ctx.load_dh_params, None) |
|
+ with self.assertRaises(IOError) as cm: |
|
+ ctx.load_dh_params(WRONGCERT) |
|
+ self.assertEqual(cm.exception.errno, errno.ENOENT) |
|
+ with self.assertRaises(ssl.SSLError) as cm: |
|
+ ctx.load_dh_params(CERTFILE) |
|
+ |
|
+ @skip_if_broken_ubuntu_ssl |
|
+ def test_session_stats(self): |
|
+ for proto in PROTOCOLS: |
|
+ ctx = ssl.SSLContext(proto) |
|
+ self.assertEqual(ctx.session_stats(), { |
|
+ 'number': 0, |
|
+ 'connect': 0, |
|
+ 'connect_good': 0, |
|
+ 'connect_renegotiate': 0, |
|
+ 'accept': 0, |
|
+ 'accept_good': 0, |
|
+ 'accept_renegotiate': 0, |
|
+ 'hits': 0, |
|
+ 'misses': 0, |
|
+ 'timeouts': 0, |
|
+ 'cache_full': 0, |
|
+ }) |
|
+ |
|
+ def test_set_default_verify_paths(self): |
|
+ # There's not much we can do to test that it acts as expected, |
|
+ # so just check it doesn't crash or raise an exception. |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.set_default_verify_paths() |
|
+ |
|
+ @unittest.skipUnless(ssl.HAS_ECDH, "ECDH disabled on this OpenSSL build") |
|
+ def test_set_ecdh_curve(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.set_ecdh_curve("prime256v1") |
|
+ ctx.set_ecdh_curve(b"prime256v1") |
|
+ self.assertRaises(TypeError, ctx.set_ecdh_curve) |
|
+ self.assertRaises(TypeError, ctx.set_ecdh_curve, None) |
|
+ self.assertRaises(ValueError, ctx.set_ecdh_curve, "foo") |
|
+ self.assertRaises(ValueError, ctx.set_ecdh_curve, b"foo") |
|
+ |
|
+ @needs_sni |
|
+ def test_sni_callback(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ |
|
+ # set_servername_callback expects a callable, or None |
|
+ self.assertRaises(TypeError, ctx.set_servername_callback) |
|
+ self.assertRaises(TypeError, ctx.set_servername_callback, 4) |
|
+ self.assertRaises(TypeError, ctx.set_servername_callback, "") |
|
+ self.assertRaises(TypeError, ctx.set_servername_callback, ctx) |
|
+ |
|
+ def dummycallback(sock, servername, ctx): |
|
+ pass |
|
+ ctx.set_servername_callback(None) |
|
+ ctx.set_servername_callback(dummycallback) |
|
+ |
|
+ @needs_sni |
|
+ def test_sni_callback_refcycle(self): |
|
+ # Reference cycles through the servername callback are detected |
|
+ # and cleared. |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ def dummycallback(sock, servername, ctx, cycle=ctx): |
|
+ pass |
|
+ ctx.set_servername_callback(dummycallback) |
|
+ wr = weakref.ref(ctx) |
|
+ del ctx, dummycallback |
|
+ gc.collect() |
|
+ self.assertIs(wr(), None) |
|
+ |
|
+ def test_cert_store_stats(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ self.assertEqual(ctx.cert_store_stats(), |
|
+ {'x509_ca': 0, 'crl': 0, 'x509': 0}) |
|
+ ctx.load_cert_chain(CERTFILE) |
|
+ self.assertEqual(ctx.cert_store_stats(), |
|
+ {'x509_ca': 0, 'crl': 0, 'x509': 0}) |
|
+ ctx.load_verify_locations(CERTFILE) |
|
+ self.assertEqual(ctx.cert_store_stats(), |
|
+ {'x509_ca': 0, 'crl': 0, 'x509': 1}) |
|
+ ctx.load_verify_locations(SVN_PYTHON_ORG_ROOT_CERT) |
|
+ self.assertEqual(ctx.cert_store_stats(), |
|
+ {'x509_ca': 1, 'crl': 0, 'x509': 2}) |
|
+ |
|
+ def test_get_ca_certs(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ self.assertEqual(ctx.get_ca_certs(), []) |
|
+ # CERTFILE is not flagged as X509v3 Basic Constraints: CA:TRUE |
|
+ ctx.load_verify_locations(CERTFILE) |
|
+ self.assertEqual(ctx.get_ca_certs(), []) |
|
+ # but SVN_PYTHON_ORG_ROOT_CERT is a CA cert |
|
+ ctx.load_verify_locations(SVN_PYTHON_ORG_ROOT_CERT) |
|
+ self.assertEqual(ctx.get_ca_certs(), |
|
+ [{'issuer': ((('organizationName', 'Root CA'),), |
|
+ (('organizationalUnitName', 'http://www.cacert.org'),), |
|
+ (('commonName', 'CA Cert Signing Authority'),), |
|
+ (('emailAddress', 'support@cacert.org'),)), |
|
+ 'notAfter': asn1time('Mar 29 12:29:49 2033 GMT'), |
|
+ 'notBefore': asn1time('Mar 30 12:29:49 2003 GMT'), |
|
+ 'serialNumber': '00', |
|
+ 'crlDistributionPoints': ('https://www.cacert.org/revoke.crl',), |
|
+ 'subject': ((('organizationName', 'Root CA'),), |
|
+ (('organizationalUnitName', 'http://www.cacert.org'),), |
|
+ (('commonName', 'CA Cert Signing Authority'),), |
|
+ (('emailAddress', 'support@cacert.org'),)), |
|
+ 'version': 3}]) |
|
+ |
|
+ with open(SVN_PYTHON_ORG_ROOT_CERT) as f: |
|
+ pem = f.read() |
|
+ der = ssl.PEM_cert_to_DER_cert(pem) |
|
+ self.assertEqual(ctx.get_ca_certs(True), [der]) |
|
|
|
+ def test_load_default_certs(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.load_default_certs() |
|
+ |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.load_default_certs(ssl.Purpose.SERVER_AUTH) |
|
+ ctx.load_default_certs() |
|
+ |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH) |
|
+ |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ self.assertRaises(TypeError, ctx.load_default_certs, None) |
|
+ self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH') |
|
+ |
|
+ def test_create_default_context(self): |
|
+ ctx = ssl.create_default_context() |
|
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) |
|
+ self.assertTrue(ctx.check_hostname) |
|
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
|
+ self.assertEqual( |
|
+ ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), |
|
+ getattr(ssl, "OP_NO_COMPRESSION", 0), |
|
+ ) |
|
+ |
|
+ with open(SIGNING_CA) as f: |
|
+ cadata = f.read().decode("ascii") |
|
+ ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH, |
|
+ cadata=cadata) |
|
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) |
|
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
|
+ self.assertEqual( |
|
+ ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), |
|
+ getattr(ssl, "OP_NO_COMPRESSION", 0), |
|
+ ) |
|
+ |
|
+ ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) |
|
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) |
|
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
|
+ self.assertEqual( |
|
+ ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), |
|
+ getattr(ssl, "OP_NO_COMPRESSION", 0), |
|
+ ) |
|
+ self.assertEqual( |
|
+ ctx.options & getattr(ssl, "OP_SINGLE_DH_USE", 0), |
|
+ getattr(ssl, "OP_SINGLE_DH_USE", 0), |
|
+ ) |
|
+ self.assertEqual( |
|
+ ctx.options & getattr(ssl, "OP_SINGLE_ECDH_USE", 0), |
|
+ getattr(ssl, "OP_SINGLE_ECDH_USE", 0), |
|
+ ) |
|
+ |
|
+ def test__create_stdlib_context(self): |
|
+ ctx = ssl._create_stdlib_context() |
|
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) |
|
+ self.assertFalse(ctx.check_hostname) |
|
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
|
+ |
|
+ ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1) |
|
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) |
|
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
|
+ |
|
+ ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1, |
|
+ cert_reqs=ssl.CERT_REQUIRED, |
|
+ check_hostname=True) |
|
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) |
|
+ self.assertTrue(ctx.check_hostname) |
|
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
|
+ |
|
+ ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH) |
|
+ self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) |
|
+ self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) |
|
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
|
+ |
|
+ def test_check_hostname(self): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ self.assertFalse(ctx.check_hostname) |
|
+ |
|
+ # Requires CERT_REQUIRED or CERT_OPTIONAL |
|
+ with self.assertRaises(ValueError): |
|
+ ctx.check_hostname = True |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ self.assertFalse(ctx.check_hostname) |
|
+ ctx.check_hostname = True |
|
+ self.assertTrue(ctx.check_hostname) |
|
+ |
|
+ ctx.verify_mode = ssl.CERT_OPTIONAL |
|
+ ctx.check_hostname = True |
|
+ self.assertTrue(ctx.check_hostname) |
|
+ |
|
+ # Cannot set CERT_NONE with check_hostname enabled |
|
+ with self.assertRaises(ValueError): |
|
+ ctx.verify_mode = ssl.CERT_NONE |
|
+ ctx.check_hostname = False |
|
+ self.assertFalse(ctx.check_hostname) |
|
+ |
|
+ |
|
+class SSLErrorTests(unittest.TestCase): |
|
+ |
|
+ def test_str(self): |
|
+ # The str() of a SSLError doesn't include the errno |
|
+ e = ssl.SSLError(1, "foo") |
|
+ self.assertEqual(str(e), "foo") |
|
+ self.assertEqual(e.errno, 1) |
|
+ # Same for a subclass |
|
+ e = ssl.SSLZeroReturnError(1, "foo") |
|
+ self.assertEqual(str(e), "foo") |
|
+ self.assertEqual(e.errno, 1) |
|
+ |
|
+ def test_lib_reason(self): |
|
+ # Test the library and reason attributes |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ with self.assertRaises(ssl.SSLError) as cm: |
|
+ ctx.load_dh_params(CERTFILE) |
|
+ self.assertEqual(cm.exception.library, 'PEM') |
|
+ self.assertEqual(cm.exception.reason, 'NO_START_LINE') |
|
+ s = str(cm.exception) |
|
+ self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s) |
|
+ |
|
+ def test_subclass(self): |
|
+ # Check that the appropriate SSLError subclass is raised |
|
+ # (this only tests one of them) |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ with closing(socket.socket()) as s: |
|
+ s.bind(("127.0.0.1", 0)) |
|
+ s.listen(5) |
|
+ c = socket.socket() |
|
+ c.connect(s.getsockname()) |
|
+ c.setblocking(False) |
|
+ with closing(ctx.wrap_socket(c, False, do_handshake_on_connect=False)) as c: |
|
+ with self.assertRaises(ssl.SSLWantReadError) as cm: |
|
+ c.do_handshake() |
|
+ s = str(cm.exception) |
|
+ self.assertTrue(s.startswith("The operation did not complete (read)"), s) |
|
+ # For compatibility |
|
+ self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ) |
|
+ |
|
+ |
|
+ |
|
|
|
class NetworkedTests(unittest.TestCase): |
|
|
|
def test_connect(self): |
|
- with test_support.transient_internet("svn.python.org"): |
|
+ with support.transient_internet("svn.python.org"): |
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
cert_reqs=ssl.CERT_NONE) |
|
- s.connect(("svn.python.org", 443)) |
|
- c = s.getpeercert() |
|
- if c: |
|
- self.fail("Peer cert %s shouldn't be here!") |
|
- s.close() |
|
- |
|
- # this should fail because we have no verification certs |
|
- s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
- cert_reqs=ssl.CERT_REQUIRED) |
|
try: |
|
s.connect(("svn.python.org", 443)) |
|
- except ssl.SSLError: |
|
- pass |
|
+ self.assertEqual({}, s.getpeercert()) |
|
finally: |
|
s.close() |
|
|
|
+ # this should fail because we have no verification certs |
|
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
+ cert_reqs=ssl.CERT_REQUIRED) |
|
+ self.assertRaisesRegexp(ssl.SSLError, "certificate verify failed", |
|
+ s.connect, ("svn.python.org", 443)) |
|
+ s.close() |
|
+ |
|
# this should succeed because we specify the root cert |
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
cert_reqs=ssl.CERT_REQUIRED, |
|
ca_certs=SVN_PYTHON_ORG_ROOT_CERT) |
|
try: |
|
s.connect(("svn.python.org", 443)) |
|
+ self.assertTrue(s.getpeercert()) |
|
finally: |
|
s.close() |
|
|
|
def test_connect_ex(self): |
|
# Issue #11326: check connect_ex() implementation |
|
- with test_support.transient_internet("svn.python.org"): |
|
+ with support.transient_internet("svn.python.org"): |
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
cert_reqs=ssl.CERT_REQUIRED, |
|
ca_certs=SVN_PYTHON_ORG_ROOT_CERT) |
|
@@ -272,7 +1206,7 @@ class NetworkedTests(unittest.TestCase): |
|
def test_non_blocking_connect_ex(self): |
|
# Issue #11326: non-blocking connect_ex() should allow handshake |
|
# to proceed after the socket gets ready. |
|
- with test_support.transient_internet("svn.python.org"): |
|
+ with support.transient_internet("svn.python.org"): |
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
cert_reqs=ssl.CERT_REQUIRED, |
|
ca_certs=SVN_PYTHON_ORG_ROOT_CERT, |
|
@@ -289,13 +1223,10 @@ class NetworkedTests(unittest.TestCase): |
|
try: |
|
s.do_handshake() |
|
break |
|
- except ssl.SSLError as err: |
|
- if err.args[0] == ssl.SSL_ERROR_WANT_READ: |
|
- select.select([s], [], [], 5.0) |
|
- elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: |
|
- select.select([], [s], [], 5.0) |
|
- else: |
|
- raise |
|
+ except ssl.SSLWantReadError: |
|
+ select.select([s], [], [], 5.0) |
|
+ except ssl.SSLWantWriteError: |
|
+ select.select([], [s], [], 5.0) |
|
# SSL established |
|
self.assertTrue(s.getpeercert()) |
|
finally: |
|
@@ -304,7 +1235,7 @@ class NetworkedTests(unittest.TestCase): |
|
def test_timeout_connect_ex(self): |
|
# Issue #12065: on a timeout, connect_ex() should return the original |
|
# errno (mimicking the behaviour of non-SSL sockets). |
|
- with test_support.transient_internet("svn.python.org"): |
|
+ with support.transient_internet("svn.python.org"): |
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
cert_reqs=ssl.CERT_REQUIRED, |
|
ca_certs=SVN_PYTHON_ORG_ROOT_CERT, |
|
@@ -319,22 +1250,109 @@ class NetworkedTests(unittest.TestCase): |
|
s.close() |
|
|
|
def test_connect_ex_error(self): |
|
- with test_support.transient_internet("svn.python.org"): |
|
+ with support.transient_internet("svn.python.org"): |
|
s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
cert_reqs=ssl.CERT_REQUIRED, |
|
ca_certs=SVN_PYTHON_ORG_ROOT_CERT) |
|
try: |
|
- self.assertEqual(errno.ECONNREFUSED, |
|
- s.connect_ex(("svn.python.org", 444))) |
|
+ rc = s.connect_ex(("svn.python.org", 444)) |
|
+ # Issue #19919: Windows machines or VMs hosted on Windows |
|
+ # machines sometimes return EWOULDBLOCK. |
|
+ self.assertIn(rc, (errno.ECONNREFUSED, errno.EWOULDBLOCK)) |
|
+ finally: |
|
+ s.close() |
|
+ |
|
+ def test_connect_with_context(self): |
|
+ with support.transient_internet("svn.python.org"): |
|
+ # Same as test_connect, but with a separately created context |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) |
|
+ s.connect(("svn.python.org", 443)) |
|
+ try: |
|
+ self.assertEqual({}, s.getpeercert()) |
|
finally: |
|
s.close() |
|
+ # Same with a server hostname |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET), |
|
+ server_hostname="svn.python.org") |
|
+ if ssl.HAS_SNI: |
|
+ s.connect(("svn.python.org", 443)) |
|
+ s.close() |
|
+ else: |
|
+ self.assertRaises(ValueError, s.connect, ("svn.python.org", 443)) |
|
+ # This should fail because we have no verification certs |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) |
|
+ self.assertRaisesRegexp(ssl.SSLError, "certificate verify failed", |
|
+ s.connect, ("svn.python.org", 443)) |
|
+ s.close() |
|
+ # This should succeed because we specify the root cert |
|
+ ctx.load_verify_locations(SVN_PYTHON_ORG_ROOT_CERT) |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) |
|
+ s.connect(("svn.python.org", 443)) |
|
+ try: |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert) |
|
+ finally: |
|
+ s.close() |
|
+ |
|
+ def test_connect_capath(self): |
|
+ # Verify server certificates using the `capath` argument |
|
+ # NOTE: the subject hashing algorithm has been changed between |
|
+ # OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must |
|
+ # contain both versions of each certificate (same content, different |
|
+ # filename) for this test to be portable across OpenSSL releases. |
|
+ with support.transient_internet("svn.python.org"): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ ctx.load_verify_locations(capath=CAPATH) |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) |
|
+ s.connect(("svn.python.org", 443)) |
|
+ try: |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert) |
|
+ finally: |
|
+ s.close() |
|
+ # Same with a bytes `capath` argument |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ ctx.load_verify_locations(capath=BYTES_CAPATH) |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) |
|
+ s.connect(("svn.python.org", 443)) |
|
+ try: |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert) |
|
+ finally: |
|
+ s.close() |
|
+ |
|
+ def test_connect_cadata(self): |
|
+ with open(CAFILE_CACERT) as f: |
|
+ pem = f.read().decode('ascii') |
|
+ der = ssl.PEM_cert_to_DER_cert(pem) |
|
+ with support.transient_internet("svn.python.org"): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ ctx.load_verify_locations(cadata=pem) |
|
+ with closing(ctx.wrap_socket(socket.socket(socket.AF_INET))) as s: |
|
+ s.connect(("svn.python.org", 443)) |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert) |
|
+ |
|
+ # same with DER |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ ctx.load_verify_locations(cadata=der) |
|
+ with closing(ctx.wrap_socket(socket.socket(socket.AF_INET))) as s: |
|
+ s.connect(("svn.python.org", 443)) |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert) |
|
|
|
@unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows") |
|
def test_makefile_close(self): |
|
# Issue #5238: creating a file-like object with makefile() shouldn't |
|
# delay closing the underlying "real socket" (here tested with its |
|
# file descriptor, hence skipping the test under Windows). |
|
- with test_support.transient_internet("svn.python.org"): |
|
+ with support.transient_internet("svn.python.org"): |
|
ss = ssl.wrap_socket(socket.socket(socket.AF_INET)) |
|
ss.connect(("svn.python.org", 443)) |
|
fd = ss.fileno() |
|
@@ -350,7 +1368,7 @@ class NetworkedTests(unittest.TestCase): |
|
self.assertEqual(e.exception.errno, errno.EBADF) |
|
|
|
def test_non_blocking_handshake(self): |
|
- with test_support.transient_internet("svn.python.org"): |
|
+ with support.transient_internet("svn.python.org"): |
|
s = socket.socket(socket.AF_INET) |
|
s.connect(("svn.python.org", 443)) |
|
s.setblocking(False) |
|
@@ -363,36 +1381,57 @@ class NetworkedTests(unittest.TestCase): |
|
count += 1 |
|
s.do_handshake() |
|
break |
|
- except ssl.SSLError, err: |
|
- if err.args[0] == ssl.SSL_ERROR_WANT_READ: |
|
- select.select([s], [], []) |
|
- elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: |
|
- select.select([], [s], []) |
|
- else: |
|
- raise |
|
+ except ssl.SSLWantReadError: |
|
+ select.select([s], [], []) |
|
+ except ssl.SSLWantWriteError: |
|
+ select.select([], [s], []) |
|
s.close() |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count) |
|
|
|
def test_get_server_certificate(self): |
|
- with test_support.transient_internet("svn.python.org"): |
|
- pem = ssl.get_server_certificate(("svn.python.org", 443)) |
|
- if not pem: |
|
- self.fail("No server certificate on svn.python.org:443!") |
|
+ def _test_get_server_certificate(host, port, cert=None): |
|
+ with support.transient_internet(host): |
|
+ pem = ssl.get_server_certificate((host, port)) |
|
+ if not pem: |
|
+ self.fail("No server certificate on %s:%s!" % (host, port)) |
|
|
|
- try: |
|
- pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE) |
|
- except ssl.SSLError: |
|
- #should fail |
|
- pass |
|
- else: |
|
- self.fail("Got server certificate %s for svn.python.org!" % pem) |
|
+ try: |
|
+ pem = ssl.get_server_certificate((host, port), |
|
+ ca_certs=CERTFILE) |
|
+ except ssl.SSLError as x: |
|
+ #should fail |
|
+ if support.verbose: |
|
+ sys.stdout.write("%s\n" % x) |
|
+ else: |
|
+ self.fail("Got server certificate %s for %s:%s!" % (pem, host, port)) |
|
+ pem = ssl.get_server_certificate((host, port), |
|
+ ca_certs=cert) |
|
+ if not pem: |
|
+ self.fail("No server certificate on %s:%s!" % (host, port)) |
|
+ if support.verbose: |
|
+ sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem)) |
|
+ |
|
+ _test_get_server_certificate('svn.python.org', 443, SVN_PYTHON_ORG_ROOT_CERT) |
|
+ if support.IPV6_ENABLED: |
|
+ _test_get_server_certificate('ipv6.google.com', 443) |
|
+ |
|
+ def test_ciphers(self): |
|
+ remote = ("svn.python.org", 443) |
|
+ with support.transient_internet(remote[0]): |
|
+ with closing(ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
+ cert_reqs=ssl.CERT_NONE, ciphers="ALL")) as s: |
|
+ s.connect(remote) |
|
+ with closing(ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
+ cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")) as s: |
|
+ s.connect(remote) |
|
+ # Error checking can happen at instantiation or when connecting |
|
+ with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): |
|
+ with closing(socket.socket(socket.AF_INET)) as sock: |
|
+ s = ssl.wrap_socket(sock, |
|
+ cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") |
|
+ s.connect(remote) |
|
|
|
- pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT) |
|
- if not pem: |
|
- self.fail("No server certificate on svn.python.org:443!") |
|
- if test_support.verbose: |
|
- sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem) |
|
|
|
def test_algorithms(self): |
|
# Issue #8484: all algorithms should be available when verifying a |
|
@@ -400,17 +1439,21 @@ class NetworkedTests(unittest.TestCase): |
|
# SHA256 was added in OpenSSL 0.9.8 |
|
if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15): |
|
self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION) |
|
- self.skipTest("remote host needs SNI, only available on Python 3.2+") |
|
- # NOTE: https://sha2.hboeck.de is another possible test host |
|
+ # sha256.tbs-internet.com needs SNI to use the correct certificate |
|
+ if not ssl.HAS_SNI: |
|
+ self.skipTest("SNI needed for this test") |
|
+ # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host) |
|
remote = ("sha256.tbs-internet.com", 443) |
|
sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") |
|
- with test_support.transient_internet("sha256.tbs-internet.com"): |
|
- s = ssl.wrap_socket(socket.socket(socket.AF_INET), |
|
- cert_reqs=ssl.CERT_REQUIRED, |
|
- ca_certs=sha256_cert,) |
|
+ with support.transient_internet("sha256.tbs-internet.com"): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ ctx.load_verify_locations(sha256_cert) |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET), |
|
+ server_hostname="sha256.tbs-internet.com") |
|
try: |
|
s.connect(remote) |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\nCipher with %r is %r\n" % |
|
(remote, s.cipher())) |
|
sys.stdout.write("Certificate is:\n%s\n" % |
|
@@ -418,6 +1461,36 @@ class NetworkedTests(unittest.TestCase): |
|
finally: |
|
s.close() |
|
|
|
+ def test_get_ca_certs_capath(self): |
|
+ # capath certs are loaded on request |
|
+ with support.transient_internet("svn.python.org"): |
|
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ ctx.verify_mode = ssl.CERT_REQUIRED |
|
+ ctx.load_verify_locations(capath=CAPATH) |
|
+ self.assertEqual(ctx.get_ca_certs(), []) |
|
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET)) |
|
+ s.connect(("svn.python.org", 443)) |
|
+ try: |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert) |
|
+ finally: |
|
+ s.close() |
|
+ self.assertEqual(len(ctx.get_ca_certs()), 1) |
|
+ |
|
+ @needs_sni |
|
+ def test_context_setget(self): |
|
+ # Check that the context of a connected socket can be replaced. |
|
+ with support.transient_internet("svn.python.org"): |
|
+ ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ ctx2 = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ s = socket.socket(socket.AF_INET) |
|
+ with closing(ctx1.wrap_socket(s)) as ss: |
|
+ ss.connect(("svn.python.org", 443)) |
|
+ self.assertIs(ss.context, ctx1) |
|
+ self.assertIs(ss._sslobj.context, ctx1) |
|
+ ss.context = ctx2 |
|
+ self.assertIs(ss.context, ctx2) |
|
+ self.assertIs(ss._sslobj.context, ctx2) |
|
|
|
try: |
|
import threading |
|
@@ -426,6 +1499,8 @@ except ImportError: |
|
else: |
|
_have_threads = True |
|
|
|
+ from test.ssl_servers import make_https_server |
|
+ |
|
class ThreadedEchoServer(threading.Thread): |
|
|
|
class ConnectionHandler(threading.Thread): |
|
@@ -434,48 +1509,51 @@ else: |
|
with and without the SSL wrapper around the socket connection, so |
|
that we can test the STARTTLS functionality.""" |
|
|
|
- def __init__(self, server, connsock): |
|
+ def __init__(self, server, connsock, addr): |
|
self.server = server |
|
self.running = False |
|
self.sock = connsock |
|
+ self.addr = addr |
|
self.sock.setblocking(1) |
|
self.sslconn = None |
|
threading.Thread.__init__(self) |
|
self.daemon = True |
|
|
|
- def show_conn_details(self): |
|
- if self.server.certreqs == ssl.CERT_REQUIRED: |
|
- cert = self.sslconn.getpeercert() |
|
- if test_support.verbose and self.server.chatty: |
|
- sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n") |
|
- cert_binary = self.sslconn.getpeercert(True) |
|
- if test_support.verbose and self.server.chatty: |
|
- sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n") |
|
- cipher = self.sslconn.cipher() |
|
- if test_support.verbose and self.server.chatty: |
|
- sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n") |
|
- |
|
def wrap_conn(self): |
|
try: |
|
- self.sslconn = ssl.wrap_socket(self.sock, server_side=True, |
|
- certfile=self.server.certificate, |
|
- ssl_version=self.server.protocol, |
|
- ca_certs=self.server.cacerts, |
|
- cert_reqs=self.server.certreqs, |
|
- ciphers=self.server.ciphers) |
|
- except ssl.SSLError as e: |
|
+ self.sslconn = self.server.context.wrap_socket( |
|
+ self.sock, server_side=True) |
|
+ self.server.selected_protocols.append(self.sslconn.selected_npn_protocol()) |
|
+ except socket.error as e: |
|
+ # We treat ConnectionResetError as though it were an |
|
+ # SSLError - OpenSSL on Ubuntu abruptly closes the |
|
+ # connection when asked to use an unsupported protocol. |
|
+ # |
|
# XXX Various errors can have happened here, for example |
|
# a mismatching protocol version, an invalid certificate, |
|
# or a low-level bug. This should be made more discriminating. |
|
+ if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET: |
|
+ raise |
|
self.server.conn_errors.append(e) |
|
if self.server.chatty: |
|
- handle_error("\n server: bad connection attempt from " + |
|
- str(self.sock.getpeername()) + ":\n") |
|
- self.close() |
|
+ handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n") |
|
self.running = False |
|
self.server.stop() |
|
+ self.close() |
|
return False |
|
else: |
|
+ if self.server.context.verify_mode == ssl.CERT_REQUIRED: |
|
+ cert = self.sslconn.getpeercert() |
|
+ if support.verbose and self.server.chatty: |
|
+ sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n") |
|
+ cert_binary = self.sslconn.getpeercert(True) |
|
+ if support.verbose and self.server.chatty: |
|
+ sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n") |
|
+ cipher = self.sslconn.cipher() |
|
+ if support.verbose and self.server.chatty: |
|
+ sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n") |
|
+ sys.stdout.write(" server: selected protocol is now " |
|
+ + str(self.sslconn.selected_npn_protocol()) + "\n") |
|
return True |
|
|
|
def read(self): |
|
@@ -494,48 +1572,53 @@ else: |
|
if self.sslconn: |
|
self.sslconn.close() |
|
else: |
|
- self.sock._sock.close() |
|
+ self.sock.close() |
|
|
|
def run(self): |
|
self.running = True |
|
if not self.server.starttls_server: |
|
- if isinstance(self.sock, ssl.SSLSocket): |
|
- self.sslconn = self.sock |
|
- elif not self.wrap_conn(): |
|
+ if not self.wrap_conn(): |
|
return |
|
- self.show_conn_details() |
|
while self.running: |
|
try: |
|
msg = self.read() |
|
- if not msg: |
|
+ stripped = msg.strip() |
|
+ if not stripped: |
|
# eof, so quit this handler |
|
self.running = False |
|
self.close() |
|
- elif msg.strip() == 'over': |
|
- if test_support.verbose and self.server.connectionchatty: |
|
+ elif stripped == b'over': |
|
+ if support.verbose and self.server.connectionchatty: |
|
sys.stdout.write(" server: client closed connection\n") |
|
self.close() |
|
return |
|
- elif self.server.starttls_server and msg.strip() == 'STARTTLS': |
|
- if test_support.verbose and self.server.connectionchatty: |
|
+ elif (self.server.starttls_server and |
|
+ stripped == b'STARTTLS'): |
|
+ if support.verbose and self.server.connectionchatty: |
|
sys.stdout.write(" server: read STARTTLS from client, sending OK...\n") |
|
- self.write("OK\n") |
|
+ self.write(b"OK\n") |
|
if not self.wrap_conn(): |
|
return |
|
- elif self.server.starttls_server and self.sslconn and msg.strip() == 'ENDTLS': |
|
- if test_support.verbose and self.server.connectionchatty: |
|
+ elif (self.server.starttls_server and self.sslconn |
|
+ and stripped == b'ENDTLS'): |
|
+ if support.verbose and self.server.connectionchatty: |
|
sys.stdout.write(" server: read ENDTLS from client, sending OK...\n") |
|
- self.write("OK\n") |
|
- self.sslconn.unwrap() |
|
+ self.write(b"OK\n") |
|
+ self.sock = self.sslconn.unwrap() |
|
self.sslconn = None |
|
- if test_support.verbose and self.server.connectionchatty: |
|
+ if support.verbose and self.server.connectionchatty: |
|
sys.stdout.write(" server: connection is now unencrypted...\n") |
|
+ elif stripped == b'CB tls-unique': |
|
+ if support.verbose and self.server.connectionchatty: |
|
+ sys.stdout.write(" server: read CB tls-unique from client, sending our CB data...\n") |
|
+ data = self.sslconn.get_channel_binding("tls-unique") |
|
+ self.write(repr(data).encode("us-ascii") + b"\n") |
|
else: |
|
- if (test_support.verbose and |
|
+ if (support.verbose and |
|
self.server.connectionchatty): |
|
ctype = (self.sslconn and "encrypted") or "unencrypted" |
|
- sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n" |
|
- % (repr(msg), ctype, repr(msg.lower()), ctype)) |
|
+ sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n" |
|
+ % (msg, ctype, msg.lower(), ctype)) |
|
self.write(msg.lower()) |
|
except ssl.SSLError: |
|
if self.server.chatty: |
|
@@ -546,36 +1629,34 @@ else: |
|
# harness, we want to stop the server |
|
self.server.stop() |
|
|
|
- def __init__(self, certificate, ssl_version=None, |
|
+ def __init__(self, certificate=None, ssl_version=None, |
|
certreqs=None, cacerts=None, |
|
chatty=True, connectionchatty=False, starttls_server=False, |
|
- wrap_accepting_socket=False, ciphers=None): |
|
- |
|
- if ssl_version is None: |
|
- ssl_version = ssl.PROTOCOL_TLSv1 |
|
- if certreqs is None: |
|
- certreqs = ssl.CERT_NONE |
|
- self.certificate = certificate |
|
- self.protocol = ssl_version |
|
- self.certreqs = certreqs |
|
- self.cacerts = cacerts |
|
- self.ciphers = ciphers |
|
+ npn_protocols=None, ciphers=None, context=None): |
|
+ if context: |
|
+ self.context = context |
|
+ else: |
|
+ self.context = ssl.SSLContext(ssl_version |
|
+ if ssl_version is not None |
|
+ else ssl.PROTOCOL_TLSv1) |
|
+ self.context.verify_mode = (certreqs if certreqs is not None |
|
+ else ssl.CERT_NONE) |
|
+ if cacerts: |
|
+ self.context.load_verify_locations(cacerts) |
|
+ if certificate: |
|
+ self.context.load_cert_chain(certificate) |
|
+ if npn_protocols: |
|
+ self.context.set_npn_protocols(npn_protocols) |
|
+ if ciphers: |
|
+ self.context.set_ciphers(ciphers) |
|
self.chatty = chatty |
|
self.connectionchatty = connectionchatty |
|
self.starttls_server = starttls_server |
|
self.sock = socket.socket() |
|
+ self.port = support.bind_port(self.sock) |
|
self.flag = None |
|
- if wrap_accepting_socket: |
|
- self.sock = ssl.wrap_socket(self.sock, server_side=True, |
|
- certfile=self.certificate, |
|
- cert_reqs = self.certreqs, |
|
- ca_certs = self.cacerts, |
|
- ssl_version = self.protocol, |
|
- ciphers = self.ciphers) |
|
- if test_support.verbose and self.chatty: |
|
- sys.stdout.write(' server: wrapped server socket as %s\n' % str(self.sock)) |
|
- self.port = test_support.bind_port(self.sock) |
|
self.active = False |
|
+ self.selected_protocols = [] |
|
self.conn_errors = [] |
|
threading.Thread.__init__(self) |
|
self.daemon = True |
|
@@ -603,10 +1684,10 @@ else: |
|
while self.active: |
|
try: |
|
newconn, connaddr = self.sock.accept() |
|
- if test_support.verbose and self.chatty: |
|
+ if support.verbose and self.chatty: |
|
sys.stdout.write(' server: new connection from ' |
|
- + str(connaddr) + '\n') |
|
- handler = self.ConnectionHandler(self, newconn) |
|
+ + repr(connaddr) + '\n') |
|
+ handler = self.ConnectionHandler(self, newconn, connaddr) |
|
handler.start() |
|
handler.join() |
|
except socket.timeout: |
|
@@ -625,11 +1706,12 @@ else: |
|
class ConnectionHandler(asyncore.dispatcher_with_send): |
|
|
|
def __init__(self, conn, certfile): |
|
- asyncore.dispatcher_with_send.__init__(self, conn) |
|
self.socket = ssl.wrap_socket(conn, server_side=True, |
|
certfile=certfile, |
|
do_handshake_on_connect=False) |
|
+ asyncore.dispatcher_with_send.__init__(self, self.socket) |
|
self._ssl_accepting = True |
|
+ self._do_ssl_handshake() |
|
|
|
def readable(self): |
|
if isinstance(self.socket, ssl.SSLSocket): |
|
@@ -640,12 +1722,11 @@ else: |
|
def _do_ssl_handshake(self): |
|
try: |
|
self.socket.do_handshake() |
|
- except ssl.SSLError, err: |
|
- if err.args[0] in (ssl.SSL_ERROR_WANT_READ, |
|
- ssl.SSL_ERROR_WANT_WRITE): |
|
- return |
|
- elif err.args[0] == ssl.SSL_ERROR_EOF: |
|
- return self.handle_close() |
|
+ except (ssl.SSLWantReadError, ssl.SSLWantWriteError): |
|
+ return |
|
+ except ssl.SSLEOFError: |
|
+ return self.handle_close() |
|
+ except ssl.SSLError: |
|
raise |
|
except socket.error, err: |
|
if err.args[0] == errno.ECONNABORTED: |
|
@@ -658,12 +1739,16 @@ else: |
|
self._do_ssl_handshake() |
|
else: |
|
data = self.recv(1024) |
|
- if data and data.strip() != 'over': |
|
+ if support.verbose: |
|
+ sys.stdout.write(" server: read %s from client\n" % repr(data)) |
|
+ if not data: |
|
+ self.close() |
|
+ else: |
|
self.send(data.lower()) |
|
|
|
def handle_close(self): |
|
self.close() |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write(" server: closed connection %s\n" % self.socket) |
|
|
|
def handle_error(self): |
|
@@ -671,14 +1756,14 @@ else: |
|
|
|
def __init__(self, certfile): |
|
self.certfile = certfile |
|
- asyncore.dispatcher.__init__(self) |
|
- self.create_socket(socket.AF_INET, socket.SOCK_STREAM) |
|
- self.port = test_support.bind_port(self.socket) |
|
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
+ self.port = support.bind_port(sock, '') |
|
+ asyncore.dispatcher.__init__(self, sock) |
|
self.listen(5) |
|
|
|
def handle_accept(self): |
|
sock_obj, addr = self.accept() |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write(" server: new connection from %s:%s\n" %addr) |
|
self.ConnectionHandler(sock_obj, self.certfile) |
|
|
|
@@ -702,13 +1787,13 @@ else: |
|
return self |
|
|
|
def __exit__(self, *args): |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write(" cleanup: stopping server.\n") |
|
self.stop() |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write(" cleanup: joining server thread.\n") |
|
self.join() |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write(" cleanup: successfully joined.\n") |
|
|
|
def start(self, flag=None): |
|
@@ -720,103 +1805,15 @@ else: |
|
if self.flag: |
|
self.flag.set() |
|
while self.active: |
|
- asyncore.loop(0.05) |
|
+ try: |
|
+ asyncore.loop(1) |
|
+ except: |
|
+ pass |
|
|
|
def stop(self): |
|
self.active = False |
|
self.server.close() |
|
|
|
- class SocketServerHTTPSServer(threading.Thread): |
|
- |
|
- class HTTPSServer(HTTPServer): |
|
- |
|
- def __init__(self, server_address, RequestHandlerClass, certfile): |
|
- HTTPServer.__init__(self, server_address, RequestHandlerClass) |
|
- # we assume the certfile contains both private key and certificate |
|
- self.certfile = certfile |
|
- self.allow_reuse_address = True |
|
- |
|
- def __str__(self): |
|
- return ('<%s %s:%s>' % |
|
- (self.__class__.__name__, |
|
- self.server_name, |
|
- self.server_port)) |
|
- |
|
- def get_request(self): |
|
- # override this to wrap socket with SSL |
|
- sock, addr = self.socket.accept() |
|
- sslconn = ssl.wrap_socket(sock, server_side=True, |
|
- certfile=self.certfile) |
|
- return sslconn, addr |
|
- |
|
- class RootedHTTPRequestHandler(SimpleHTTPRequestHandler): |
|
- # need to override translate_path to get a known root, |
|
- # instead of using os.curdir, since the test could be |
|
- # run from anywhere |
|
- |
|
- server_version = "TestHTTPS/1.0" |
|
- |
|
- root = None |
|
- |
|
- def translate_path(self, path): |
|
- """Translate a /-separated PATH to the local filename syntax. |
|
- |
|
- Components that mean special things to the local file system |
|
- (e.g. drive or directory names) are ignored. (XXX They should |
|
- probably be diagnosed.) |
|
- |
|
- """ |
|
- # abandon query parameters |
|
- path = urlparse.urlparse(path)[2] |
|
- path = os.path.normpath(urllib.unquote(path)) |
|
- words = path.split('/') |
|
- words = filter(None, words) |
|
- path = self.root |
|
- for word in words: |
|
- drive, word = os.path.splitdrive(word) |
|
- head, word = os.path.split(word) |
|
- if word in self.root: continue |
|
- path = os.path.join(path, word) |
|
- return path |
|
- |
|
- def log_message(self, format, *args): |
|
- |
|
- # we override this to suppress logging unless "verbose" |
|
- |
|
- if test_support.verbose: |
|
- sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" % |
|
- (self.server.server_address, |
|
- self.server.server_port, |
|
- self.request.cipher(), |
|
- self.log_date_time_string(), |
|
- format%args)) |
|
- |
|
- |
|
- def __init__(self, certfile): |
|
- self.flag = None |
|
- self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0] |
|
- self.server = self.HTTPSServer( |
|
- (HOST, 0), self.RootedHTTPRequestHandler, certfile) |
|
- self.port = self.server.server_port |
|
- threading.Thread.__init__(self) |
|
- self.daemon = True |
|
- |
|
- def __str__(self): |
|
- return "<%s %s>" % (self.__class__.__name__, self.server) |
|
- |
|
- def start(self, flag=None): |
|
- self.flag = flag |
|
- threading.Thread.start(self) |
|
- |
|
- def run(self): |
|
- if self.flag: |
|
- self.flag.set() |
|
- self.server.serve_forever(0.05) |
|
- |
|
- def stop(self): |
|
- self.server.shutdown() |
|
- |
|
- |
|
def bad_cert_test(certfile): |
|
""" |
|
Launch a server with CERT_REQUIRED, and check that trying to |
|
@@ -824,74 +1821,74 @@ else: |
|
""" |
|
server = ThreadedEchoServer(CERTFILE, |
|
certreqs=ssl.CERT_REQUIRED, |
|
- cacerts=CERTFILE, chatty=False) |
|
+ cacerts=CERTFILE, chatty=False, |
|
+ connectionchatty=False) |
|
with server: |
|
try: |
|
- s = ssl.wrap_socket(socket.socket(), |
|
- certfile=certfile, |
|
- ssl_version=ssl.PROTOCOL_TLSv1) |
|
- s.connect((HOST, server.port)) |
|
- except ssl.SSLError, x: |
|
- if test_support.verbose: |
|
- sys.stdout.write("\nSSLError is %s\n" % x[1]) |
|
- except socket.error, x: |
|
- if test_support.verbose: |
|
- sys.stdout.write("\nsocket.error is %s\n" % x[1]) |
|
+ with closing(socket.socket()) as sock: |
|
+ s = ssl.wrap_socket(sock, |
|
+ certfile=certfile, |
|
+ ssl_version=ssl.PROTOCOL_TLSv1) |
|
+ s.connect((HOST, server.port)) |
|
+ except ssl.SSLError as x: |
|
+ if support.verbose: |
|
+ sys.stdout.write("\nSSLError is %s\n" % x.args[1]) |
|
+ except OSError as x: |
|
+ if support.verbose: |
|
+ sys.stdout.write("\nOSError is %s\n" % x.args[1]) |
|
+ except OSError as x: |
|
+ if x.errno != errno.ENOENT: |
|
+ raise |
|
+ if support.verbose: |
|
+ sys.stdout.write("\OSError is %s\n" % str(x)) |
|
else: |
|
raise AssertionError("Use of invalid cert should have failed!") |
|
|
|
- def server_params_test(certfile, protocol, certreqs, cacertsfile, |
|
- client_certfile, client_protocol=None, indata="FOO\n", |
|
- ciphers=None, chatty=True, connectionchatty=False, |
|
- wrap_accepting_socket=False): |
|
+ def server_params_test(client_context, server_context, indata=b"FOO\n", |
|
+ chatty=True, connectionchatty=False, sni_name=None): |
|
""" |
|
Launch a server, connect a client to it and try various reads |
|
and writes. |
|
""" |
|
- server = ThreadedEchoServer(certfile, |
|
- certreqs=certreqs, |
|
- ssl_version=protocol, |
|
- cacerts=cacertsfile, |
|
- ciphers=ciphers, |
|
+ stats = {} |
|
+ server = ThreadedEchoServer(context=server_context, |
|
chatty=chatty, |
|
- connectionchatty=connectionchatty, |
|
- wrap_accepting_socket=wrap_accepting_socket) |
|
+ connectionchatty=False) |
|
with server: |
|
- # try to connect |
|
- if client_protocol is None: |
|
- client_protocol = protocol |
|
- s = ssl.wrap_socket(socket.socket(), |
|
- certfile=client_certfile, |
|
- ca_certs=cacertsfile, |
|
- ciphers=ciphers, |
|
- cert_reqs=certreqs, |
|
- ssl_version=client_protocol) |
|
- s.connect((HOST, server.port)) |
|
- for arg in [indata, bytearray(indata), memoryview(indata)]: |
|
- if connectionchatty: |
|
- if test_support.verbose: |
|
- sys.stdout.write( |
|
- " client: sending %s...\n" % (repr(arg))) |
|
- s.write(arg) |
|
- outdata = s.read() |
|
+ with closing(client_context.wrap_socket(socket.socket(), |
|
+ server_hostname=sni_name)) as s: |
|
+ s.connect((HOST, server.port)) |
|
+ for arg in [indata, bytearray(indata), memoryview(indata)]: |
|
+ if connectionchatty: |
|
+ if support.verbose: |
|
+ sys.stdout.write( |
|
+ " client: sending %r...\n" % indata) |
|
+ s.write(arg) |
|
+ outdata = s.read() |
|
+ if connectionchatty: |
|
+ if support.verbose: |
|
+ sys.stdout.write(" client: read %r\n" % outdata) |
|
+ if outdata != indata.lower(): |
|
+ raise AssertionError( |
|
+ "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n" |
|
+ % (outdata[:20], len(outdata), |
|
+ indata[:20].lower(), len(indata))) |
|
+ s.write(b"over\n") |
|
if connectionchatty: |
|
- if test_support.verbose: |
|
- sys.stdout.write(" client: read %s\n" % repr(outdata)) |
|
- if outdata != indata.lower(): |
|
- raise AssertionError( |
|
- "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n" |
|
- % (outdata[:min(len(outdata),20)], len(outdata), |
|
- indata[:min(len(indata),20)].lower(), len(indata))) |
|
- s.write("over\n") |
|
- if connectionchatty: |
|
- if test_support.verbose: |
|
- sys.stdout.write(" client: closing connection.\n") |
|
- s.close() |
|
+ if support.verbose: |
|
+ sys.stdout.write(" client: closing connection.\n") |
|
+ stats.update({ |
|
+ 'compression': s.compression(), |
|
+ 'cipher': s.cipher(), |
|
+ 'peercert': s.getpeercert(), |
|
+ 'client_npn_protocol': s.selected_npn_protocol() |
|
+ }) |
|
+ s.close() |
|
+ stats['server_npn_protocols'] = server.selected_protocols |
|
+ return stats |
|
|
|
- def try_protocol_combo(server_protocol, |
|
- client_protocol, |
|
- expect_success, |
|
- certsreqs=None): |
|
+ def try_protocol_combo(server_protocol, client_protocol, expect_success, |
|
+ certsreqs=None, server_options=0, client_options=0): |
|
if certsreqs is None: |
|
certsreqs = ssl.CERT_NONE |
|
certtype = { |
|
@@ -899,19 +1896,30 @@ else: |
|
ssl.CERT_OPTIONAL: "CERT_OPTIONAL", |
|
ssl.CERT_REQUIRED: "CERT_REQUIRED", |
|
}[certsreqs] |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n" |
|
sys.stdout.write(formatstr % |
|
(ssl.get_protocol_name(client_protocol), |
|
ssl.get_protocol_name(server_protocol), |
|
certtype)) |
|
+ client_context = ssl.SSLContext(client_protocol) |
|
+ client_context.options |= client_options |
|
+ server_context = ssl.SSLContext(server_protocol) |
|
+ server_context.options |= server_options |
|
+ |
|
+ # NOTE: we must enable "ALL" ciphers on the client, otherwise an |
|
+ # SSLv23 client will send an SSLv3 hello (rather than SSLv2) |
|
+ # starting from OpenSSL 1.0.0 (see issue #8322). |
|
+ if client_context.protocol == ssl.PROTOCOL_SSLv23: |
|
+ client_context.set_ciphers("ALL") |
|
+ |
|
+ for ctx in (client_context, server_context): |
|
+ ctx.verify_mode = certsreqs |
|
+ ctx.load_cert_chain(CERTFILE) |
|
+ ctx.load_verify_locations(CERTFILE) |
|
try: |
|
- # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client |
|
- # will send an SSLv3 hello (rather than SSLv2) starting from |
|
- # OpenSSL 1.0.0 (see issue #8322). |
|
- server_params_test(CERTFILE, server_protocol, certsreqs, |
|
- CERTFILE, CERTFILE, client_protocol, |
|
- ciphers="ALL", chatty=False) |
|
+ server_params_test(client_context, server_context, |
|
+ chatty=False, connectionchatty=False) |
|
# Protocol mismatch can result in either an SSLError, or a |
|
# "Connection reset by peer" error. |
|
except ssl.SSLError: |
|
@@ -930,75 +1938,38 @@ else: |
|
|
|
class ThreadedTests(unittest.TestCase): |
|
|
|
- def test_rude_shutdown(self): |
|
- """A brutal shutdown of an SSL server should raise an IOError |
|
- in the client when attempting handshake. |
|
- """ |
|
- listener_ready = threading.Event() |
|
- listener_gone = threading.Event() |
|
- |
|
- s = socket.socket() |
|
- port = test_support.bind_port(s, HOST) |
|
- |
|
- # `listener` runs in a thread. It sits in an accept() until |
|
- # the main thread connects. Then it rudely closes the socket, |
|
- # and sets Event `listener_gone` to let the main thread know |
|
- # the socket is gone. |
|
- def listener(): |
|
- s.listen(5) |
|
- listener_ready.set() |
|
- s.accept() |
|
- s.close() |
|
- listener_gone.set() |
|
- |
|
- def connector(): |
|
- listener_ready.wait() |
|
- c = socket.socket() |
|
- c.connect((HOST, port)) |
|
- listener_gone.wait() |
|
- try: |
|
- ssl_sock = ssl.wrap_socket(c) |
|
- except IOError: |
|
- pass |
|
- else: |
|
- self.fail('connecting to closed SSL socket should have failed') |
|
- |
|
- t = threading.Thread(target=listener) |
|
- t.start() |
|
- try: |
|
- connector() |
|
- finally: |
|
- t.join() |
|
- |
|
@skip_if_broken_ubuntu_ssl |
|
def test_echo(self): |
|
"""Basic test of an SSL client connecting to a server""" |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
- server_params_test(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE, |
|
- CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1, |
|
- chatty=True, connectionchatty=True) |
|
+ for protocol in PROTOCOLS: |
|
+ context = ssl.SSLContext(protocol) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ server_params_test(context, context, |
|
+ chatty=True, connectionchatty=True) |
|
|
|
def test_getpeercert(self): |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
- s2 = socket.socket() |
|
- server = ThreadedEchoServer(CERTFILE, |
|
- certreqs=ssl.CERT_NONE, |
|
- ssl_version=ssl.PROTOCOL_SSLv23, |
|
- cacerts=CERTFILE, |
|
- chatty=False) |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ context.verify_mode = ssl.CERT_REQUIRED |
|
+ context.load_verify_locations(CERTFILE) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ server = ThreadedEchoServer(context=context, chatty=False) |
|
with server: |
|
- s = ssl.wrap_socket(socket.socket(), |
|
- certfile=CERTFILE, |
|
- ca_certs=CERTFILE, |
|
- cert_reqs=ssl.CERT_REQUIRED, |
|
- ssl_version=ssl.PROTOCOL_SSLv23) |
|
+ s = context.wrap_socket(socket.socket(), |
|
+ do_handshake_on_connect=False) |
|
s.connect((HOST, server.port)) |
|
+ # getpeercert() raise ValueError while the handshake isn't |
|
+ # done. |
|
+ with self.assertRaises(ValueError): |
|
+ s.getpeercert() |
|
+ s.do_handshake() |
|
cert = s.getpeercert() |
|
self.assertTrue(cert, "Can't get peer certificate.") |
|
cipher = s.cipher() |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write(pprint.pformat(cert) + '\n') |
|
sys.stdout.write("Connection cipher is " + str(cipher) + '.\n') |
|
if 'subject' not in cert: |
|
@@ -1009,8 +1980,94 @@ else: |
|
self.fail( |
|
"Missing or invalid 'organizationName' field in certificate subject; " |
|
"should be 'Python Software Foundation'.") |
|
+ self.assertIn('notBefore', cert) |
|
+ self.assertIn('notAfter', cert) |
|
+ before = ssl.cert_time_to_seconds(cert['notBefore']) |
|
+ after = ssl.cert_time_to_seconds(cert['notAfter']) |
|
+ self.assertLess(before, after) |
|
s.close() |
|
|
|
+ @unittest.skipUnless(have_verify_flags(), |
|
+ "verify_flags need OpenSSL > 0.9.8") |
|
+ def test_crl_check(self): |
|
+ if support.verbose: |
|
+ sys.stdout.write("\n") |
|
+ |
|
+ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ server_context.load_cert_chain(SIGNED_CERTFILE) |
|
+ |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ context.verify_mode = ssl.CERT_REQUIRED |
|
+ context.load_verify_locations(SIGNING_CA) |
|
+ self.assertEqual(context.verify_flags, ssl.VERIFY_DEFAULT) |
|
+ |
|
+ # VERIFY_DEFAULT should pass |
|
+ server = ThreadedEchoServer(context=server_context, chatty=True) |
|
+ with server: |
|
+ with closing(context.wrap_socket(socket.socket())) as s: |
|
+ s.connect((HOST, server.port)) |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert, "Can't get peer certificate.") |
|
+ |
|
+ # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails |
|
+ context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF |
|
+ |
|
+ server = ThreadedEchoServer(context=server_context, chatty=True) |
|
+ with server: |
|
+ with closing(context.wrap_socket(socket.socket())) as s: |
|
+ with self.assertRaisesRegexp(ssl.SSLError, |
|
+ "certificate verify failed"): |
|
+ s.connect((HOST, server.port)) |
|
+ |
|
+ # now load a CRL file. The CRL file is signed by the CA. |
|
+ context.load_verify_locations(CRLFILE) |
|
+ |
|
+ server = ThreadedEchoServer(context=server_context, chatty=True) |
|
+ with server: |
|
+ with closing(context.wrap_socket(socket.socket())) as s: |
|
+ s.connect((HOST, server.port)) |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert, "Can't get peer certificate.") |
|
+ |
|
+ @needs_sni |
|
+ def test_check_hostname(self): |
|
+ if support.verbose: |
|
+ sys.stdout.write("\n") |
|
+ |
|
+ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ server_context.load_cert_chain(SIGNED_CERTFILE) |
|
+ |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ context.verify_mode = ssl.CERT_REQUIRED |
|
+ context.check_hostname = True |
|
+ context.load_verify_locations(SIGNING_CA) |
|
+ |
|
+ # correct hostname should verify |
|
+ server = ThreadedEchoServer(context=server_context, chatty=True) |
|
+ with server: |
|
+ with closing(context.wrap_socket(socket.socket(), |
|
+ server_hostname="localhost")) as s: |
|
+ s.connect((HOST, server.port)) |
|
+ cert = s.getpeercert() |
|
+ self.assertTrue(cert, "Can't get peer certificate.") |
|
+ |
|
+ # incorrect hostname should raise an exception |
|
+ server = ThreadedEchoServer(context=server_context, chatty=True) |
|
+ with server: |
|
+ with closing(context.wrap_socket(socket.socket(), |
|
+ server_hostname="invalid")) as s: |
|
+ with self.assertRaisesRegexp(ssl.CertificateError, |
|
+ "hostname 'invalid' doesn't match u?'localhost'"): |
|
+ s.connect((HOST, server.port)) |
|
+ |
|
+ # missing server_hostname arg should cause an exception, too |
|
+ server = ThreadedEchoServer(context=server_context, chatty=True) |
|
+ with server: |
|
+ with closing(socket.socket()) as s: |
|
+ with self.assertRaisesRegexp(ValueError, |
|
+ "check_hostname requires server_hostname"): |
|
+ context.wrap_socket(s) |
|
+ |
|
def test_empty_cert(self): |
|
"""Connecting with an empty cert file""" |
|
bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, |
|
@@ -1027,26 +2084,83 @@ else: |
|
"""Connecting with a badly formatted key (syntax error)""" |
|
bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, |
|
"badkey.pem")) |
|
+ def test_rude_shutdown(self): |
|
+ """A brutal shutdown of an SSL server should raise an OSError |
|
+ in the client when attempting handshake. |
|
+ """ |
|
+ listener_ready = threading.Event() |
|
+ listener_gone = threading.Event() |
|
|
|
- @skip_if_broken_ubuntu_ssl |
|
+ s = socket.socket() |
|
+ port = support.bind_port(s, HOST) |
|
+ |
|
+ # `listener` runs in a thread. It sits in an accept() until |
|
+ # the main thread connects. Then it rudely closes the socket, |
|
+ # and sets Event `listener_gone` to let the main thread know |
|
+ # the socket is gone. |
|
+ def listener(): |
|
+ s.listen(5) |
|
+ listener_ready.set() |
|
+ newsock, addr = s.accept() |
|
+ newsock.close() |
|
+ s.close() |
|
+ listener_gone.set() |
|
+ |
|
+ def connector(): |
|
+ listener_ready.wait() |
|
+ with closing(socket.socket()) as c: |
|
+ c.connect((HOST, port)) |
|
+ listener_gone.wait() |
|
+ try: |
|
+ ssl_sock = ssl.wrap_socket(c) |
|
+ except ssl.SSLError: |
|
+ pass |
|
+ else: |
|
+ self.fail('connecting to closed SSL socket should have failed') |
|
+ |
|
+ t = threading.Thread(target=listener) |
|
+ t.start() |
|
+ try: |
|
+ connector() |
|
+ finally: |
|
+ t.join() |
|
+ |
|
+ @unittest.skipUnless(hasattr(ssl, 'PROTOCOL_SSLv2'), |
|
+ "OpenSSL is compiled without SSLv2 support") |
|
def test_protocol_sslv2(self): |
|
"""Connecting to an SSLv2 server with various client options""" |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
- if not hasattr(ssl, 'PROTOCOL_SSLv2'): |
|
- self.skipTest("PROTOCOL_SSLv2 needed") |
|
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) |
|
+ # SSLv23 client with specific SSL options |
|
+ if no_sslv2_implies_sslv3_hello(): |
|
+ # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
|
+ client_options=ssl.OP_NO_SSLv2) |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
|
+ client_options=ssl.OP_NO_SSLv3) |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
|
+ client_options=ssl.OP_NO_TLSv1) |
|
|
|
@skip_if_broken_ubuntu_ssl |
|
def test_protocol_sslv23(self): |
|
"""Connecting to an SSLv23 server with various client options""" |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
+ if hasattr(ssl, 'PROTOCOL_SSLv2'): |
|
+ try: |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) |
|
+ except socket.error as x: |
|
+ # this fails on some older versions of OpenSSL (0.9.7l, for instance) |
|
+ if support.verbose: |
|
+ sys.stdout.write( |
|
+ " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" |
|
+ % str(x)) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) |
|
@@ -1059,22 +2173,38 @@ else: |
|
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) |
|
|
|
+ # Server with specific SSL options |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False, |
|
+ server_options=ssl.OP_NO_SSLv3) |
|
+ # Will choose TLSv1 |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, |
|
+ server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, False, |
|
+ server_options=ssl.OP_NO_TLSv1) |
|
+ |
|
+ |
|
@skip_if_broken_ubuntu_ssl |
|
def test_protocol_sslv3(self): |
|
"""Connecting to an SSLv3 server with various client options""" |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) |
|
if hasattr(ssl, 'PROTOCOL_SSLv2'): |
|
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False, |
|
+ client_options=ssl.OP_NO_SSLv3) |
|
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) |
|
+ if no_sslv2_implies_sslv3_hello(): |
|
+ # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, True, |
|
+ client_options=ssl.OP_NO_SSLv2) |
|
|
|
@skip_if_broken_ubuntu_ssl |
|
def test_protocol_tlsv1(self): |
|
"""Connecting to a TLSv1 server with various client options""" |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) |
|
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) |
|
@@ -1082,10 +2212,55 @@ else: |
|
if hasattr(ssl, 'PROTOCOL_SSLv2'): |
|
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) |
|
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False, |
|
+ client_options=ssl.OP_NO_TLSv1) |
|
+ |
|
+ @skip_if_broken_ubuntu_ssl |
|
+ @unittest.skipUnless(hasattr(ssl, "PROTOCOL_TLSv1_1"), |
|
+ "TLS version 1.1 not supported.") |
|
+ def test_protocol_tlsv1_1(self): |
|
+ """Connecting to a TLSv1.1 server with various client options. |
|
+ Testing against older TLS versions.""" |
|
+ if support.verbose: |
|
+ sys.stdout.write("\n") |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, True) |
|
+ if hasattr(ssl, 'PROTOCOL_SSLv2'): |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv23, False, |
|
+ client_options=ssl.OP_NO_TLSv1_1) |
|
+ |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, True) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1, False) |
|
+ |
|
+ |
|
+ @skip_if_broken_ubuntu_ssl |
|
+ @unittest.skipUnless(hasattr(ssl, "PROTOCOL_TLSv1_2"), |
|
+ "TLS version 1.2 not supported.") |
|
+ def test_protocol_tlsv1_2(self): |
|
+ """Connecting to a TLSv1.2 server with various client options. |
|
+ Testing against older TLS versions.""" |
|
+ if support.verbose: |
|
+ sys.stdout.write("\n") |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, True, |
|
+ server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2, |
|
+ client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,) |
|
+ if hasattr(ssl, 'PROTOCOL_SSLv2'): |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv2, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv3, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv23, False, |
|
+ client_options=ssl.OP_NO_TLSv1_2) |
|
+ |
|
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, True) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False) |
|
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_2, False) |
|
|
|
def test_starttls(self): |
|
"""Switching from clear text to encrypted and back again.""" |
|
- msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6") |
|
+ msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6") |
|
|
|
server = ThreadedEchoServer(CERTFILE, |
|
ssl_version=ssl.PROTOCOL_TLSv1, |
|
@@ -1097,119 +2272,109 @@ else: |
|
s = socket.socket() |
|
s.setblocking(1) |
|
s.connect((HOST, server.port)) |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
for indata in msgs: |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write( |
|
- " client: sending %s...\n" % repr(indata)) |
|
+ " client: sending %r...\n" % indata) |
|
if wrapped: |
|
conn.write(indata) |
|
outdata = conn.read() |
|
else: |
|
s.send(indata) |
|
outdata = s.recv(1024) |
|
- if (indata == "STARTTLS" and |
|
- outdata.strip().lower().startswith("ok")): |
|
+ msg = outdata.strip().lower() |
|
+ if indata == b"STARTTLS" and msg.startswith(b"ok"): |
|
# STARTTLS ok, switch to secure mode |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write( |
|
- " client: read %s from server, starting TLS...\n" |
|
- % repr(outdata)) |
|
+ " client: read %r from server, starting TLS...\n" |
|
+ % msg) |
|
conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1) |
|
wrapped = True |
|
- elif (indata == "ENDTLS" and |
|
- outdata.strip().lower().startswith("ok")): |
|
+ elif indata == b"ENDTLS" and msg.startswith(b"ok"): |
|
# ENDTLS ok, switch back to clear text |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write( |
|
- " client: read %s from server, ending TLS...\n" |
|
- % repr(outdata)) |
|
+ " client: read %r from server, ending TLS...\n" |
|
+ % msg) |
|
s = conn.unwrap() |
|
wrapped = False |
|
else: |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write( |
|
- " client: read %s from server\n" % repr(outdata)) |
|
- if test_support.verbose: |
|
+ " client: read %r from server\n" % msg) |
|
+ if support.verbose: |
|
sys.stdout.write(" client: closing connection.\n") |
|
if wrapped: |
|
- conn.write("over\n") |
|
+ conn.write(b"over\n") |
|
else: |
|
- s.send("over\n") |
|
- s.close() |
|
+ s.send(b"over\n") |
|
+ if wrapped: |
|
+ conn.close() |
|
+ else: |
|
+ s.close() |
|
|
|
def test_socketserver(self): |
|
"""Using a SocketServer to create and manage SSL connections.""" |
|
- server = SocketServerHTTPSServer(CERTFILE) |
|
- flag = threading.Event() |
|
- server.start(flag) |
|
- # wait for it to start |
|
- flag.wait() |
|
+ server = make_https_server(self, certfile=CERTFILE) |
|
# try to connect |
|
+ if support.verbose: |
|
+ sys.stdout.write('\n') |
|
+ with open(CERTFILE, 'rb') as f: |
|
+ d1 = f.read() |
|
+ d2 = '' |
|
+ # now fetch the same data from the HTTPS server |
|
+ url = 'https://%s:%d/%s' % ( |
|
+ HOST, server.port, os.path.split(CERTFILE)[1]) |
|
+ f = urllib.urlopen(url) |
|
try: |
|
- if test_support.verbose: |
|
- sys.stdout.write('\n') |
|
- with open(CERTFILE, 'rb') as f: |
|
- d1 = f.read() |
|
- d2 = '' |
|
- # now fetch the same data from the HTTPS server |
|
- url = 'https://127.0.0.1:%d/%s' % ( |
|
- server.port, os.path.split(CERTFILE)[1]) |
|
- with test_support.check_py3k_warnings(): |
|
- f = urllib.urlopen(url) |
|
dlen = f.info().getheader("content-length") |
|
if dlen and (int(dlen) > 0): |
|
d2 = f.read(int(dlen)) |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write( |
|
" client: read %d bytes from remote server '%s'\n" |
|
% (len(d2), server)) |
|
- f.close() |
|
- self.assertEqual(d1, d2) |
|
finally: |
|
- server.stop() |
|
- server.join() |
|
- |
|
- def test_wrapped_accept(self): |
|
- """Check the accept() method on SSL sockets.""" |
|
- if test_support.verbose: |
|
- sys.stdout.write("\n") |
|
- server_params_test(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED, |
|
- CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23, |
|
- chatty=True, connectionchatty=True, |
|
- wrap_accepting_socket=True) |
|
+ f.close() |
|
+ self.assertEqual(d1, d2) |
|
|
|
def test_asyncore_server(self): |
|
"""Check the example asyncore integration.""" |
|
indata = "TEST MESSAGE of mixed case\n" |
|
|
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
+ |
|
+ indata = b"FOO\n" |
|
server = AsyncoreEchoServer(CERTFILE) |
|
with server: |
|
s = ssl.wrap_socket(socket.socket()) |
|
s.connect(('127.0.0.1', server.port)) |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write( |
|
- " client: sending %s...\n" % (repr(indata))) |
|
+ " client: sending %r...\n" % indata) |
|
s.write(indata) |
|
outdata = s.read() |
|
- if test_support.verbose: |
|
- sys.stdout.write(" client: read %s\n" % repr(outdata)) |
|
+ if support.verbose: |
|
+ sys.stdout.write(" client: read %r\n" % outdata) |
|
if outdata != indata.lower(): |
|
self.fail( |
|
- "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n" |
|
- % (outdata[:min(len(outdata),20)], len(outdata), |
|
- indata[:min(len(indata),20)].lower(), len(indata))) |
|
- s.write("over\n") |
|
- if test_support.verbose: |
|
+ "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n" |
|
+ % (outdata[:20], len(outdata), |
|
+ indata[:20].lower(), len(indata))) |
|
+ s.write(b"over\n") |
|
+ if support.verbose: |
|
sys.stdout.write(" client: closing connection.\n") |
|
s.close() |
|
+ if support.verbose: |
|
+ sys.stdout.write(" client: connection closed.\n") |
|
|
|
def test_recv_send(self): |
|
"""Test recv(), send() and friends.""" |
|
- if test_support.verbose: |
|
+ if support.verbose: |
|
sys.stdout.write("\n") |
|
|
|
server = ThreadedEchoServer(CERTFILE, |
|
@@ -1228,12 +2393,12 @@ else: |
|
s.connect((HOST, server.port)) |
|
# helper methods for standardising recv* method signatures |
|
def _recv_into(): |
|
- b = bytearray("\0"*100) |
|
+ b = bytearray(b"\0"*100) |
|
count = s.recv_into(b) |
|
return b[:count] |
|
|
|
def _recvfrom_into(): |
|
- b = bytearray("\0"*100) |
|
+ b = bytearray(b"\0"*100) |
|
count, addr = s.recvfrom_into(b) |
|
return b[:count] |
|
|
|
@@ -1252,73 +2417,73 @@ else: |
|
data_prefix = u"PREFIX_" |
|
|
|
for meth_name, send_meth, expect_success, args in send_methods: |
|
- indata = data_prefix + meth_name |
|
+ indata = (data_prefix + meth_name).encode('ascii') |
|
try: |
|
- send_meth(indata.encode('ASCII', 'strict'), *args) |
|
+ send_meth(indata, *args) |
|
outdata = s.read() |
|
- outdata = outdata.decode('ASCII', 'strict') |
|
if outdata != indata.lower(): |
|
self.fail( |
|
- "While sending with <<%s>> bad data " |
|
- "<<%r>> (%d) received; " |
|
- "expected <<%r>> (%d)\n" % ( |
|
- meth_name, outdata[:20], len(outdata), |
|
- indata[:20], len(indata) |
|
+ "While sending with <<{name:s}>> bad data " |
|
+ "<<{outdata:r}>> ({nout:d}) received; " |
|
+ "expected <<{indata:r}>> ({nin:d})\n".format( |
|
+ name=meth_name, outdata=outdata[:20], |
|
+ nout=len(outdata), |
|
+ indata=indata[:20], nin=len(indata) |
|
) |
|
) |
|
except ValueError as e: |
|
if expect_success: |
|
self.fail( |
|
- "Failed to send with method <<%s>>; " |
|
- "expected to succeed.\n" % (meth_name,) |
|
+ "Failed to send with method <<{name:s}>>; " |
|
+ "expected to succeed.\n".format(name=meth_name) |
|
) |
|
if not str(e).startswith(meth_name): |
|
self.fail( |
|
- "Method <<%s>> failed with unexpected " |
|
- "exception message: %s\n" % ( |
|
- meth_name, e |
|
+ "Method <<{name:s}>> failed with unexpected " |
|
+ "exception message: {exp:s}\n".format( |
|
+ name=meth_name, exp=e |
|
) |
|
) |
|
|
|
for meth_name, recv_meth, expect_success, args in recv_methods: |
|
- indata = data_prefix + meth_name |
|
+ indata = (data_prefix + meth_name).encode('ascii') |
|
try: |
|
- s.send(indata.encode('ASCII', 'strict')) |
|
+ s.send(indata) |
|
outdata = recv_meth(*args) |
|
- outdata = outdata.decode('ASCII', 'strict') |
|
if outdata != indata.lower(): |
|
self.fail( |
|
- "While receiving with <<%s>> bad data " |
|
- "<<%r>> (%d) received; " |
|
- "expected <<%r>> (%d)\n" % ( |
|
- meth_name, outdata[:20], len(outdata), |
|
- indata[:20], len(indata) |
|
+ "While receiving with <<{name:s}>> bad data " |
|
+ "<<{outdata:r}>> ({nout:d}) received; " |
|
+ "expected <<{indata:r}>> ({nin:d})\n".format( |
|
+ name=meth_name, outdata=outdata[:20], |
|
+ nout=len(outdata), |
|
+ indata=indata[:20], nin=len(indata) |
|
) |
|
) |
|
except ValueError as e: |
|
if expect_success: |
|
self.fail( |
|
- "Failed to receive with method <<%s>>; " |
|
- "expected to succeed.\n" % (meth_name,) |
|
+ "Failed to receive with method <<{name:s}>>; " |
|
+ "expected to succeed.\n".format(name=meth_name) |
|
) |
|
if not str(e).startswith(meth_name): |
|
self.fail( |
|
- "Method <<%s>> failed with unexpected " |
|
- "exception message: %s\n" % ( |
|
- meth_name, e |
|
+ "Method <<{name:s}>> failed with unexpected " |
|
+ "exception message: {exp:s}\n".format( |
|
+ name=meth_name, exp=e |
|
) |
|
) |
|
# consume data |
|
s.read() |
|
|
|
- s.write("over\n".encode("ASCII", "strict")) |
|
+ s.write(b"over\n") |
|
s.close() |
|
|
|
def test_handshake_timeout(self): |
|
# Issue #5103: SSL handshake must respect the socket timeout |
|
server = socket.socket(socket.AF_INET) |
|
host = "127.0.0.1" |
|
- port = test_support.bind_port(server) |
|
+ port = support.bind_port(server) |
|
started = threading.Event() |
|
finish = False |
|
|
|
@@ -1332,6 +2497,8 @@ else: |
|
# Let the socket hang around rather than having |
|
# it closed by garbage collection. |
|
conns.append(server.accept()[0]) |
|
+ for sock in conns: |
|
+ sock.close() |
|
|
|
t = threading.Thread(target=serve) |
|
t.start() |
|
@@ -1349,8 +2516,8 @@ else: |
|
c.close() |
|
try: |
|
c = socket.socket(socket.AF_INET) |
|
- c.settimeout(0.2) |
|
c = ssl.wrap_socket(c) |
|
+ c.settimeout(0.2) |
|
# Will attempt handshake and time out |
|
self.assertRaisesRegexp(ssl.SSLError, "timed out", |
|
c.connect, (host, port)) |
|
@@ -1361,59 +2528,384 @@ else: |
|
t.join() |
|
server.close() |
|
|
|
+ def test_server_accept(self): |
|
+ # Issue #16357: accept() on a SSLSocket created through |
|
+ # SSLContext.wrap_socket(). |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ context.verify_mode = ssl.CERT_REQUIRED |
|
+ context.load_verify_locations(CERTFILE) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ server = socket.socket(socket.AF_INET) |
|
+ host = "127.0.0.1" |
|
+ port = support.bind_port(server) |
|
+ server = context.wrap_socket(server, server_side=True) |
|
+ |
|
+ evt = threading.Event() |
|
+ remote = [None] |
|
+ peer = [None] |
|
+ def serve(): |
|
+ server.listen(5) |
|
+ # Block on the accept and wait on the connection to close. |
|
+ evt.set() |
|
+ remote[0], peer[0] = server.accept() |
|
+ remote[0].recv(1) |
|
+ |
|
+ t = threading.Thread(target=serve) |
|
+ t.start() |
|
+ # Client wait until server setup and perform a connect. |
|
+ evt.wait() |
|
+ client = context.wrap_socket(socket.socket()) |
|
+ client.connect((host, port)) |
|
+ client_addr = client.getsockname() |
|
+ client.close() |
|
+ t.join() |
|
+ remote[0].close() |
|
+ server.close() |
|
+ # Sanity checks. |
|
+ self.assertIsInstance(remote[0], ssl.SSLSocket) |
|
+ self.assertEqual(peer[0], client_addr) |
|
+ |
|
+ def test_getpeercert_enotconn(self): |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ with closing(context.wrap_socket(socket.socket())) as sock: |
|
+ with self.assertRaises(socket.error) as cm: |
|
+ sock.getpeercert() |
|
+ self.assertEqual(cm.exception.errno, errno.ENOTCONN) |
|
+ |
|
+ def test_do_handshake_enotconn(self): |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ with closing(context.wrap_socket(socket.socket())) as sock: |
|
+ with self.assertRaises(socket.error) as cm: |
|
+ sock.do_handshake() |
|
+ self.assertEqual(cm.exception.errno, errno.ENOTCONN) |
|
+ |
|
def test_default_ciphers(self): |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ try: |
|
+ # Force a set of weak ciphers on our client context |
|
+ context.set_ciphers("DES") |
|
+ except ssl.SSLError: |
|
+ self.skipTest("no DES cipher available") |
|
with ThreadedEchoServer(CERTFILE, |
|
ssl_version=ssl.PROTOCOL_SSLv23, |
|
chatty=False) as server: |
|
- sock = socket.socket() |
|
- try: |
|
- # Force a set of weak ciphers on our client socket |
|
- try: |
|
- s = ssl.wrap_socket(sock, |
|
- ssl_version=ssl.PROTOCOL_SSLv23, |
|
- ciphers="DES") |
|
- except ssl.SSLError: |
|
- self.skipTest("no DES cipher available") |
|
- with self.assertRaises((OSError, ssl.SSLError)): |
|
+ with closing(context.wrap_socket(socket.socket())) as s: |
|
+ with self.assertRaises(ssl.SSLError): |
|
s.connect((HOST, server.port)) |
|
- finally: |
|
- sock.close() |
|
self.assertIn("no shared cipher", str(server.conn_errors[0])) |
|
|
|
+ @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") |
|
+ def test_default_ecdh_curve(self): |
|
+ # Issue #21015: elliptic curve-based Diffie Hellman key exchange |
|
+ # should be enabled by default on SSL contexts. |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled |
|
+ # explicitly using the 'ECCdraft' cipher alias. Otherwise, |
|
+ # our default cipher list should prefer ECDH-based ciphers |
|
+ # automatically. |
|
+ if ssl.OPENSSL_VERSION_INFO < (1, 0, 0): |
|
+ context.set_ciphers("ECCdraft:ECDH") |
|
+ with ThreadedEchoServer(context=context) as server: |
|
+ with closing(context.wrap_socket(socket.socket())) as s: |
|
+ s.connect((HOST, server.port)) |
|
+ self.assertIn("ECDH", s.cipher()[0]) |
|
+ |
|
+ @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES, |
|
+ "'tls-unique' channel binding not available") |
|
+ def test_tls_unique_channel_binding(self): |
|
+ """Test tls-unique channel binding.""" |
|
+ if support.verbose: |
|
+ sys.stdout.write("\n") |
|
+ |
|
+ server = ThreadedEchoServer(CERTFILE, |
|
+ certreqs=ssl.CERT_NONE, |
|
+ ssl_version=ssl.PROTOCOL_TLSv1, |
|
+ cacerts=CERTFILE, |
|
+ chatty=True, |
|
+ connectionchatty=False) |
|
+ with server: |
|
+ s = ssl.wrap_socket(socket.socket(), |
|
+ server_side=False, |
|
+ certfile=CERTFILE, |
|
+ ca_certs=CERTFILE, |
|
+ cert_reqs=ssl.CERT_NONE, |
|
+ ssl_version=ssl.PROTOCOL_TLSv1) |
|
+ s.connect((HOST, server.port)) |
|
+ # get the data |
|
+ cb_data = s.get_channel_binding("tls-unique") |
|
+ if support.verbose: |
|
+ sys.stdout.write(" got channel binding data: {0!r}\n" |
|
+ .format(cb_data)) |
|
+ |
|
+ # check if it is sane |
|
+ self.assertIsNotNone(cb_data) |
|
+ self.assertEqual(len(cb_data), 12) # True for TLSv1 |
|
+ |
|
+ # and compare with the peers version |
|
+ s.write(b"CB tls-unique\n") |
|
+ peer_data_repr = s.read().strip() |
|
+ self.assertEqual(peer_data_repr, |
|
+ repr(cb_data).encode("us-ascii")) |
|
+ s.close() |
|
+ |
|
+ # now, again |
|
+ s = ssl.wrap_socket(socket.socket(), |
|
+ server_side=False, |
|
+ certfile=CERTFILE, |
|
+ ca_certs=CERTFILE, |
|
+ cert_reqs=ssl.CERT_NONE, |
|
+ ssl_version=ssl.PROTOCOL_TLSv1) |
|
+ s.connect((HOST, server.port)) |
|
+ new_cb_data = s.get_channel_binding("tls-unique") |
|
+ if support.verbose: |
|
+ sys.stdout.write(" got another channel binding data: {0!r}\n" |
|
+ .format(new_cb_data)) |
|
+ # is it really unique |
|
+ self.assertNotEqual(cb_data, new_cb_data) |
|
+ self.assertIsNotNone(cb_data) |
|
+ self.assertEqual(len(cb_data), 12) # True for TLSv1 |
|
+ s.write(b"CB tls-unique\n") |
|
+ peer_data_repr = s.read().strip() |
|
+ self.assertEqual(peer_data_repr, |
|
+ repr(new_cb_data).encode("us-ascii")) |
|
+ s.close() |
|
+ |
|
+ def test_compression(self): |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ stats = server_params_test(context, context, |
|
+ chatty=True, connectionchatty=True) |
|
+ if support.verbose: |
|
+ sys.stdout.write(" got compression: {!r}\n".format(stats['compression'])) |
|
+ self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' }) |
|
+ |
|
+ @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'), |
|
+ "ssl.OP_NO_COMPRESSION needed for this test") |
|
+ def test_compression_disabled(self): |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ context.options |= ssl.OP_NO_COMPRESSION |
|
+ stats = server_params_test(context, context, |
|
+ chatty=True, connectionchatty=True) |
|
+ self.assertIs(stats['compression'], None) |
|
+ |
|
+ def test_dh_params(self): |
|
+ # Check we can get a connection with ephemeral Diffie-Hellman |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ context.load_dh_params(DHFILE) |
|
+ context.set_ciphers("kEDH") |
|
+ stats = server_params_test(context, context, |
|
+ chatty=True, connectionchatty=True) |
|
+ cipher = stats["cipher"][0] |
|
+ parts = cipher.split("-") |
|
+ if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts: |
|
+ self.fail("Non-DH cipher: " + cipher[0]) |
|
+ |
|
+ def test_selected_npn_protocol(self): |
|
+ # selected_npn_protocol() is None unless NPN is used |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ stats = server_params_test(context, context, |
|
+ chatty=True, connectionchatty=True) |
|
+ self.assertIs(stats['client_npn_protocol'], None) |
|
+ |
|
+ @unittest.skipUnless(ssl.HAS_NPN, "NPN support needed for this test") |
|
+ def test_npn_protocols(self): |
|
+ server_protocols = ['http/1.1', 'spdy/2'] |
|
+ protocol_tests = [ |
|
+ (['http/1.1', 'spdy/2'], 'http/1.1'), |
|
+ (['spdy/2', 'http/1.1'], 'http/1.1'), |
|
+ (['spdy/2', 'test'], 'spdy/2'), |
|
+ (['abc', 'def'], 'abc') |
|
+ ] |
|
+ for client_protocols, expected in protocol_tests: |
|
+ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ server_context.load_cert_chain(CERTFILE) |
|
+ server_context.set_npn_protocols(server_protocols) |
|
+ client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ client_context.load_cert_chain(CERTFILE) |
|
+ client_context.set_npn_protocols(client_protocols) |
|
+ stats = server_params_test(client_context, server_context, |
|
+ chatty=True, connectionchatty=True) |
|
+ |
|
+ msg = "failed trying %s (s) and %s (c).\n" \ |
|
+ "was expecting %s, but got %%s from the %%s" \ |
|
+ % (str(server_protocols), str(client_protocols), |
|
+ str(expected)) |
|
+ client_result = stats['client_npn_protocol'] |
|
+ self.assertEqual(client_result, expected, msg % (client_result, "client")) |
|
+ server_result = stats['server_npn_protocols'][-1] \ |
|
+ if len(stats['server_npn_protocols']) else 'nothing' |
|
+ self.assertEqual(server_result, expected, msg % (server_result, "server")) |
|
+ |
|
+ def sni_contexts(self): |
|
+ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ server_context.load_cert_chain(SIGNED_CERTFILE) |
|
+ other_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ other_context.load_cert_chain(SIGNED_CERTFILE2) |
|
+ client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
|
+ client_context.verify_mode = ssl.CERT_REQUIRED |
|
+ client_context.load_verify_locations(SIGNING_CA) |
|
+ return server_context, other_context, client_context |
|
+ |
|
+ def check_common_name(self, stats, name): |
|
+ cert = stats['peercert'] |
|
+ self.assertIn((('commonName', name),), cert['subject']) |
|
+ |
|
+ @needs_sni |
|
+ def test_sni_callback(self): |
|
+ calls = [] |
|
+ server_context, other_context, client_context = self.sni_contexts() |
|
+ |
|
+ def servername_cb(ssl_sock, server_name, initial_context): |
|
+ calls.append((server_name, initial_context)) |
|
+ if server_name is not None: |
|
+ ssl_sock.context = other_context |
|
+ server_context.set_servername_callback(servername_cb) |
|
+ |
|
+ stats = server_params_test(client_context, server_context, |
|
+ chatty=True, |
|
+ sni_name='supermessage') |
|
+ # The hostname was fetched properly, and the certificate was |
|
+ # changed for the connection. |
|
+ self.assertEqual(calls, [("supermessage", server_context)]) |
|
+ # CERTFILE4 was selected |
|
+ self.check_common_name(stats, 'fakehostname') |
|
+ |
|
+ calls = [] |
|
+ # The callback is called with server_name=None |
|
+ stats = server_params_test(client_context, server_context, |
|
+ chatty=True, |
|
+ sni_name=None) |
|
+ self.assertEqual(calls, [(None, server_context)]) |
|
+ self.check_common_name(stats, 'localhost') |
|
+ |
|
+ # Check disabling the callback |
|
+ calls = [] |
|
+ server_context.set_servername_callback(None) |
|
+ |
|
+ stats = server_params_test(client_context, server_context, |
|
+ chatty=True, |
|
+ sni_name='notfunny') |
|
+ # Certificate didn't change |
|
+ self.check_common_name(stats, 'localhost') |
|
+ self.assertEqual(calls, []) |
|
+ |
|
+ @needs_sni |
|
+ def test_sni_callback_alert(self): |
|
+ # Returning a TLS alert is reflected to the connecting client |
|
+ server_context, other_context, client_context = self.sni_contexts() |
|
+ |
|
+ def cb_returning_alert(ssl_sock, server_name, initial_context): |
|
+ return ssl.ALERT_DESCRIPTION_ACCESS_DENIED |
|
+ server_context.set_servername_callback(cb_returning_alert) |
|
+ |
|
+ with self.assertRaises(ssl.SSLError) as cm: |
|
+ stats = server_params_test(client_context, server_context, |
|
+ chatty=False, |
|
+ sni_name='supermessage') |
|
+ self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED') |
|
+ |
|
+ @needs_sni |
|
+ def test_sni_callback_raising(self): |
|
+ # Raising fails the connection with a TLS handshake failure alert. |
|
+ server_context, other_context, client_context = self.sni_contexts() |
|
+ |
|
+ def cb_raising(ssl_sock, server_name, initial_context): |
|
+ 1/0 |
|
+ server_context.set_servername_callback(cb_raising) |
|
+ |
|
+ with self.assertRaises(ssl.SSLError) as cm, \ |
|
+ support.captured_stderr() as stderr: |
|
+ stats = server_params_test(client_context, server_context, |
|
+ chatty=False, |
|
+ sni_name='supermessage') |
|
+ self.assertEqual(cm.exception.reason, 'SSLV3_ALERT_HANDSHAKE_FAILURE') |
|
+ self.assertIn("ZeroDivisionError", stderr.getvalue()) |
|
+ |
|
+ @needs_sni |
|
+ def test_sni_callback_wrong_return_type(self): |
|
+ # Returning the wrong return type terminates the TLS connection |
|
+ # with an internal error alert. |
|
+ server_context, other_context, client_context = self.sni_contexts() |
|
+ |
|
+ def cb_wrong_return_type(ssl_sock, server_name, initial_context): |
|
+ return "foo" |
|
+ server_context.set_servername_callback(cb_wrong_return_type) |
|
+ |
|
+ with self.assertRaises(ssl.SSLError) as cm, \ |
|
+ support.captured_stderr() as stderr: |
|
+ stats = server_params_test(client_context, server_context, |
|
+ chatty=False, |
|
+ sni_name='supermessage') |
|
+ self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR') |
|
+ self.assertIn("TypeError", stderr.getvalue()) |
|
+ |
|
+ def test_read_write_after_close_raises_valuerror(self): |
|
+ context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
|
+ context.verify_mode = ssl.CERT_REQUIRED |
|
+ context.load_verify_locations(CERTFILE) |
|
+ context.load_cert_chain(CERTFILE) |
|
+ server = ThreadedEchoServer(context=context, chatty=False) |
|
+ |
|
+ with server: |
|
+ s = context.wrap_socket(socket.socket()) |
|
+ s.connect((HOST, server.port)) |
|
+ s.close() |
|
+ |
|
+ self.assertRaises(ValueError, s.read, 1024) |
|
+ self.assertRaises(ValueError, s.write, b'hello') |
|
+ |
|
|
|
def test_main(verbose=False): |
|
- global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, NOKIACERT, NULLBYTECERT |
|
- CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, |
|
- "keycert.pem") |
|
- SVN_PYTHON_ORG_ROOT_CERT = os.path.join( |
|
- os.path.dirname(__file__) or os.curdir, |
|
- "https_svn_python_org_root.pem") |
|
- NOKIACERT = os.path.join(os.path.dirname(__file__) or os.curdir, |
|
- "nokia.pem") |
|
- NULLBYTECERT = os.path.join(os.path.dirname(__file__) or os.curdir, |
|
- "nullbytecert.pem") |
|
- |
|
- if (not os.path.exists(CERTFILE) or |
|
- not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT) or |
|
- not os.path.exists(NOKIACERT) or |
|
- not os.path.exists(NULLBYTECERT)): |
|
- raise test_support.TestFailed("Can't read certificate files!") |
|
+ if support.verbose: |
|
+ plats = { |
|
+ 'Linux': platform.linux_distribution, |
|
+ 'Mac': platform.mac_ver, |
|
+ 'Windows': platform.win32_ver, |
|
+ } |
|
+ for name, func in plats.items(): |
|
+ plat = func() |
|
+ if plat and plat[0]: |
|
+ plat = '%s %r' % (name, plat) |
|
+ break |
|
+ else: |
|
+ plat = repr(platform.platform()) |
|
+ print("test_ssl: testing with %r %r" % |
|
+ (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO)) |
|
+ print(" under %s" % plat) |
|
+ print(" HAS_SNI = %r" % ssl.HAS_SNI) |
|
+ print(" OP_ALL = 0x%8x" % ssl.OP_ALL) |
|
+ try: |
|
+ print(" OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1) |
|
+ except AttributeError: |
|
+ pass |
|
+ |
|
+ for filename in [ |
|
+ CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, BYTES_CERTFILE, |
|
+ ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY, |
|
+ SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA, |
|
+ BADCERT, BADKEY, EMPTYCERT]: |
|
+ if not os.path.exists(filename): |
|
+ raise support.TestFailed("Can't read certificate file %r" % filename) |
|
|
|
- tests = [BasicTests, BasicSocketTests] |
|
+ tests = [ContextTests, BasicSocketTests, SSLErrorTests] |
|
|
|
- if test_support.is_resource_enabled('network'): |
|
+ if support.is_resource_enabled('network'): |
|
tests.append(NetworkedTests) |
|
|
|
if _have_threads: |
|
- thread_info = test_support.threading_setup() |
|
- if thread_info and test_support.is_resource_enabled('network'): |
|
+ thread_info = support.threading_setup() |
|
+ if thread_info: |
|
tests.append(ThreadedTests) |
|
|
|
try: |
|
- test_support.run_unittest(*tests) |
|
+ support.run_unittest(*tests) |
|
finally: |
|
if _have_threads: |
|
- test_support.threading_cleanup(*thread_info) |
|
+ support.threading_cleanup(*thread_info) |
|
|
|
if __name__ == "__main__": |
|
test_main() |
|
diff -up Python-2.7.5/Makefile.pre.in.ssl Python-2.7.5/Makefile.pre.in |
|
--- Python-2.7.5/Makefile.pre.in.ssl 2015-02-24 11:37:01.544850801 +0100 |
|
+++ Python-2.7.5/Makefile.pre.in 2015-02-24 10:19:57.491864267 +0100 |
|
@@ -931,7 +931,7 @@ PLATMACDIRS= plat-mac plat-mac/Carbon pl |
|
plat-mac/lib-scriptpackages/Terminal |
|
PLATMACPATH=:plat-mac:plat-mac/lib-scriptpackages |
|
LIBSUBDIRS= lib-tk lib-tk/test lib-tk/test/test_tkinter \ |
|
- lib-tk/test/test_ttk site-packages test test/data \ |
|
+ lib-tk/test/test_ttk site-packages test test/data test/capath \ |
|
test/cjkencodings test/decimaltestdata test/xmltestdata test/subprocessdata \ |
|
test/tracedmodules \ |
|
encodings compiler hotshot \ |
|
diff --git a/Modules/_ssl_data.h b/Modules/_ssl_data.h |
|
new file mode 100644 |
|
--- /dev/null |
|
+++ b/Modules/_ssl_data.h |
|
@@ -0,0 +1,1653 @@ |
|
+/* File generated by Tools/ssl/make_ssl_data.py */ |
|
+/* Generated on 2012-05-16T23:56:40.981382 */ |
|
+ |
|
+static struct py_ssl_library_code library_codes[] = { |
|
+ {"PEM", ERR_LIB_PEM}, |
|
+ {"SSL", ERR_LIB_SSL}, |
|
+ {"X509", ERR_LIB_X509}, |
|
+ { NULL } |
|
+}; |
|
+ |
|
+static struct py_ssl_error_code error_codes[] = { |
|
+ #ifdef PEM_R_BAD_BASE64_DECODE |
|
+ {"BAD_BASE64_DECODE", ERR_LIB_PEM, PEM_R_BAD_BASE64_DECODE}, |
|
+ #else |
|
+ {"BAD_BASE64_DECODE", ERR_LIB_PEM, 100}, |
|
+ #endif |
|
+ #ifdef PEM_R_BAD_DECRYPT |
|
+ {"BAD_DECRYPT", ERR_LIB_PEM, PEM_R_BAD_DECRYPT}, |
|
+ #else |
|
+ {"BAD_DECRYPT", ERR_LIB_PEM, 101}, |
|
+ #endif |
|
+ #ifdef PEM_R_BAD_END_LINE |
|
+ {"BAD_END_LINE", ERR_LIB_PEM, PEM_R_BAD_END_LINE}, |
|
+ #else |
|
+ {"BAD_END_LINE", ERR_LIB_PEM, 102}, |
|
+ #endif |
|
+ #ifdef PEM_R_BAD_IV_CHARS |
|
+ {"BAD_IV_CHARS", ERR_LIB_PEM, PEM_R_BAD_IV_CHARS}, |
|
+ #else |
|
+ {"BAD_IV_CHARS", ERR_LIB_PEM, 103}, |
|
+ #endif |
|
+ #ifdef PEM_R_BAD_MAGIC_NUMBER |
|
+ {"BAD_MAGIC_NUMBER", ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER}, |
|
+ #else |
|
+ {"BAD_MAGIC_NUMBER", ERR_LIB_PEM, 116}, |
|
+ #endif |
|
+ #ifdef PEM_R_BAD_PASSWORD_READ |
|
+ {"BAD_PASSWORD_READ", ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ}, |
|
+ #else |
|
+ {"BAD_PASSWORD_READ", ERR_LIB_PEM, 104}, |
|
+ #endif |
|
+ #ifdef PEM_R_BAD_VERSION_NUMBER |
|
+ {"BAD_VERSION_NUMBER", ERR_LIB_PEM, PEM_R_BAD_VERSION_NUMBER}, |
|
+ #else |
|
+ {"BAD_VERSION_NUMBER", ERR_LIB_PEM, 117}, |
|
+ #endif |
|
+ #ifdef PEM_R_BIO_WRITE_FAILURE |
|
+ {"BIO_WRITE_FAILURE", ERR_LIB_PEM, PEM_R_BIO_WRITE_FAILURE}, |
|
+ #else |
|
+ {"BIO_WRITE_FAILURE", ERR_LIB_PEM, 118}, |
|
+ #endif |
|
+ #ifdef PEM_R_CIPHER_IS_NULL |
|
+ {"CIPHER_IS_NULL", ERR_LIB_PEM, PEM_R_CIPHER_IS_NULL}, |
|
+ #else |
|
+ {"CIPHER_IS_NULL", ERR_LIB_PEM, 127}, |
|
+ #endif |
|
+ #ifdef PEM_R_ERROR_CONVERTING_PRIVATE_KEY |
|
+ {"ERROR_CONVERTING_PRIVATE_KEY", ERR_LIB_PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY}, |
|
+ #else |
|
+ {"ERROR_CONVERTING_PRIVATE_KEY", ERR_LIB_PEM, 115}, |
|
+ #endif |
|
+ #ifdef PEM_R_EXPECTING_PRIVATE_KEY_BLOB |
|
+ {"EXPECTING_PRIVATE_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PRIVATE_KEY_BLOB}, |
|
+ #else |
|
+ {"EXPECTING_PRIVATE_KEY_BLOB", ERR_LIB_PEM, 119}, |
|
+ #endif |
|
+ #ifdef PEM_R_EXPECTING_PUBLIC_KEY_BLOB |
|
+ {"EXPECTING_PUBLIC_KEY_BLOB", ERR_LIB_PEM, PEM_R_EXPECTING_PUBLIC_KEY_BLOB}, |
|
+ #else |
|
+ {"EXPECTING_PUBLIC_KEY_BLOB", ERR_LIB_PEM, 120}, |
|
+ #endif |
|
+ #ifdef PEM_R_INCONSISTENT_HEADER |
|
+ {"INCONSISTENT_HEADER", ERR_LIB_PEM, PEM_R_INCONSISTENT_HEADER}, |
|
+ #else |
|
+ {"INCONSISTENT_HEADER", ERR_LIB_PEM, 121}, |
|
+ #endif |
|
+ #ifdef PEM_R_KEYBLOB_HEADER_PARSE_ERROR |
|
+ {"KEYBLOB_HEADER_PARSE_ERROR", ERR_LIB_PEM, PEM_R_KEYBLOB_HEADER_PARSE_ERROR}, |
|
+ #else |
|
+ {"KEYBLOB_HEADER_PARSE_ERROR", ERR_LIB_PEM, 122}, |
|
+ #endif |
|
+ #ifdef PEM_R_KEYBLOB_TOO_SHORT |
|
+ {"KEYBLOB_TOO_SHORT", ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT}, |
|
+ #else |
|
+ {"KEYBLOB_TOO_SHORT", ERR_LIB_PEM, 123}, |
|
+ #endif |
|
+ #ifdef PEM_R_NOT_DEK_INFO |
|
+ {"NOT_DEK_INFO", ERR_LIB_PEM, PEM_R_NOT_DEK_INFO}, |
|
+ #else |
|
+ {"NOT_DEK_INFO", ERR_LIB_PEM, 105}, |
|
+ #endif |
|
+ #ifdef PEM_R_NOT_ENCRYPTED |
|
+ {"NOT_ENCRYPTED", ERR_LIB_PEM, PEM_R_NOT_ENCRYPTED}, |
|
+ #else |
|
+ {"NOT_ENCRYPTED", ERR_LIB_PEM, 106}, |
|
+ #endif |
|
+ #ifdef PEM_R_NOT_PROC_TYPE |
|
+ {"NOT_PROC_TYPE", ERR_LIB_PEM, PEM_R_NOT_PROC_TYPE}, |
|
+ #else |
|
+ {"NOT_PROC_TYPE", ERR_LIB_PEM, 107}, |
|
+ #endif |
|
+ #ifdef PEM_R_NO_START_LINE |
|
+ {"NO_START_LINE", ERR_LIB_PEM, PEM_R_NO_START_LINE}, |
|
+ #else |
|
+ {"NO_START_LINE", ERR_LIB_PEM, 108}, |
|
+ #endif |
|
+ #ifdef PEM_R_PROBLEMS_GETTING_PASSWORD |
|
+ {"PROBLEMS_GETTING_PASSWORD", ERR_LIB_PEM, PEM_R_PROBLEMS_GETTING_PASSWORD}, |
|
+ #else |
|
+ {"PROBLEMS_GETTING_PASSWORD", ERR_LIB_PEM, 109}, |
|
+ #endif |
|
+ #ifdef PEM_R_PUBLIC_KEY_NO_RSA |
|
+ {"PUBLIC_KEY_NO_RSA", ERR_LIB_PEM, PEM_R_PUBLIC_KEY_NO_RSA}, |
|
+ #else |
|
+ {"PUBLIC_KEY_NO_RSA", ERR_LIB_PEM, 110}, |
|
+ #endif |
|
+ #ifdef PEM_R_PVK_DATA_TOO_SHORT |
|
+ {"PVK_DATA_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT}, |
|
+ #else |
|
+ {"PVK_DATA_TOO_SHORT", ERR_LIB_PEM, 124}, |
|
+ #endif |
|
+ #ifdef PEM_R_PVK_TOO_SHORT |
|
+ {"PVK_TOO_SHORT", ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT}, |
|
+ #else |
|
+ {"PVK_TOO_SHORT", ERR_LIB_PEM, 125}, |
|
+ #endif |
|
+ #ifdef PEM_R_READ_KEY |
|
+ {"READ_KEY", ERR_LIB_PEM, PEM_R_READ_KEY}, |
|
+ #else |
|
+ {"READ_KEY", ERR_LIB_PEM, 111}, |
|
+ #endif |
|
+ #ifdef PEM_R_SHORT_HEADER |
|
+ {"SHORT_HEADER", ERR_LIB_PEM, PEM_R_SHORT_HEADER}, |
|
+ #else |
|
+ {"SHORT_HEADER", ERR_LIB_PEM, 112}, |
|
+ #endif |
|
+ #ifdef PEM_R_UNSUPPORTED_CIPHER |
|
+ {"UNSUPPORTED_CIPHER", ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER}, |
|
+ #else |
|
+ {"UNSUPPORTED_CIPHER", ERR_LIB_PEM, 113}, |
|
+ #endif |
|
+ #ifdef PEM_R_UNSUPPORTED_ENCRYPTION |
|
+ {"UNSUPPORTED_ENCRYPTION", ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION}, |
|
+ #else |
|
+ {"UNSUPPORTED_ENCRYPTION", ERR_LIB_PEM, 114}, |
|
+ #endif |
|
+ #ifdef PEM_R_UNSUPPORTED_KEY_COMPONENTS |
|
+ {"UNSUPPORTED_KEY_COMPONENTS", ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS}, |
|
+ #else |
|
+ {"UNSUPPORTED_KEY_COMPONENTS", ERR_LIB_PEM, 126}, |
|
+ #endif |
|
+ #ifdef SSL_R_APP_DATA_IN_HANDSHAKE |
|
+ {"APP_DATA_IN_HANDSHAKE", ERR_LIB_SSL, SSL_R_APP_DATA_IN_HANDSHAKE}, |
|
+ #else |
|
+ {"APP_DATA_IN_HANDSHAKE", ERR_LIB_SSL, 100}, |
|
+ #endif |
|
+ #ifdef SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT |
|
+ {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", ERR_LIB_SSL, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT}, |
|
+ #else |
|
+ {"ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT", ERR_LIB_SSL, 272}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_ALERT_RECORD |
|
+ {"BAD_ALERT_RECORD", ERR_LIB_SSL, SSL_R_BAD_ALERT_RECORD}, |
|
+ #else |
|
+ {"BAD_ALERT_RECORD", ERR_LIB_SSL, 101}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_AUTHENTICATION_TYPE |
|
+ {"BAD_AUTHENTICATION_TYPE", ERR_LIB_SSL, SSL_R_BAD_AUTHENTICATION_TYPE}, |
|
+ #else |
|
+ {"BAD_AUTHENTICATION_TYPE", ERR_LIB_SSL, 102}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_CHANGE_CIPHER_SPEC |
|
+ {"BAD_CHANGE_CIPHER_SPEC", ERR_LIB_SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC}, |
|
+ #else |
|
+ {"BAD_CHANGE_CIPHER_SPEC", ERR_LIB_SSL, 103}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_CHECKSUM |
|
+ {"BAD_CHECKSUM", ERR_LIB_SSL, SSL_R_BAD_CHECKSUM}, |
|
+ #else |
|
+ {"BAD_CHECKSUM", ERR_LIB_SSL, 104}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_DATA_RETURNED_BY_CALLBACK |
|
+ {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK}, |
|
+ #else |
|
+ {"BAD_DATA_RETURNED_BY_CALLBACK", ERR_LIB_SSL, 106}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_DECOMPRESSION |
|
+ {"BAD_DECOMPRESSION", ERR_LIB_SSL, SSL_R_BAD_DECOMPRESSION}, |
|
+ #else |
|
+ {"BAD_DECOMPRESSION", ERR_LIB_SSL, 107}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_DH_G_LENGTH |
|
+ {"BAD_DH_G_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DH_G_LENGTH}, |
|
+ #else |
|
+ {"BAD_DH_G_LENGTH", ERR_LIB_SSL, 108}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_DH_PUB_KEY_LENGTH |
|
+ {"BAD_DH_PUB_KEY_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DH_PUB_KEY_LENGTH}, |
|
+ #else |
|
+ {"BAD_DH_PUB_KEY_LENGTH", ERR_LIB_SSL, 109}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_DH_P_LENGTH |
|
+ {"BAD_DH_P_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DH_P_LENGTH}, |
|
+ #else |
|
+ {"BAD_DH_P_LENGTH", ERR_LIB_SSL, 110}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_DIGEST_LENGTH |
|
+ {"BAD_DIGEST_LENGTH", ERR_LIB_SSL, SSL_R_BAD_DIGEST_LENGTH}, |
|
+ #else |
|
+ {"BAD_DIGEST_LENGTH", ERR_LIB_SSL, 111}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_DSA_SIGNATURE |
|
+ {"BAD_DSA_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_DSA_SIGNATURE}, |
|
+ #else |
|
+ {"BAD_DSA_SIGNATURE", ERR_LIB_SSL, 112}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_ECC_CERT |
|
+ {"BAD_ECC_CERT", ERR_LIB_SSL, SSL_R_BAD_ECC_CERT}, |
|
+ #else |
|
+ {"BAD_ECC_CERT", ERR_LIB_SSL, 304}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_ECDSA_SIGNATURE |
|
+ {"BAD_ECDSA_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_ECDSA_SIGNATURE}, |
|
+ #else |
|
+ {"BAD_ECDSA_SIGNATURE", ERR_LIB_SSL, 305}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_ECPOINT |
|
+ {"BAD_ECPOINT", ERR_LIB_SSL, SSL_R_BAD_ECPOINT}, |
|
+ #else |
|
+ {"BAD_ECPOINT", ERR_LIB_SSL, 306}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_HANDSHAKE_LENGTH |
|
+ {"BAD_HANDSHAKE_LENGTH", ERR_LIB_SSL, SSL_R_BAD_HANDSHAKE_LENGTH}, |
|
+ #else |
|
+ {"BAD_HANDSHAKE_LENGTH", ERR_LIB_SSL, 332}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_HELLO_REQUEST |
|
+ {"BAD_HELLO_REQUEST", ERR_LIB_SSL, SSL_R_BAD_HELLO_REQUEST}, |
|
+ #else |
|
+ {"BAD_HELLO_REQUEST", ERR_LIB_SSL, 105}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_LENGTH |
|
+ {"BAD_LENGTH", ERR_LIB_SSL, SSL_R_BAD_LENGTH}, |
|
+ #else |
|
+ {"BAD_LENGTH", ERR_LIB_SSL, 271}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_MAC_DECODE |
|
+ {"BAD_MAC_DECODE", ERR_LIB_SSL, SSL_R_BAD_MAC_DECODE}, |
|
+ #else |
|
+ {"BAD_MAC_DECODE", ERR_LIB_SSL, 113}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_MAC_LENGTH |
|
+ {"BAD_MAC_LENGTH", ERR_LIB_SSL, SSL_R_BAD_MAC_LENGTH}, |
|
+ #else |
|
+ {"BAD_MAC_LENGTH", ERR_LIB_SSL, 333}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_MESSAGE_TYPE |
|
+ {"BAD_MESSAGE_TYPE", ERR_LIB_SSL, SSL_R_BAD_MESSAGE_TYPE}, |
|
+ #else |
|
+ {"BAD_MESSAGE_TYPE", ERR_LIB_SSL, 114}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_PACKET_LENGTH |
|
+ {"BAD_PACKET_LENGTH", ERR_LIB_SSL, SSL_R_BAD_PACKET_LENGTH}, |
|
+ #else |
|
+ {"BAD_PACKET_LENGTH", ERR_LIB_SSL, 115}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_PROTOCOL_VERSION_NUMBER |
|
+ {"BAD_PROTOCOL_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_BAD_PROTOCOL_VERSION_NUMBER}, |
|
+ #else |
|
+ {"BAD_PROTOCOL_VERSION_NUMBER", ERR_LIB_SSL, 116}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH |
|
+ {"BAD_PSK_IDENTITY_HINT_LENGTH", ERR_LIB_SSL, SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH}, |
|
+ #else |
|
+ {"BAD_PSK_IDENTITY_HINT_LENGTH", ERR_LIB_SSL, 316}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_RESPONSE_ARGUMENT |
|
+ {"BAD_RESPONSE_ARGUMENT", ERR_LIB_SSL, SSL_R_BAD_RESPONSE_ARGUMENT}, |
|
+ #else |
|
+ {"BAD_RESPONSE_ARGUMENT", ERR_LIB_SSL, 117}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_RSA_DECRYPT |
|
+ {"BAD_RSA_DECRYPT", ERR_LIB_SSL, SSL_R_BAD_RSA_DECRYPT}, |
|
+ #else |
|
+ {"BAD_RSA_DECRYPT", ERR_LIB_SSL, 118}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_RSA_ENCRYPT |
|
+ {"BAD_RSA_ENCRYPT", ERR_LIB_SSL, SSL_R_BAD_RSA_ENCRYPT}, |
|
+ #else |
|
+ {"BAD_RSA_ENCRYPT", ERR_LIB_SSL, 119}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_RSA_E_LENGTH |
|
+ {"BAD_RSA_E_LENGTH", ERR_LIB_SSL, SSL_R_BAD_RSA_E_LENGTH}, |
|
+ #else |
|
+ {"BAD_RSA_E_LENGTH", ERR_LIB_SSL, 120}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_RSA_MODULUS_LENGTH |
|
+ {"BAD_RSA_MODULUS_LENGTH", ERR_LIB_SSL, SSL_R_BAD_RSA_MODULUS_LENGTH}, |
|
+ #else |
|
+ {"BAD_RSA_MODULUS_LENGTH", ERR_LIB_SSL, 121}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_RSA_SIGNATURE |
|
+ {"BAD_RSA_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_RSA_SIGNATURE}, |
|
+ #else |
|
+ {"BAD_RSA_SIGNATURE", ERR_LIB_SSL, 122}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_SIGNATURE |
|
+ {"BAD_SIGNATURE", ERR_LIB_SSL, SSL_R_BAD_SIGNATURE}, |
|
+ #else |
|
+ {"BAD_SIGNATURE", ERR_LIB_SSL, 123}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_SSL_FILETYPE |
|
+ {"BAD_SSL_FILETYPE", ERR_LIB_SSL, SSL_R_BAD_SSL_FILETYPE}, |
|
+ #else |
|
+ {"BAD_SSL_FILETYPE", ERR_LIB_SSL, 124}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_SSL_SESSION_ID_LENGTH |
|
+ {"BAD_SSL_SESSION_ID_LENGTH", ERR_LIB_SSL, SSL_R_BAD_SSL_SESSION_ID_LENGTH}, |
|
+ #else |
|
+ {"BAD_SSL_SESSION_ID_LENGTH", ERR_LIB_SSL, 125}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_STATE |
|
+ {"BAD_STATE", ERR_LIB_SSL, SSL_R_BAD_STATE}, |
|
+ #else |
|
+ {"BAD_STATE", ERR_LIB_SSL, 126}, |
|
+ #endif |
|
+ #ifdef SSL_R_BAD_WRITE_RETRY |
|
+ {"BAD_WRITE_RETRY", ERR_LIB_SSL, SSL_R_BAD_WRITE_RETRY}, |
|
+ #else |
|
+ {"BAD_WRITE_RETRY", ERR_LIB_SSL, 127}, |
|
+ #endif |
|
+ #ifdef SSL_R_BIO_NOT_SET |
|
+ {"BIO_NOT_SET", ERR_LIB_SSL, SSL_R_BIO_NOT_SET}, |
|
+ #else |
|
+ {"BIO_NOT_SET", ERR_LIB_SSL, 128}, |
|
+ #endif |
|
+ #ifdef SSL_R_BLOCK_CIPHER_PAD_IS_WRONG |
|
+ {"BLOCK_CIPHER_PAD_IS_WRONG", ERR_LIB_SSL, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG}, |
|
+ #else |
|
+ {"BLOCK_CIPHER_PAD_IS_WRONG", ERR_LIB_SSL, 129}, |
|
+ #endif |
|
+ #ifdef SSL_R_BN_LIB |
|
+ {"BN_LIB", ERR_LIB_SSL, SSL_R_BN_LIB}, |
|
+ #else |
|
+ {"BN_LIB", ERR_LIB_SSL, 130}, |
|
+ #endif |
|
+ #ifdef SSL_R_CA_DN_LENGTH_MISMATCH |
|
+ {"CA_DN_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CA_DN_LENGTH_MISMATCH}, |
|
+ #else |
|
+ {"CA_DN_LENGTH_MISMATCH", ERR_LIB_SSL, 131}, |
|
+ #endif |
|
+ #ifdef SSL_R_CA_DN_TOO_LONG |
|
+ {"CA_DN_TOO_LONG", ERR_LIB_SSL, SSL_R_CA_DN_TOO_LONG}, |
|
+ #else |
|
+ {"CA_DN_TOO_LONG", ERR_LIB_SSL, 132}, |
|
+ #endif |
|
+ #ifdef SSL_R_CCS_RECEIVED_EARLY |
|
+ {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, SSL_R_CCS_RECEIVED_EARLY}, |
|
+ #else |
|
+ {"CCS_RECEIVED_EARLY", ERR_LIB_SSL, 133}, |
|
+ #endif |
|
+ #ifdef SSL_R_CERTIFICATE_VERIFY_FAILED |
|
+ {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED}, |
|
+ #else |
|
+ {"CERTIFICATE_VERIFY_FAILED", ERR_LIB_SSL, 134}, |
|
+ #endif |
|
+ #ifdef SSL_R_CERT_LENGTH_MISMATCH |
|
+ {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_CERT_LENGTH_MISMATCH}, |
|
+ #else |
|
+ {"CERT_LENGTH_MISMATCH", ERR_LIB_SSL, 135}, |
|
+ #endif |
|
+ #ifdef SSL_R_CHALLENGE_IS_DIFFERENT |
|
+ {"CHALLENGE_IS_DIFFERENT", ERR_LIB_SSL, SSL_R_CHALLENGE_IS_DIFFERENT}, |
|
+ #else |
|
+ {"CHALLENGE_IS_DIFFERENT", ERR_LIB_SSL, 136}, |
|
+ #endif |
|
+ #ifdef SSL_R_CIPHER_CODE_WRONG_LENGTH |
|
+ {"CIPHER_CODE_WRONG_LENGTH", ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH}, |
|
+ #else |
|
+ {"CIPHER_CODE_WRONG_LENGTH", ERR_LIB_SSL, 137}, |
|
+ #endif |
|
+ #ifdef SSL_R_CIPHER_OR_HASH_UNAVAILABLE |
|
+ {"CIPHER_OR_HASH_UNAVAILABLE", ERR_LIB_SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE}, |
|
+ #else |
|
+ {"CIPHER_OR_HASH_UNAVAILABLE", ERR_LIB_SSL, 138}, |
|
+ #endif |
|
+ #ifdef SSL_R_CIPHER_TABLE_SRC_ERROR |
|
+ {"CIPHER_TABLE_SRC_ERROR", ERR_LIB_SSL, SSL_R_CIPHER_TABLE_SRC_ERROR}, |
|
+ #else |
|
+ {"CIPHER_TABLE_SRC_ERROR", ERR_LIB_SSL, 139}, |
|
+ #endif |
|
+ #ifdef SSL_R_CLIENTHELLO_TLSEXT |
|
+ {"CLIENTHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_CLIENTHELLO_TLSEXT}, |
|
+ #else |
|
+ {"CLIENTHELLO_TLSEXT", ERR_LIB_SSL, 226}, |
|
+ #endif |
|
+ #ifdef SSL_R_COMPRESSED_LENGTH_TOO_LONG |
|
+ {"COMPRESSED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_COMPRESSED_LENGTH_TOO_LONG}, |
|
+ #else |
|
+ {"COMPRESSED_LENGTH_TOO_LONG", ERR_LIB_SSL, 140}, |
|
+ #endif |
|
+ #ifdef SSL_R_COMPRESSION_DISABLED |
|
+ {"COMPRESSION_DISABLED", ERR_LIB_SSL, SSL_R_COMPRESSION_DISABLED}, |
|
+ #else |
|
+ {"COMPRESSION_DISABLED", ERR_LIB_SSL, 343}, |
|
+ #endif |
|
+ #ifdef SSL_R_COMPRESSION_FAILURE |
|
+ {"COMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_COMPRESSION_FAILURE}, |
|
+ #else |
|
+ {"COMPRESSION_FAILURE", ERR_LIB_SSL, 141}, |
|
+ #endif |
|
+ #ifdef SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE |
|
+ {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", ERR_LIB_SSL, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE}, |
|
+ #else |
|
+ {"COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE", ERR_LIB_SSL, 307}, |
|
+ #endif |
|
+ #ifdef SSL_R_COMPRESSION_LIBRARY_ERROR |
|
+ {"COMPRESSION_LIBRARY_ERROR", ERR_LIB_SSL, SSL_R_COMPRESSION_LIBRARY_ERROR}, |
|
+ #else |
|
+ {"COMPRESSION_LIBRARY_ERROR", ERR_LIB_SSL, 142}, |
|
+ #endif |
|
+ #ifdef SSL_R_CONNECTION_ID_IS_DIFFERENT |
|
+ {"CONNECTION_ID_IS_DIFFERENT", ERR_LIB_SSL, SSL_R_CONNECTION_ID_IS_DIFFERENT}, |
|
+ #else |
|
+ {"CONNECTION_ID_IS_DIFFERENT", ERR_LIB_SSL, 143}, |
|
+ #endif |
|
+ #ifdef SSL_R_CONNECTION_TYPE_NOT_SET |
|
+ {"CONNECTION_TYPE_NOT_SET", ERR_LIB_SSL, SSL_R_CONNECTION_TYPE_NOT_SET}, |
|
+ #else |
|
+ {"CONNECTION_TYPE_NOT_SET", ERR_LIB_SSL, 144}, |
|
+ #endif |
|
+ #ifdef SSL_R_COOKIE_MISMATCH |
|
+ {"COOKIE_MISMATCH", ERR_LIB_SSL, SSL_R_COOKIE_MISMATCH}, |
|
+ #else |
|
+ {"COOKIE_MISMATCH", ERR_LIB_SSL, 308}, |
|
+ #endif |
|
+ #ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED |
|
+ {"DATA_BETWEEN_CCS_AND_FINISHED", ERR_LIB_SSL, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED}, |
|
+ #else |
|
+ {"DATA_BETWEEN_CCS_AND_FINISHED", ERR_LIB_SSL, 145}, |
|
+ #endif |
|
+ #ifdef SSL_R_DATA_LENGTH_TOO_LONG |
|
+ {"DATA_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_DATA_LENGTH_TOO_LONG}, |
|
+ #else |
|
+ {"DATA_LENGTH_TOO_LONG", ERR_LIB_SSL, 146}, |
|
+ #endif |
|
+ #ifdef SSL_R_DECRYPTION_FAILED |
|
+ {"DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED}, |
|
+ #else |
|
+ {"DECRYPTION_FAILED", ERR_LIB_SSL, 147}, |
|
+ #endif |
|
+ #ifdef SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC |
|
+ {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC}, |
|
+ #else |
|
+ {"DECRYPTION_FAILED_OR_BAD_RECORD_MAC", ERR_LIB_SSL, 281}, |
|
+ #endif |
|
+ #ifdef SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG |
|
+ {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG}, |
|
+ #else |
|
+ {"DH_PUBLIC_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, 148}, |
|
+ #endif |
|
+ #ifdef SSL_R_DIGEST_CHECK_FAILED |
|
+ {"DIGEST_CHECK_FAILED", ERR_LIB_SSL, SSL_R_DIGEST_CHECK_FAILED}, |
|
+ #else |
|
+ {"DIGEST_CHECK_FAILED", ERR_LIB_SSL, 149}, |
|
+ #endif |
|
+ #ifdef SSL_R_DTLS_MESSAGE_TOO_BIG |
|
+ {"DTLS_MESSAGE_TOO_BIG", ERR_LIB_SSL, SSL_R_DTLS_MESSAGE_TOO_BIG}, |
|
+ #else |
|
+ {"DTLS_MESSAGE_TOO_BIG", ERR_LIB_SSL, 334}, |
|
+ #endif |
|
+ #ifdef SSL_R_DUPLICATE_COMPRESSION_ID |
|
+ {"DUPLICATE_COMPRESSION_ID", ERR_LIB_SSL, SSL_R_DUPLICATE_COMPRESSION_ID}, |
|
+ #else |
|
+ {"DUPLICATE_COMPRESSION_ID", ERR_LIB_SSL, 309}, |
|
+ #endif |
|
+ #ifdef SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT |
|
+ {"ECC_CERT_NOT_FOR_KEY_AGREEMENT", ERR_LIB_SSL, SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT}, |
|
+ #else |
|
+ {"ECC_CERT_NOT_FOR_KEY_AGREEMENT", ERR_LIB_SSL, 317}, |
|
+ #endif |
|
+ #ifdef SSL_R_ECC_CERT_NOT_FOR_SIGNING |
|
+ {"ECC_CERT_NOT_FOR_SIGNING", ERR_LIB_SSL, SSL_R_ECC_CERT_NOT_FOR_SIGNING}, |
|
+ #else |
|
+ {"ECC_CERT_NOT_FOR_SIGNING", ERR_LIB_SSL, 318}, |
|
+ #endif |
|
+ #ifdef SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE |
|
+ {"ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE", ERR_LIB_SSL, SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE}, |
|
+ #else |
|
+ {"ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE", ERR_LIB_SSL, 322}, |
|
+ #endif |
|
+ #ifdef SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE |
|
+ {"ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE", ERR_LIB_SSL, SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE}, |
|
+ #else |
|
+ {"ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE", ERR_LIB_SSL, 323}, |
|
+ #endif |
|
+ #ifdef SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER |
|
+ {"ECGROUP_TOO_LARGE_FOR_CIPHER", ERR_LIB_SSL, SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER}, |
|
+ #else |
|
+ {"ECGROUP_TOO_LARGE_FOR_CIPHER", ERR_LIB_SSL, 310}, |
|
+ #endif |
|
+ #ifdef SSL_R_ENCRYPTED_LENGTH_TOO_LONG |
|
+ {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_ENCRYPTED_LENGTH_TOO_LONG}, |
|
+ #else |
|
+ {"ENCRYPTED_LENGTH_TOO_LONG", ERR_LIB_SSL, 150}, |
|
+ #endif |
|
+ #ifdef SSL_R_ERROR_GENERATING_TMP_RSA_KEY |
|
+ {"ERROR_GENERATING_TMP_RSA_KEY", ERR_LIB_SSL, SSL_R_ERROR_GENERATING_TMP_RSA_KEY}, |
|
+ #else |
|
+ {"ERROR_GENERATING_TMP_RSA_KEY", ERR_LIB_SSL, 282}, |
|
+ #endif |
|
+ #ifdef SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST |
|
+ {"ERROR_IN_RECEIVED_CIPHER_LIST", ERR_LIB_SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST}, |
|
+ #else |
|
+ {"ERROR_IN_RECEIVED_CIPHER_LIST", ERR_LIB_SSL, 151}, |
|
+ #endif |
|
+ #ifdef SSL_R_EXCESSIVE_MESSAGE_SIZE |
|
+ {"EXCESSIVE_MESSAGE_SIZE", ERR_LIB_SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE}, |
|
+ #else |
|
+ {"EXCESSIVE_MESSAGE_SIZE", ERR_LIB_SSL, 152}, |
|
+ #endif |
|
+ #ifdef SSL_R_EXTRA_DATA_IN_MESSAGE |
|
+ {"EXTRA_DATA_IN_MESSAGE", ERR_LIB_SSL, SSL_R_EXTRA_DATA_IN_MESSAGE}, |
|
+ #else |
|
+ {"EXTRA_DATA_IN_MESSAGE", ERR_LIB_SSL, 153}, |
|
+ #endif |
|
+ #ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS |
|
+ {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, SSL_R_GOT_A_FIN_BEFORE_A_CCS}, |
|
+ #else |
|
+ {"GOT_A_FIN_BEFORE_A_CCS", ERR_LIB_SSL, 154}, |
|
+ #endif |
|
+ #ifdef SSL_R_HTTPS_PROXY_REQUEST |
|
+ {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, SSL_R_HTTPS_PROXY_REQUEST}, |
|
+ #else |
|
+ {"HTTPS_PROXY_REQUEST", ERR_LIB_SSL, 155}, |
|
+ #endif |
|
+ #ifdef SSL_R_HTTP_REQUEST |
|
+ {"HTTP_REQUEST", ERR_LIB_SSL, SSL_R_HTTP_REQUEST}, |
|
+ #else |
|
+ {"HTTP_REQUEST", ERR_LIB_SSL, 156}, |
|
+ #endif |
|
+ #ifdef SSL_R_ILLEGAL_PADDING |
|
+ {"ILLEGAL_PADDING", ERR_LIB_SSL, SSL_R_ILLEGAL_PADDING}, |
|
+ #else |
|
+ {"ILLEGAL_PADDING", ERR_LIB_SSL, 283}, |
|
+ #endif |
|
+ #ifdef SSL_R_INCONSISTENT_COMPRESSION |
|
+ {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, SSL_R_INCONSISTENT_COMPRESSION}, |
|
+ #else |
|
+ {"INCONSISTENT_COMPRESSION", ERR_LIB_SSL, 340}, |
|
+ #endif |
|
+ #ifdef SSL_R_INVALID_CHALLENGE_LENGTH |
|
+ {"INVALID_CHALLENGE_LENGTH", ERR_LIB_SSL, SSL_R_INVALID_CHALLENGE_LENGTH}, |
|
+ #else |
|
+ {"INVALID_CHALLENGE_LENGTH", ERR_LIB_SSL, 158}, |
|
+ #endif |
|
+ #ifdef SSL_R_INVALID_COMMAND |
|
+ {"INVALID_COMMAND", ERR_LIB_SSL, SSL_R_INVALID_COMMAND}, |
|
+ #else |
|
+ {"INVALID_COMMAND", ERR_LIB_SSL, 280}, |
|
+ #endif |
|
+ #ifdef SSL_R_INVALID_COMPRESSION_ALGORITHM |
|
+ {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_INVALID_COMPRESSION_ALGORITHM}, |
|
+ #else |
|
+ {"INVALID_COMPRESSION_ALGORITHM", ERR_LIB_SSL, 341}, |
|
+ #endif |
|
+ #ifdef SSL_R_INVALID_PURPOSE |
|
+ {"INVALID_PURPOSE", ERR_LIB_SSL, SSL_R_INVALID_PURPOSE}, |
|
+ #else |
|
+ {"INVALID_PURPOSE", ERR_LIB_SSL, 278}, |
|
+ #endif |
|
+ #ifdef SSL_R_INVALID_STATUS_RESPONSE |
|
+ {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_INVALID_STATUS_RESPONSE}, |
|
+ #else |
|
+ {"INVALID_STATUS_RESPONSE", ERR_LIB_SSL, 328}, |
|
+ #endif |
|
+ #ifdef SSL_R_INVALID_TICKET_KEYS_LENGTH |
|
+ {"INVALID_TICKET_KEYS_LENGTH", ERR_LIB_SSL, SSL_R_INVALID_TICKET_KEYS_LENGTH}, |
|
+ #else |
|
+ {"INVALID_TICKET_KEYS_LENGTH", ERR_LIB_SSL, 325}, |
|
+ #endif |
|
+ #ifdef SSL_R_INVALID_TRUST |
|
+ {"INVALID_TRUST", ERR_LIB_SSL, SSL_R_INVALID_TRUST}, |
|
+ #else |
|
+ {"INVALID_TRUST", ERR_LIB_SSL, 279}, |
|
+ #endif |
|
+ #ifdef SSL_R_KEY_ARG_TOO_LONG |
|
+ {"KEY_ARG_TOO_LONG", ERR_LIB_SSL, SSL_R_KEY_ARG_TOO_LONG}, |
|
+ #else |
|
+ {"KEY_ARG_TOO_LONG", ERR_LIB_SSL, 284}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5 |
|
+ {"KRB5", ERR_LIB_SSL, SSL_R_KRB5}, |
|
+ #else |
|
+ {"KRB5", ERR_LIB_SSL, 285}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_C_CC_PRINC |
|
+ {"KRB5_C_CC_PRINC", ERR_LIB_SSL, SSL_R_KRB5_C_CC_PRINC}, |
|
+ #else |
|
+ {"KRB5_C_CC_PRINC", ERR_LIB_SSL, 286}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_C_GET_CRED |
|
+ {"KRB5_C_GET_CRED", ERR_LIB_SSL, SSL_R_KRB5_C_GET_CRED}, |
|
+ #else |
|
+ {"KRB5_C_GET_CRED", ERR_LIB_SSL, 287}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_C_INIT |
|
+ {"KRB5_C_INIT", ERR_LIB_SSL, SSL_R_KRB5_C_INIT}, |
|
+ #else |
|
+ {"KRB5_C_INIT", ERR_LIB_SSL, 288}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_C_MK_REQ |
|
+ {"KRB5_C_MK_REQ", ERR_LIB_SSL, SSL_R_KRB5_C_MK_REQ}, |
|
+ #else |
|
+ {"KRB5_C_MK_REQ", ERR_LIB_SSL, 289}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_S_BAD_TICKET |
|
+ {"KRB5_S_BAD_TICKET", ERR_LIB_SSL, SSL_R_KRB5_S_BAD_TICKET}, |
|
+ #else |
|
+ {"KRB5_S_BAD_TICKET", ERR_LIB_SSL, 290}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_S_INIT |
|
+ {"KRB5_S_INIT", ERR_LIB_SSL, SSL_R_KRB5_S_INIT}, |
|
+ #else |
|
+ {"KRB5_S_INIT", ERR_LIB_SSL, 291}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_S_RD_REQ |
|
+ {"KRB5_S_RD_REQ", ERR_LIB_SSL, SSL_R_KRB5_S_RD_REQ}, |
|
+ #else |
|
+ {"KRB5_S_RD_REQ", ERR_LIB_SSL, 292}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_S_TKT_EXPIRED |
|
+ {"KRB5_S_TKT_EXPIRED", ERR_LIB_SSL, SSL_R_KRB5_S_TKT_EXPIRED}, |
|
+ #else |
|
+ {"KRB5_S_TKT_EXPIRED", ERR_LIB_SSL, 293}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_S_TKT_NYV |
|
+ {"KRB5_S_TKT_NYV", ERR_LIB_SSL, SSL_R_KRB5_S_TKT_NYV}, |
|
+ #else |
|
+ {"KRB5_S_TKT_NYV", ERR_LIB_SSL, 294}, |
|
+ #endif |
|
+ #ifdef SSL_R_KRB5_S_TKT_SKEW |
|
+ {"KRB5_S_TKT_SKEW", ERR_LIB_SSL, SSL_R_KRB5_S_TKT_SKEW}, |
|
+ #else |
|
+ {"KRB5_S_TKT_SKEW", ERR_LIB_SSL, 295}, |
|
+ #endif |
|
+ #ifdef SSL_R_LENGTH_MISMATCH |
|
+ {"LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_LENGTH_MISMATCH}, |
|
+ #else |
|
+ {"LENGTH_MISMATCH", ERR_LIB_SSL, 159}, |
|
+ #endif |
|
+ #ifdef SSL_R_LENGTH_TOO_SHORT |
|
+ {"LENGTH_TOO_SHORT", ERR_LIB_SSL, SSL_R_LENGTH_TOO_SHORT}, |
|
+ #else |
|
+ {"LENGTH_TOO_SHORT", ERR_LIB_SSL, 160}, |
|
+ #endif |
|
+ #ifdef SSL_R_LIBRARY_BUG |
|
+ {"LIBRARY_BUG", ERR_LIB_SSL, SSL_R_LIBRARY_BUG}, |
|
+ #else |
|
+ {"LIBRARY_BUG", ERR_LIB_SSL, 274}, |
|
+ #endif |
|
+ #ifdef SSL_R_LIBRARY_HAS_NO_CIPHERS |
|
+ {"LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS}, |
|
+ #else |
|
+ {"LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, 161}, |
|
+ #endif |
|
+ #ifdef SSL_R_MESSAGE_TOO_LONG |
|
+ {"MESSAGE_TOO_LONG", ERR_LIB_SSL, SSL_R_MESSAGE_TOO_LONG}, |
|
+ #else |
|
+ {"MESSAGE_TOO_LONG", ERR_LIB_SSL, 296}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_DH_DSA_CERT |
|
+ {"MISSING_DH_DSA_CERT", ERR_LIB_SSL, SSL_R_MISSING_DH_DSA_CERT}, |
|
+ #else |
|
+ {"MISSING_DH_DSA_CERT", ERR_LIB_SSL, 162}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_DH_KEY |
|
+ {"MISSING_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_DH_KEY}, |
|
+ #else |
|
+ {"MISSING_DH_KEY", ERR_LIB_SSL, 163}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_DH_RSA_CERT |
|
+ {"MISSING_DH_RSA_CERT", ERR_LIB_SSL, SSL_R_MISSING_DH_RSA_CERT}, |
|
+ #else |
|
+ {"MISSING_DH_RSA_CERT", ERR_LIB_SSL, 164}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_DSA_SIGNING_CERT |
|
+ {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_DSA_SIGNING_CERT}, |
|
+ #else |
|
+ {"MISSING_DSA_SIGNING_CERT", ERR_LIB_SSL, 165}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_EXPORT_TMP_DH_KEY |
|
+ {"MISSING_EXPORT_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_EXPORT_TMP_DH_KEY}, |
|
+ #else |
|
+ {"MISSING_EXPORT_TMP_DH_KEY", ERR_LIB_SSL, 166}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_EXPORT_TMP_RSA_KEY |
|
+ {"MISSING_EXPORT_TMP_RSA_KEY", ERR_LIB_SSL, SSL_R_MISSING_EXPORT_TMP_RSA_KEY}, |
|
+ #else |
|
+ {"MISSING_EXPORT_TMP_RSA_KEY", ERR_LIB_SSL, 167}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_RSA_CERTIFICATE |
|
+ {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, SSL_R_MISSING_RSA_CERTIFICATE}, |
|
+ #else |
|
+ {"MISSING_RSA_CERTIFICATE", ERR_LIB_SSL, 168}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_RSA_ENCRYPTING_CERT |
|
+ {"MISSING_RSA_ENCRYPTING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_ENCRYPTING_CERT}, |
|
+ #else |
|
+ {"MISSING_RSA_ENCRYPTING_CERT", ERR_LIB_SSL, 169}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_RSA_SIGNING_CERT |
|
+ {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, SSL_R_MISSING_RSA_SIGNING_CERT}, |
|
+ #else |
|
+ {"MISSING_RSA_SIGNING_CERT", ERR_LIB_SSL, 170}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_TMP_DH_KEY |
|
+ {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_DH_KEY}, |
|
+ #else |
|
+ {"MISSING_TMP_DH_KEY", ERR_LIB_SSL, 171}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_TMP_ECDH_KEY |
|
+ {"MISSING_TMP_ECDH_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_ECDH_KEY}, |
|
+ #else |
|
+ {"MISSING_TMP_ECDH_KEY", ERR_LIB_SSL, 311}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_TMP_RSA_KEY |
|
+ {"MISSING_TMP_RSA_KEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_RSA_KEY}, |
|
+ #else |
|
+ {"MISSING_TMP_RSA_KEY", ERR_LIB_SSL, 172}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_TMP_RSA_PKEY |
|
+ {"MISSING_TMP_RSA_PKEY", ERR_LIB_SSL, SSL_R_MISSING_TMP_RSA_PKEY}, |
|
+ #else |
|
+ {"MISSING_TMP_RSA_PKEY", ERR_LIB_SSL, 173}, |
|
+ #endif |
|
+ #ifdef SSL_R_MISSING_VERIFY_MESSAGE |
|
+ {"MISSING_VERIFY_MESSAGE", ERR_LIB_SSL, SSL_R_MISSING_VERIFY_MESSAGE}, |
|
+ #else |
|
+ {"MISSING_VERIFY_MESSAGE", ERR_LIB_SSL, 174}, |
|
+ #endif |
|
+ #ifdef SSL_R_NON_SSLV2_INITIAL_PACKET |
|
+ {"NON_SSLV2_INITIAL_PACKET", ERR_LIB_SSL, SSL_R_NON_SSLV2_INITIAL_PACKET}, |
|
+ #else |
|
+ {"NON_SSLV2_INITIAL_PACKET", ERR_LIB_SSL, 175}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CERTIFICATES_RETURNED |
|
+ {"NO_CERTIFICATES_RETURNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATES_RETURNED}, |
|
+ #else |
|
+ {"NO_CERTIFICATES_RETURNED", ERR_LIB_SSL, 176}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CERTIFICATE_ASSIGNED |
|
+ {"NO_CERTIFICATE_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_ASSIGNED}, |
|
+ #else |
|
+ {"NO_CERTIFICATE_ASSIGNED", ERR_LIB_SSL, 177}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CERTIFICATE_RETURNED |
|
+ {"NO_CERTIFICATE_RETURNED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_RETURNED}, |
|
+ #else |
|
+ {"NO_CERTIFICATE_RETURNED", ERR_LIB_SSL, 178}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CERTIFICATE_SET |
|
+ {"NO_CERTIFICATE_SET", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET}, |
|
+ #else |
|
+ {"NO_CERTIFICATE_SET", ERR_LIB_SSL, 179}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CERTIFICATE_SPECIFIED |
|
+ {"NO_CERTIFICATE_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SPECIFIED}, |
|
+ #else |
|
+ {"NO_CERTIFICATE_SPECIFIED", ERR_LIB_SSL, 180}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CIPHERS_AVAILABLE |
|
+ {"NO_CIPHERS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_CIPHERS_AVAILABLE}, |
|
+ #else |
|
+ {"NO_CIPHERS_AVAILABLE", ERR_LIB_SSL, 181}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CIPHERS_PASSED |
|
+ {"NO_CIPHERS_PASSED", ERR_LIB_SSL, SSL_R_NO_CIPHERS_PASSED}, |
|
+ #else |
|
+ {"NO_CIPHERS_PASSED", ERR_LIB_SSL, 182}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CIPHERS_SPECIFIED |
|
+ {"NO_CIPHERS_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_CIPHERS_SPECIFIED}, |
|
+ #else |
|
+ {"NO_CIPHERS_SPECIFIED", ERR_LIB_SSL, 183}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CIPHER_LIST |
|
+ {"NO_CIPHER_LIST", ERR_LIB_SSL, SSL_R_NO_CIPHER_LIST}, |
|
+ #else |
|
+ {"NO_CIPHER_LIST", ERR_LIB_SSL, 184}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CIPHER_MATCH |
|
+ {"NO_CIPHER_MATCH", ERR_LIB_SSL, SSL_R_NO_CIPHER_MATCH}, |
|
+ #else |
|
+ {"NO_CIPHER_MATCH", ERR_LIB_SSL, 185}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CLIENT_CERT_METHOD |
|
+ {"NO_CLIENT_CERT_METHOD", ERR_LIB_SSL, SSL_R_NO_CLIENT_CERT_METHOD}, |
|
+ #else |
|
+ {"NO_CLIENT_CERT_METHOD", ERR_LIB_SSL, 331}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_CLIENT_CERT_RECEIVED |
|
+ {"NO_CLIENT_CERT_RECEIVED", ERR_LIB_SSL, SSL_R_NO_CLIENT_CERT_RECEIVED}, |
|
+ #else |
|
+ {"NO_CLIENT_CERT_RECEIVED", ERR_LIB_SSL, 186}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_COMPRESSION_SPECIFIED |
|
+ {"NO_COMPRESSION_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_COMPRESSION_SPECIFIED}, |
|
+ #else |
|
+ {"NO_COMPRESSION_SPECIFIED", ERR_LIB_SSL, 187}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER |
|
+ {"NO_GOST_CERTIFICATE_SENT_BY_PEER", ERR_LIB_SSL, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER}, |
|
+ #else |
|
+ {"NO_GOST_CERTIFICATE_SENT_BY_PEER", ERR_LIB_SSL, 330}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_METHOD_SPECIFIED |
|
+ {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, SSL_R_NO_METHOD_SPECIFIED}, |
|
+ #else |
|
+ {"NO_METHOD_SPECIFIED", ERR_LIB_SSL, 188}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_PRIVATEKEY |
|
+ {"NO_PRIVATEKEY", ERR_LIB_SSL, SSL_R_NO_PRIVATEKEY}, |
|
+ #else |
|
+ {"NO_PRIVATEKEY", ERR_LIB_SSL, 189}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_PRIVATE_KEY_ASSIGNED |
|
+ {"NO_PRIVATE_KEY_ASSIGNED", ERR_LIB_SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED}, |
|
+ #else |
|
+ {"NO_PRIVATE_KEY_ASSIGNED", ERR_LIB_SSL, 190}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_PROTOCOLS_AVAILABLE |
|
+ {"NO_PROTOCOLS_AVAILABLE", ERR_LIB_SSL, SSL_R_NO_PROTOCOLS_AVAILABLE}, |
|
+ #else |
|
+ {"NO_PROTOCOLS_AVAILABLE", ERR_LIB_SSL, 191}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_PUBLICKEY |
|
+ {"NO_PUBLICKEY", ERR_LIB_SSL, SSL_R_NO_PUBLICKEY}, |
|
+ #else |
|
+ {"NO_PUBLICKEY", ERR_LIB_SSL, 192}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_RENEGOTIATION |
|
+ {"NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_NO_RENEGOTIATION}, |
|
+ #else |
|
+ {"NO_RENEGOTIATION", ERR_LIB_SSL, 339}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_REQUIRED_DIGEST |
|
+ {"NO_REQUIRED_DIGEST", ERR_LIB_SSL, SSL_R_NO_REQUIRED_DIGEST}, |
|
+ #else |
|
+ {"NO_REQUIRED_DIGEST", ERR_LIB_SSL, 324}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_SHARED_CIPHER |
|
+ {"NO_SHARED_CIPHER", ERR_LIB_SSL, SSL_R_NO_SHARED_CIPHER}, |
|
+ #else |
|
+ {"NO_SHARED_CIPHER", ERR_LIB_SSL, 193}, |
|
+ #endif |
|
+ #ifdef SSL_R_NO_VERIFY_CALLBACK |
|
+ {"NO_VERIFY_CALLBACK", ERR_LIB_SSL, SSL_R_NO_VERIFY_CALLBACK}, |
|
+ #else |
|
+ {"NO_VERIFY_CALLBACK", ERR_LIB_SSL, 194}, |
|
+ #endif |
|
+ #ifdef SSL_R_NULL_SSL_CTX |
|
+ {"NULL_SSL_CTX", ERR_LIB_SSL, SSL_R_NULL_SSL_CTX}, |
|
+ #else |
|
+ {"NULL_SSL_CTX", ERR_LIB_SSL, 195}, |
|
+ #endif |
|
+ #ifdef SSL_R_NULL_SSL_METHOD_PASSED |
|
+ {"NULL_SSL_METHOD_PASSED", ERR_LIB_SSL, SSL_R_NULL_SSL_METHOD_PASSED}, |
|
+ #else |
|
+ {"NULL_SSL_METHOD_PASSED", ERR_LIB_SSL, 196}, |
|
+ #endif |
|
+ #ifdef SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED |
|
+ {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED}, |
|
+ #else |
|
+ {"OLD_SESSION_CIPHER_NOT_RETURNED", ERR_LIB_SSL, 197}, |
|
+ #endif |
|
+ #ifdef SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED |
|
+ {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED}, |
|
+ #else |
|
+ {"OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED", ERR_LIB_SSL, 344}, |
|
+ #endif |
|
+ #ifdef SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE |
|
+ {"ONLY_TLS_ALLOWED_IN_FIPS_MODE", ERR_LIB_SSL, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE}, |
|
+ #else |
|
+ {"ONLY_TLS_ALLOWED_IN_FIPS_MODE", ERR_LIB_SSL, 297}, |
|
+ #endif |
|
+ #ifdef SSL_R_OPAQUE_PRF_INPUT_TOO_LONG |
|
+ {"OPAQUE_PRF_INPUT_TOO_LONG", ERR_LIB_SSL, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG}, |
|
+ #else |
|
+ {"OPAQUE_PRF_INPUT_TOO_LONG", ERR_LIB_SSL, 327}, |
|
+ #endif |
|
+ #ifdef SSL_R_PACKET_LENGTH_TOO_LONG |
|
+ {"PACKET_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PACKET_LENGTH_TOO_LONG}, |
|
+ #else |
|
+ {"PACKET_LENGTH_TOO_LONG", ERR_LIB_SSL, 198}, |
|
+ #endif |
|
+ #ifdef SSL_R_PARSE_TLSEXT |
|
+ {"PARSE_TLSEXT", ERR_LIB_SSL, SSL_R_PARSE_TLSEXT}, |
|
+ #else |
|
+ {"PARSE_TLSEXT", ERR_LIB_SSL, 227}, |
|
+ #endif |
|
+ #ifdef SSL_R_PATH_TOO_LONG |
|
+ {"PATH_TOO_LONG", ERR_LIB_SSL, SSL_R_PATH_TOO_LONG}, |
|
+ #else |
|
+ {"PATH_TOO_LONG", ERR_LIB_SSL, 270}, |
|
+ #endif |
|
+ #ifdef SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE |
|
+ {"PEER_DID_NOT_RETURN_A_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE}, |
|
+ #else |
|
+ {"PEER_DID_NOT_RETURN_A_CERTIFICATE", ERR_LIB_SSL, 199}, |
|
+ #endif |
|
+ #ifdef SSL_R_PEER_ERROR |
|
+ {"PEER_ERROR", ERR_LIB_SSL, SSL_R_PEER_ERROR}, |
|
+ #else |
|
+ {"PEER_ERROR", ERR_LIB_SSL, 200}, |
|
+ #endif |
|
+ #ifdef SSL_R_PEER_ERROR_CERTIFICATE |
|
+ {"PEER_ERROR_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_ERROR_CERTIFICATE}, |
|
+ #else |
|
+ {"PEER_ERROR_CERTIFICATE", ERR_LIB_SSL, 201}, |
|
+ #endif |
|
+ #ifdef SSL_R_PEER_ERROR_NO_CERTIFICATE |
|
+ {"PEER_ERROR_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_PEER_ERROR_NO_CERTIFICATE}, |
|
+ #else |
|
+ {"PEER_ERROR_NO_CERTIFICATE", ERR_LIB_SSL, 202}, |
|
+ #endif |
|
+ #ifdef SSL_R_PEER_ERROR_NO_CIPHER |
|
+ {"PEER_ERROR_NO_CIPHER", ERR_LIB_SSL, SSL_R_PEER_ERROR_NO_CIPHER}, |
|
+ #else |
|
+ {"PEER_ERROR_NO_CIPHER", ERR_LIB_SSL, 203}, |
|
+ #endif |
|
+ #ifdef SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE |
|
+ {"PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE}, |
|
+ #else |
|
+ {"PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE", ERR_LIB_SSL, 204}, |
|
+ #endif |
|
+ #ifdef SSL_R_PRE_MAC_LENGTH_TOO_LONG |
|
+ {"PRE_MAC_LENGTH_TOO_LONG", ERR_LIB_SSL, SSL_R_PRE_MAC_LENGTH_TOO_LONG}, |
|
+ #else |
|
+ {"PRE_MAC_LENGTH_TOO_LONG", ERR_LIB_SSL, 205}, |
|
+ #endif |
|
+ #ifdef SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS |
|
+ {"PROBLEMS_MAPPING_CIPHER_FUNCTIONS", ERR_LIB_SSL, SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS}, |
|
+ #else |
|
+ {"PROBLEMS_MAPPING_CIPHER_FUNCTIONS", ERR_LIB_SSL, 206}, |
|
+ #endif |
|
+ #ifdef SSL_R_PROTOCOL_IS_SHUTDOWN |
|
+ {"PROTOCOL_IS_SHUTDOWN", ERR_LIB_SSL, SSL_R_PROTOCOL_IS_SHUTDOWN}, |
|
+ #else |
|
+ {"PROTOCOL_IS_SHUTDOWN", ERR_LIB_SSL, 207}, |
|
+ #endif |
|
+ #ifdef SSL_R_PSK_IDENTITY_NOT_FOUND |
|
+ {"PSK_IDENTITY_NOT_FOUND", ERR_LIB_SSL, SSL_R_PSK_IDENTITY_NOT_FOUND}, |
|
+ #else |
|
+ {"PSK_IDENTITY_NOT_FOUND", ERR_LIB_SSL, 223}, |
|
+ #endif |
|
+ #ifdef SSL_R_PSK_NO_CLIENT_CB |
|
+ {"PSK_NO_CLIENT_CB", ERR_LIB_SSL, SSL_R_PSK_NO_CLIENT_CB}, |
|
+ #else |
|
+ {"PSK_NO_CLIENT_CB", ERR_LIB_SSL, 224}, |
|
+ #endif |
|
+ #ifdef SSL_R_PSK_NO_SERVER_CB |
|
+ {"PSK_NO_SERVER_CB", ERR_LIB_SSL, SSL_R_PSK_NO_SERVER_CB}, |
|
+ #else |
|
+ {"PSK_NO_SERVER_CB", ERR_LIB_SSL, 225}, |
|
+ #endif |
|
+ #ifdef SSL_R_PUBLIC_KEY_ENCRYPT_ERROR |
|
+ {"PUBLIC_KEY_ENCRYPT_ERROR", ERR_LIB_SSL, SSL_R_PUBLIC_KEY_ENCRYPT_ERROR}, |
|
+ #else |
|
+ {"PUBLIC_KEY_ENCRYPT_ERROR", ERR_LIB_SSL, 208}, |
|
+ #endif |
|
+ #ifdef SSL_R_PUBLIC_KEY_IS_NOT_RSA |
|
+ {"PUBLIC_KEY_IS_NOT_RSA", ERR_LIB_SSL, SSL_R_PUBLIC_KEY_IS_NOT_RSA}, |
|
+ #else |
|
+ {"PUBLIC_KEY_IS_NOT_RSA", ERR_LIB_SSL, 209}, |
|
+ #endif |
|
+ #ifdef SSL_R_PUBLIC_KEY_NOT_RSA |
|
+ {"PUBLIC_KEY_NOT_RSA", ERR_LIB_SSL, SSL_R_PUBLIC_KEY_NOT_RSA}, |
|
+ #else |
|
+ {"PUBLIC_KEY_NOT_RSA", ERR_LIB_SSL, 210}, |
|
+ #endif |
|
+ #ifdef SSL_R_READ_BIO_NOT_SET |
|
+ {"READ_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_READ_BIO_NOT_SET}, |
|
+ #else |
|
+ {"READ_BIO_NOT_SET", ERR_LIB_SSL, 211}, |
|
+ #endif |
|
+ #ifdef SSL_R_READ_TIMEOUT_EXPIRED |
|
+ {"READ_TIMEOUT_EXPIRED", ERR_LIB_SSL, SSL_R_READ_TIMEOUT_EXPIRED}, |
|
+ #else |
|
+ {"READ_TIMEOUT_EXPIRED", ERR_LIB_SSL, 312}, |
|
+ #endif |
|
+ #ifdef SSL_R_READ_WRONG_PACKET_TYPE |
|
+ {"READ_WRONG_PACKET_TYPE", ERR_LIB_SSL, SSL_R_READ_WRONG_PACKET_TYPE}, |
|
+ #else |
|
+ {"READ_WRONG_PACKET_TYPE", ERR_LIB_SSL, 212}, |
|
+ #endif |
|
+ #ifdef SSL_R_RECORD_LENGTH_MISMATCH |
|
+ {"RECORD_LENGTH_MISMATCH", ERR_LIB_SSL, SSL_R_RECORD_LENGTH_MISMATCH}, |
|
+ #else |
|
+ {"RECORD_LENGTH_MISMATCH", ERR_LIB_SSL, 213}, |
|
+ #endif |
|
+ #ifdef SSL_R_RECORD_TOO_LARGE |
|
+ {"RECORD_TOO_LARGE", ERR_LIB_SSL, SSL_R_RECORD_TOO_LARGE}, |
|
+ #else |
|
+ {"RECORD_TOO_LARGE", ERR_LIB_SSL, 214}, |
|
+ #endif |
|
+ #ifdef SSL_R_RECORD_TOO_SMALL |
|
+ {"RECORD_TOO_SMALL", ERR_LIB_SSL, SSL_R_RECORD_TOO_SMALL}, |
|
+ #else |
|
+ {"RECORD_TOO_SMALL", ERR_LIB_SSL, 298}, |
|
+ #endif |
|
+ #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG |
|
+ {"RENEGOTIATE_EXT_TOO_LONG", ERR_LIB_SSL, SSL_R_RENEGOTIATE_EXT_TOO_LONG}, |
|
+ #else |
|
+ {"RENEGOTIATE_EXT_TOO_LONG", ERR_LIB_SSL, 335}, |
|
+ #endif |
|
+ #ifdef SSL_R_RENEGOTIATION_ENCODING_ERR |
|
+ {"RENEGOTIATION_ENCODING_ERR", ERR_LIB_SSL, SSL_R_RENEGOTIATION_ENCODING_ERR}, |
|
+ #else |
|
+ {"RENEGOTIATION_ENCODING_ERR", ERR_LIB_SSL, 336}, |
|
+ #endif |
|
+ #ifdef SSL_R_RENEGOTIATION_MISMATCH |
|
+ {"RENEGOTIATION_MISMATCH", ERR_LIB_SSL, SSL_R_RENEGOTIATION_MISMATCH}, |
|
+ #else |
|
+ {"RENEGOTIATION_MISMATCH", ERR_LIB_SSL, 337}, |
|
+ #endif |
|
+ #ifdef SSL_R_REQUIRED_CIPHER_MISSING |
|
+ {"REQUIRED_CIPHER_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_CIPHER_MISSING}, |
|
+ #else |
|
+ {"REQUIRED_CIPHER_MISSING", ERR_LIB_SSL, 215}, |
|
+ #endif |
|
+ #ifdef SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING |
|
+ {"REQUIRED_COMPRESSSION_ALGORITHM_MISSING", ERR_LIB_SSL, SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING}, |
|
+ #else |
|
+ {"REQUIRED_COMPRESSSION_ALGORITHM_MISSING", ERR_LIB_SSL, 342}, |
|
+ #endif |
|
+ #ifdef SSL_R_REUSE_CERT_LENGTH_NOT_ZERO |
|
+ {"REUSE_CERT_LENGTH_NOT_ZERO", ERR_LIB_SSL, SSL_R_REUSE_CERT_LENGTH_NOT_ZERO}, |
|
+ #else |
|
+ {"REUSE_CERT_LENGTH_NOT_ZERO", ERR_LIB_SSL, 216}, |
|
+ #endif |
|
+ #ifdef SSL_R_REUSE_CERT_TYPE_NOT_ZERO |
|
+ {"REUSE_CERT_TYPE_NOT_ZERO", ERR_LIB_SSL, SSL_R_REUSE_CERT_TYPE_NOT_ZERO}, |
|
+ #else |
|
+ {"REUSE_CERT_TYPE_NOT_ZERO", ERR_LIB_SSL, 217}, |
|
+ #endif |
|
+ #ifdef SSL_R_REUSE_CIPHER_LIST_NOT_ZERO |
|
+ {"REUSE_CIPHER_LIST_NOT_ZERO", ERR_LIB_SSL, SSL_R_REUSE_CIPHER_LIST_NOT_ZERO}, |
|
+ #else |
|
+ {"REUSE_CIPHER_LIST_NOT_ZERO", ERR_LIB_SSL, 218}, |
|
+ #endif |
|
+ #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING |
|
+ {"SCSV_RECEIVED_WHEN_RENEGOTIATING", ERR_LIB_SSL, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING}, |
|
+ #else |
|
+ {"SCSV_RECEIVED_WHEN_RENEGOTIATING", ERR_LIB_SSL, 345}, |
|
+ #endif |
|
+ #ifdef SSL_R_SERVERHELLO_TLSEXT |
|
+ {"SERVERHELLO_TLSEXT", ERR_LIB_SSL, SSL_R_SERVERHELLO_TLSEXT}, |
|
+ #else |
|
+ {"SERVERHELLO_TLSEXT", ERR_LIB_SSL, 275}, |
|
+ #endif |
|
+ #ifdef SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED |
|
+ {"SESSION_ID_CONTEXT_UNINITIALIZED", ERR_LIB_SSL, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED}, |
|
+ #else |
|
+ {"SESSION_ID_CONTEXT_UNINITIALIZED", ERR_LIB_SSL, 277}, |
|
+ #endif |
|
+ #ifdef SSL_R_SHORT_READ |
|
+ {"SHORT_READ", ERR_LIB_SSL, SSL_R_SHORT_READ}, |
|
+ #else |
|
+ {"SHORT_READ", ERR_LIB_SSL, 219}, |
|
+ #endif |
|
+ #ifdef SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE |
|
+ {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE}, |
|
+ #else |
|
+ {"SIGNATURE_FOR_NON_SIGNING_CERTIFICATE", ERR_LIB_SSL, 220}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL23_DOING_SESSION_ID_REUSE |
|
+ {"SSL23_DOING_SESSION_ID_REUSE", ERR_LIB_SSL, SSL_R_SSL23_DOING_SESSION_ID_REUSE}, |
|
+ #else |
|
+ {"SSL23_DOING_SESSION_ID_REUSE", ERR_LIB_SSL, 221}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL2_CONNECTION_ID_TOO_LONG |
|
+ {"SSL2_CONNECTION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL2_CONNECTION_ID_TOO_LONG}, |
|
+ #else |
|
+ {"SSL2_CONNECTION_ID_TOO_LONG", ERR_LIB_SSL, 299}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT |
|
+ {"SSL3_EXT_INVALID_ECPOINTFORMAT", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT}, |
|
+ #else |
|
+ {"SSL3_EXT_INVALID_ECPOINTFORMAT", ERR_LIB_SSL, 321}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME |
|
+ {"SSL3_EXT_INVALID_SERVERNAME", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME}, |
|
+ #else |
|
+ {"SSL3_EXT_INVALID_SERVERNAME", ERR_LIB_SSL, 319}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE |
|
+ {"SSL3_EXT_INVALID_SERVERNAME_TYPE", ERR_LIB_SSL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE}, |
|
+ #else |
|
+ {"SSL3_EXT_INVALID_SERVERNAME_TYPE", ERR_LIB_SSL, 320}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG |
|
+ {"SSL3_SESSION_ID_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL3_SESSION_ID_TOO_LONG}, |
|
+ #else |
|
+ {"SSL3_SESSION_ID_TOO_LONG", ERR_LIB_SSL, 300}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL3_SESSION_ID_TOO_SHORT |
|
+ {"SSL3_SESSION_ID_TOO_SHORT", ERR_LIB_SSL, SSL_R_SSL3_SESSION_ID_TOO_SHORT}, |
|
+ #else |
|
+ {"SSL3_SESSION_ID_TOO_SHORT", ERR_LIB_SSL, 222}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE |
|
+ {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE}, |
|
+ #else |
|
+ {"SSLV3_ALERT_BAD_CERTIFICATE", ERR_LIB_SSL, 1042}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_BAD_RECORD_MAC |
|
+ {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC}, |
|
+ #else |
|
+ {"SSLV3_ALERT_BAD_RECORD_MAC", ERR_LIB_SSL, 1020}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED |
|
+ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED}, |
|
+ #else |
|
+ {"SSLV3_ALERT_CERTIFICATE_EXPIRED", ERR_LIB_SSL, 1045}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED |
|
+ {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED}, |
|
+ #else |
|
+ {"SSLV3_ALERT_CERTIFICATE_REVOKED", ERR_LIB_SSL, 1044}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN |
|
+ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN}, |
|
+ #else |
|
+ {"SSLV3_ALERT_CERTIFICATE_UNKNOWN", ERR_LIB_SSL, 1046}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE |
|
+ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE}, |
|
+ #else |
|
+ {"SSLV3_ALERT_DECOMPRESSION_FAILURE", ERR_LIB_SSL, 1030}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE |
|
+ {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE}, |
|
+ #else |
|
+ {"SSLV3_ALERT_HANDSHAKE_FAILURE", ERR_LIB_SSL, 1040}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER |
|
+ {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER}, |
|
+ #else |
|
+ {"SSLV3_ALERT_ILLEGAL_PARAMETER", ERR_LIB_SSL, 1047}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_NO_CERTIFICATE |
|
+ {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_NO_CERTIFICATE}, |
|
+ #else |
|
+ {"SSLV3_ALERT_NO_CERTIFICATE", ERR_LIB_SSL, 1041}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE |
|
+ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE}, |
|
+ #else |
|
+ {"SSLV3_ALERT_UNEXPECTED_MESSAGE", ERR_LIB_SSL, 1010}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE |
|
+ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE}, |
|
+ #else |
|
+ {"SSLV3_ALERT_UNSUPPORTED_CERTIFICATE", ERR_LIB_SSL, 1043}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION |
|
+ {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", ERR_LIB_SSL, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION}, |
|
+ #else |
|
+ {"SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION", ERR_LIB_SSL, 228}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_HANDSHAKE_FAILURE |
|
+ {"SSL_HANDSHAKE_FAILURE", ERR_LIB_SSL, SSL_R_SSL_HANDSHAKE_FAILURE}, |
|
+ #else |
|
+ {"SSL_HANDSHAKE_FAILURE", ERR_LIB_SSL, 229}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS |
|
+ {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS}, |
|
+ #else |
|
+ {"SSL_LIBRARY_HAS_NO_CIPHERS", ERR_LIB_SSL, 230}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_SESSION_ID_CALLBACK_FAILED |
|
+ {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED}, |
|
+ #else |
|
+ {"SSL_SESSION_ID_CALLBACK_FAILED", ERR_LIB_SSL, 301}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_SESSION_ID_CONFLICT |
|
+ {"SSL_SESSION_ID_CONFLICT", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONFLICT}, |
|
+ #else |
|
+ {"SSL_SESSION_ID_CONFLICT", ERR_LIB_SSL, 302}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG |
|
+ {"SSL_SESSION_ID_CONTEXT_TOO_LONG", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG}, |
|
+ #else |
|
+ {"SSL_SESSION_ID_CONTEXT_TOO_LONG", ERR_LIB_SSL, 273}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH |
|
+ {"SSL_SESSION_ID_HAS_BAD_LENGTH", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH}, |
|
+ #else |
|
+ {"SSL_SESSION_ID_HAS_BAD_LENGTH", ERR_LIB_SSL, 303}, |
|
+ #endif |
|
+ #ifdef SSL_R_SSL_SESSION_ID_IS_DIFFERENT |
|
+ {"SSL_SESSION_ID_IS_DIFFERENT", ERR_LIB_SSL, SSL_R_SSL_SESSION_ID_IS_DIFFERENT}, |
|
+ #else |
|
+ {"SSL_SESSION_ID_IS_DIFFERENT", ERR_LIB_SSL, 231}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_ACCESS_DENIED |
|
+ {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_ACCESS_DENIED}, |
|
+ #else |
|
+ {"TLSV1_ALERT_ACCESS_DENIED", ERR_LIB_SSL, 1049}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_DECODE_ERROR |
|
+ {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECODE_ERROR}, |
|
+ #else |
|
+ {"TLSV1_ALERT_DECODE_ERROR", ERR_LIB_SSL, 1050}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_DECRYPTION_FAILED |
|
+ {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED}, |
|
+ #else |
|
+ {"TLSV1_ALERT_DECRYPTION_FAILED", ERR_LIB_SSL, 1021}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_DECRYPT_ERROR |
|
+ {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_DECRYPT_ERROR}, |
|
+ #else |
|
+ {"TLSV1_ALERT_DECRYPT_ERROR", ERR_LIB_SSL, 1051}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION |
|
+ {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION}, |
|
+ #else |
|
+ {"TLSV1_ALERT_EXPORT_RESTRICTION", ERR_LIB_SSL, 1060}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY |
|
+ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY}, |
|
+ #else |
|
+ {"TLSV1_ALERT_INSUFFICIENT_SECURITY", ERR_LIB_SSL, 1071}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_INTERNAL_ERROR |
|
+ {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_INTERNAL_ERROR}, |
|
+ #else |
|
+ {"TLSV1_ALERT_INTERNAL_ERROR", ERR_LIB_SSL, 1080}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_NO_RENEGOTIATION |
|
+ {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION}, |
|
+ #else |
|
+ {"TLSV1_ALERT_NO_RENEGOTIATION", ERR_LIB_SSL, 1100}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_PROTOCOL_VERSION |
|
+ {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION}, |
|
+ #else |
|
+ {"TLSV1_ALERT_PROTOCOL_VERSION", ERR_LIB_SSL, 1070}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_RECORD_OVERFLOW |
|
+ {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW}, |
|
+ #else |
|
+ {"TLSV1_ALERT_RECORD_OVERFLOW", ERR_LIB_SSL, 1022}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA |
|
+ {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_UNKNOWN_CA}, |
|
+ #else |
|
+ {"TLSV1_ALERT_UNKNOWN_CA", ERR_LIB_SSL, 1048}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_ALERT_USER_CANCELLED |
|
+ {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, SSL_R_TLSV1_ALERT_USER_CANCELLED}, |
|
+ #else |
|
+ {"TLSV1_ALERT_USER_CANCELLED", ERR_LIB_SSL, 1090}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE |
|
+ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE}, |
|
+ #else |
|
+ {"TLSV1_BAD_CERTIFICATE_HASH_VALUE", ERR_LIB_SSL, 1114}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE |
|
+ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE}, |
|
+ #else |
|
+ {"TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE", ERR_LIB_SSL, 1113}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE |
|
+ {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE}, |
|
+ #else |
|
+ {"TLSV1_CERTIFICATE_UNOBTAINABLE", ERR_LIB_SSL, 1111}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_UNRECOGNIZED_NAME |
|
+ {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, SSL_R_TLSV1_UNRECOGNIZED_NAME}, |
|
+ #else |
|
+ {"TLSV1_UNRECOGNIZED_NAME", ERR_LIB_SSL, 1112}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLSV1_UNSUPPORTED_EXTENSION |
|
+ {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, SSL_R_TLSV1_UNSUPPORTED_EXTENSION}, |
|
+ #else |
|
+ {"TLSV1_UNSUPPORTED_EXTENSION", ERR_LIB_SSL, 1110}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER |
|
+ {"TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER", ERR_LIB_SSL, SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER}, |
|
+ #else |
|
+ {"TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER", ERR_LIB_SSL, 232}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST |
|
+ {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST}, |
|
+ #else |
|
+ {"TLS_INVALID_ECPOINTFORMAT_LIST", ERR_LIB_SSL, 157}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST |
|
+ {"TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST", ERR_LIB_SSL, SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST}, |
|
+ #else |
|
+ {"TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST", ERR_LIB_SSL, 233}, |
|
+ #endif |
|
+ #ifdef SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG |
|
+ {"TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG}, |
|
+ #else |
|
+ {"TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG", ERR_LIB_SSL, 234}, |
|
+ #endif |
|
+ #ifdef SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER |
|
+ {"TRIED_TO_USE_UNSUPPORTED_CIPHER", ERR_LIB_SSL, SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER}, |
|
+ #else |
|
+ {"TRIED_TO_USE_UNSUPPORTED_CIPHER", ERR_LIB_SSL, 235}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_DECODE_DH_CERTS |
|
+ {"UNABLE_TO_DECODE_DH_CERTS", ERR_LIB_SSL, SSL_R_UNABLE_TO_DECODE_DH_CERTS}, |
|
+ #else |
|
+ {"UNABLE_TO_DECODE_DH_CERTS", ERR_LIB_SSL, 236}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_DECODE_ECDH_CERTS |
|
+ {"UNABLE_TO_DECODE_ECDH_CERTS", ERR_LIB_SSL, SSL_R_UNABLE_TO_DECODE_ECDH_CERTS}, |
|
+ #else |
|
+ {"UNABLE_TO_DECODE_ECDH_CERTS", ERR_LIB_SSL, 313}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY |
|
+ {"UNABLE_TO_EXTRACT_PUBLIC_KEY", ERR_LIB_SSL, SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY}, |
|
+ #else |
|
+ {"UNABLE_TO_EXTRACT_PUBLIC_KEY", ERR_LIB_SSL, 237}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_FIND_DH_PARAMETERS |
|
+ {"UNABLE_TO_FIND_DH_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_DH_PARAMETERS}, |
|
+ #else |
|
+ {"UNABLE_TO_FIND_DH_PARAMETERS", ERR_LIB_SSL, 238}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS |
|
+ {"UNABLE_TO_FIND_ECDH_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS}, |
|
+ #else |
|
+ {"UNABLE_TO_FIND_ECDH_PARAMETERS", ERR_LIB_SSL, 314}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS |
|
+ {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS}, |
|
+ #else |
|
+ {"UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS", ERR_LIB_SSL, 239}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_FIND_SSL_METHOD |
|
+ {"UNABLE_TO_FIND_SSL_METHOD", ERR_LIB_SSL, SSL_R_UNABLE_TO_FIND_SSL_METHOD}, |
|
+ #else |
|
+ {"UNABLE_TO_FIND_SSL_METHOD", ERR_LIB_SSL, 240}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES |
|
+ {"UNABLE_TO_LOAD_SSL2_MD5_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES}, |
|
+ #else |
|
+ {"UNABLE_TO_LOAD_SSL2_MD5_ROUTINES", ERR_LIB_SSL, 241}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES |
|
+ {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES}, |
|
+ #else |
|
+ {"UNABLE_TO_LOAD_SSL3_MD5_ROUTINES", ERR_LIB_SSL, 242}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES |
|
+ {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", ERR_LIB_SSL, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES}, |
|
+ #else |
|
+ {"UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES", ERR_LIB_SSL, 243}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNEXPECTED_MESSAGE |
|
+ {"UNEXPECTED_MESSAGE", ERR_LIB_SSL, SSL_R_UNEXPECTED_MESSAGE}, |
|
+ #else |
|
+ {"UNEXPECTED_MESSAGE", ERR_LIB_SSL, 244}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNEXPECTED_RECORD |
|
+ {"UNEXPECTED_RECORD", ERR_LIB_SSL, SSL_R_UNEXPECTED_RECORD}, |
|
+ #else |
|
+ {"UNEXPECTED_RECORD", ERR_LIB_SSL, 245}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNINITIALIZED |
|
+ {"UNINITIALIZED", ERR_LIB_SSL, SSL_R_UNINITIALIZED}, |
|
+ #else |
|
+ {"UNINITIALIZED", ERR_LIB_SSL, 276}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_ALERT_TYPE |
|
+ {"UNKNOWN_ALERT_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_ALERT_TYPE}, |
|
+ #else |
|
+ {"UNKNOWN_ALERT_TYPE", ERR_LIB_SSL, 246}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_CERTIFICATE_TYPE |
|
+ {"UNKNOWN_CERTIFICATE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE}, |
|
+ #else |
|
+ {"UNKNOWN_CERTIFICATE_TYPE", ERR_LIB_SSL, 247}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_CIPHER_RETURNED |
|
+ {"UNKNOWN_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_RETURNED}, |
|
+ #else |
|
+ {"UNKNOWN_CIPHER_RETURNED", ERR_LIB_SSL, 248}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_CIPHER_TYPE |
|
+ {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_CIPHER_TYPE}, |
|
+ #else |
|
+ {"UNKNOWN_CIPHER_TYPE", ERR_LIB_SSL, 249}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE |
|
+ {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE}, |
|
+ #else |
|
+ {"UNKNOWN_KEY_EXCHANGE_TYPE", ERR_LIB_SSL, 250}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_PKEY_TYPE |
|
+ {"UNKNOWN_PKEY_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_PKEY_TYPE}, |
|
+ #else |
|
+ {"UNKNOWN_PKEY_TYPE", ERR_LIB_SSL, 251}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_PROTOCOL |
|
+ {"UNKNOWN_PROTOCOL", ERR_LIB_SSL, SSL_R_UNKNOWN_PROTOCOL}, |
|
+ #else |
|
+ {"UNKNOWN_PROTOCOL", ERR_LIB_SSL, 252}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_REMOTE_ERROR_TYPE |
|
+ {"UNKNOWN_REMOTE_ERROR_TYPE", ERR_LIB_SSL, SSL_R_UNKNOWN_REMOTE_ERROR_TYPE}, |
|
+ #else |
|
+ {"UNKNOWN_REMOTE_ERROR_TYPE", ERR_LIB_SSL, 253}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_SSL_VERSION |
|
+ {"UNKNOWN_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNKNOWN_SSL_VERSION}, |
|
+ #else |
|
+ {"UNKNOWN_SSL_VERSION", ERR_LIB_SSL, 254}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNKNOWN_STATE |
|
+ {"UNKNOWN_STATE", ERR_LIB_SSL, SSL_R_UNKNOWN_STATE}, |
|
+ #else |
|
+ {"UNKNOWN_STATE", ERR_LIB_SSL, 255}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED |
|
+ {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", ERR_LIB_SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED}, |
|
+ #else |
|
+ {"UNSAFE_LEGACY_RENEGOTIATION_DISABLED", ERR_LIB_SSL, 338}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSUPPORTED_CIPHER |
|
+ {"UNSUPPORTED_CIPHER", ERR_LIB_SSL, SSL_R_UNSUPPORTED_CIPHER}, |
|
+ #else |
|
+ {"UNSUPPORTED_CIPHER", ERR_LIB_SSL, 256}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM |
|
+ {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, |
|
+ #else |
|
+ {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_SSL, 257}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSUPPORTED_DIGEST_TYPE |
|
+ {"UNSUPPORTED_DIGEST_TYPE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_DIGEST_TYPE}, |
|
+ #else |
|
+ {"UNSUPPORTED_DIGEST_TYPE", ERR_LIB_SSL, 326}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSUPPORTED_ELLIPTIC_CURVE |
|
+ {"UNSUPPORTED_ELLIPTIC_CURVE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE}, |
|
+ #else |
|
+ {"UNSUPPORTED_ELLIPTIC_CURVE", ERR_LIB_SSL, 315}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSUPPORTED_PROTOCOL |
|
+ {"UNSUPPORTED_PROTOCOL", ERR_LIB_SSL, SSL_R_UNSUPPORTED_PROTOCOL}, |
|
+ #else |
|
+ {"UNSUPPORTED_PROTOCOL", ERR_LIB_SSL, 258}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSUPPORTED_SSL_VERSION |
|
+ {"UNSUPPORTED_SSL_VERSION", ERR_LIB_SSL, SSL_R_UNSUPPORTED_SSL_VERSION}, |
|
+ #else |
|
+ {"UNSUPPORTED_SSL_VERSION", ERR_LIB_SSL, 259}, |
|
+ #endif |
|
+ #ifdef SSL_R_UNSUPPORTED_STATUS_TYPE |
|
+ {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, SSL_R_UNSUPPORTED_STATUS_TYPE}, |
|
+ #else |
|
+ {"UNSUPPORTED_STATUS_TYPE", ERR_LIB_SSL, 329}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRITE_BIO_NOT_SET |
|
+ {"WRITE_BIO_NOT_SET", ERR_LIB_SSL, SSL_R_WRITE_BIO_NOT_SET}, |
|
+ #else |
|
+ {"WRITE_BIO_NOT_SET", ERR_LIB_SSL, 260}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRONG_CIPHER_RETURNED |
|
+ {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, SSL_R_WRONG_CIPHER_RETURNED}, |
|
+ #else |
|
+ {"WRONG_CIPHER_RETURNED", ERR_LIB_SSL, 261}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRONG_MESSAGE_TYPE |
|
+ {"WRONG_MESSAGE_TYPE", ERR_LIB_SSL, SSL_R_WRONG_MESSAGE_TYPE}, |
|
+ #else |
|
+ {"WRONG_MESSAGE_TYPE", ERR_LIB_SSL, 262}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRONG_NUMBER_OF_KEY_BITS |
|
+ {"WRONG_NUMBER_OF_KEY_BITS", ERR_LIB_SSL, SSL_R_WRONG_NUMBER_OF_KEY_BITS}, |
|
+ #else |
|
+ {"WRONG_NUMBER_OF_KEY_BITS", ERR_LIB_SSL, 263}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRONG_SIGNATURE_LENGTH |
|
+ {"WRONG_SIGNATURE_LENGTH", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_LENGTH}, |
|
+ #else |
|
+ {"WRONG_SIGNATURE_LENGTH", ERR_LIB_SSL, 264}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRONG_SIGNATURE_SIZE |
|
+ {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, SSL_R_WRONG_SIGNATURE_SIZE}, |
|
+ #else |
|
+ {"WRONG_SIGNATURE_SIZE", ERR_LIB_SSL, 265}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRONG_SSL_VERSION |
|
+ {"WRONG_SSL_VERSION", ERR_LIB_SSL, SSL_R_WRONG_SSL_VERSION}, |
|
+ #else |
|
+ {"WRONG_SSL_VERSION", ERR_LIB_SSL, 266}, |
|
+ #endif |
|
+ #ifdef SSL_R_WRONG_VERSION_NUMBER |
|
+ {"WRONG_VERSION_NUMBER", ERR_LIB_SSL, SSL_R_WRONG_VERSION_NUMBER}, |
|
+ #else |
|
+ {"WRONG_VERSION_NUMBER", ERR_LIB_SSL, 267}, |
|
+ #endif |
|
+ #ifdef SSL_R_X509_LIB |
|
+ {"X509_LIB", ERR_LIB_SSL, SSL_R_X509_LIB}, |
|
+ #else |
|
+ {"X509_LIB", ERR_LIB_SSL, 268}, |
|
+ #endif |
|
+ #ifdef SSL_R_X509_VERIFICATION_SETUP_PROBLEMS |
|
+ {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS}, |
|
+ #else |
|
+ {"X509_VERIFICATION_SETUP_PROBLEMS", ERR_LIB_SSL, 269}, |
|
+ #endif |
|
+ #ifdef X509_R_BAD_X509_FILETYPE |
|
+ {"BAD_X509_FILETYPE", ERR_LIB_X509, X509_R_BAD_X509_FILETYPE}, |
|
+ #else |
|
+ {"BAD_X509_FILETYPE", ERR_LIB_X509, 100}, |
|
+ #endif |
|
+ #ifdef X509_R_BASE64_DECODE_ERROR |
|
+ {"BASE64_DECODE_ERROR", ERR_LIB_X509, X509_R_BASE64_DECODE_ERROR}, |
|
+ #else |
|
+ {"BASE64_DECODE_ERROR", ERR_LIB_X509, 118}, |
|
+ #endif |
|
+ #ifdef X509_R_CANT_CHECK_DH_KEY |
|
+ {"CANT_CHECK_DH_KEY", ERR_LIB_X509, X509_R_CANT_CHECK_DH_KEY}, |
|
+ #else |
|
+ {"CANT_CHECK_DH_KEY", ERR_LIB_X509, 114}, |
|
+ #endif |
|
+ #ifdef X509_R_CERT_ALREADY_IN_HASH_TABLE |
|
+ {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, X509_R_CERT_ALREADY_IN_HASH_TABLE}, |
|
+ #else |
|
+ {"CERT_ALREADY_IN_HASH_TABLE", ERR_LIB_X509, 101}, |
|
+ #endif |
|
+ #ifdef X509_R_ERR_ASN1_LIB |
|
+ {"ERR_ASN1_LIB", ERR_LIB_X509, X509_R_ERR_ASN1_LIB}, |
|
+ #else |
|
+ {"ERR_ASN1_LIB", ERR_LIB_X509, 102}, |
|
+ #endif |
|
+ #ifdef X509_R_INVALID_DIRECTORY |
|
+ {"INVALID_DIRECTORY", ERR_LIB_X509, X509_R_INVALID_DIRECTORY}, |
|
+ #else |
|
+ {"INVALID_DIRECTORY", ERR_LIB_X509, 113}, |
|
+ #endif |
|
+ #ifdef X509_R_INVALID_FIELD_NAME |
|
+ {"INVALID_FIELD_NAME", ERR_LIB_X509, X509_R_INVALID_FIELD_NAME}, |
|
+ #else |
|
+ {"INVALID_FIELD_NAME", ERR_LIB_X509, 119}, |
|
+ #endif |
|
+ #ifdef X509_R_INVALID_TRUST |
|
+ {"INVALID_TRUST", ERR_LIB_X509, X509_R_INVALID_TRUST}, |
|
+ #else |
|
+ {"INVALID_TRUST", ERR_LIB_X509, 123}, |
|
+ #endif |
|
+ #ifdef X509_R_KEY_TYPE_MISMATCH |
|
+ {"KEY_TYPE_MISMATCH", ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH}, |
|
+ #else |
|
+ {"KEY_TYPE_MISMATCH", ERR_LIB_X509, 115}, |
|
+ #endif |
|
+ #ifdef X509_R_KEY_VALUES_MISMATCH |
|
+ {"KEY_VALUES_MISMATCH", ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH}, |
|
+ #else |
|
+ {"KEY_VALUES_MISMATCH", ERR_LIB_X509, 116}, |
|
+ #endif |
|
+ #ifdef X509_R_LOADING_CERT_DIR |
|
+ {"LOADING_CERT_DIR", ERR_LIB_X509, X509_R_LOADING_CERT_DIR}, |
|
+ #else |
|
+ {"LOADING_CERT_DIR", ERR_LIB_X509, 103}, |
|
+ #endif |
|
+ #ifdef X509_R_LOADING_DEFAULTS |
|
+ {"LOADING_DEFAULTS", ERR_LIB_X509, X509_R_LOADING_DEFAULTS}, |
|
+ #else |
|
+ {"LOADING_DEFAULTS", ERR_LIB_X509, 104}, |
|
+ #endif |
|
+ #ifdef X509_R_METHOD_NOT_SUPPORTED |
|
+ {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED}, |
|
+ #else |
|
+ {"METHOD_NOT_SUPPORTED", ERR_LIB_X509, 124}, |
|
+ #endif |
|
+ #ifdef X509_R_NO_CERT_SET_FOR_US_TO_VERIFY |
|
+ {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY}, |
|
+ #else |
|
+ {"NO_CERT_SET_FOR_US_TO_VERIFY", ERR_LIB_X509, 105}, |
|
+ #endif |
|
+ #ifdef X509_R_PUBLIC_KEY_DECODE_ERROR |
|
+ {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_DECODE_ERROR}, |
|
+ #else |
|
+ {"PUBLIC_KEY_DECODE_ERROR", ERR_LIB_X509, 125}, |
|
+ #endif |
|
+ #ifdef X509_R_PUBLIC_KEY_ENCODE_ERROR |
|
+ {"PUBLIC_KEY_ENCODE_ERROR", ERR_LIB_X509, X509_R_PUBLIC_KEY_ENCODE_ERROR}, |
|
+ #else |
|
+ {"PUBLIC_KEY_ENCODE_ERROR", ERR_LIB_X509, 126}, |
|
+ #endif |
|
+ #ifdef X509_R_SHOULD_RETRY |
|
+ {"SHOULD_RETRY", ERR_LIB_X509, X509_R_SHOULD_RETRY}, |
|
+ #else |
|
+ {"SHOULD_RETRY", ERR_LIB_X509, 106}, |
|
+ #endif |
|
+ #ifdef X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN |
|
+ {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", ERR_LIB_X509, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN}, |
|
+ #else |
|
+ {"UNABLE_TO_FIND_PARAMETERS_IN_CHAIN", ERR_LIB_X509, 107}, |
|
+ #endif |
|
+ #ifdef X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY |
|
+ {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", ERR_LIB_X509, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY}, |
|
+ #else |
|
+ {"UNABLE_TO_GET_CERTS_PUBLIC_KEY", ERR_LIB_X509, 108}, |
|
+ #endif |
|
+ #ifdef X509_R_UNKNOWN_KEY_TYPE |
|
+ {"UNKNOWN_KEY_TYPE", ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE}, |
|
+ #else |
|
+ {"UNKNOWN_KEY_TYPE", ERR_LIB_X509, 117}, |
|
+ #endif |
|
+ #ifdef X509_R_UNKNOWN_NID |
|
+ {"UNKNOWN_NID", ERR_LIB_X509, X509_R_UNKNOWN_NID}, |
|
+ #else |
|
+ {"UNKNOWN_NID", ERR_LIB_X509, 109}, |
|
+ #endif |
|
+ #ifdef X509_R_UNKNOWN_PURPOSE_ID |
|
+ {"UNKNOWN_PURPOSE_ID", ERR_LIB_X509, X509_R_UNKNOWN_PURPOSE_ID}, |
|
+ #else |
|
+ {"UNKNOWN_PURPOSE_ID", ERR_LIB_X509, 121}, |
|
+ #endif |
|
+ #ifdef X509_R_UNKNOWN_TRUST_ID |
|
+ {"UNKNOWN_TRUST_ID", ERR_LIB_X509, X509_R_UNKNOWN_TRUST_ID}, |
|
+ #else |
|
+ {"UNKNOWN_TRUST_ID", ERR_LIB_X509, 120}, |
|
+ #endif |
|
+ #ifdef X509_R_UNSUPPORTED_ALGORITHM |
|
+ {"UNSUPPORTED_ALGORITHM", ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM}, |
|
+ #else |
|
+ {"UNSUPPORTED_ALGORITHM", ERR_LIB_X509, 111}, |
|
+ #endif |
|
+ #ifdef X509_R_WRONG_LOOKUP_TYPE |
|
+ {"WRONG_LOOKUP_TYPE", ERR_LIB_X509, X509_R_WRONG_LOOKUP_TYPE}, |
|
+ #else |
|
+ {"WRONG_LOOKUP_TYPE", ERR_LIB_X509, 112}, |
|
+ #endif |
|
+ #ifdef X509_R_WRONG_TYPE |
|
+ {"WRONG_TYPE", ERR_LIB_X509, X509_R_WRONG_TYPE}, |
|
+ #else |
|
+ {"WRONG_TYPE", ERR_LIB_X509, 122}, |
|
+ #endif |
|
+ { NULL } |
|
+}; |
|
diff -up Python-2.7.5/Lib/test/test_support.py.ssl Python-2.7.5/Lib/test/test_support.py |
|
--- Python-2.7.5/Lib/test/test_support.py.ssl 2015-02-24 12:12:20.587171888 +0100 |
|
+++ Python-2.7.5/Lib/test/test_support.py 2015-02-24 12:12:59.495502649 +0100 |
|
@@ -290,7 +290,8 @@ def requires(resource, msg=None): |
|
msg = "Use of the `%s' resource not enabled" % resource |
|
raise ResourceDenied(msg) |
|
|
|
-HOST = 'localhost' |
|
+HOST = "127.0.0.1" |
|
+HOSTv6 = "::1" |
|
|
|
def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): |
|
"""Returns an unused port that should be suitable for binding. This is
|
|
|