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.
13083 lines
512 KiB
13083 lines
512 KiB
![]()
6 years ago
|
# 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
|