diff --git a/SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch b/SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch new file mode 100644 index 0000000..b964896 --- /dev/null +++ b/SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch @@ -0,0 +1,176 @@ + +# HG changeset patch +# User Victor Stinner +# Date 1406673545 -7200 +# Node ID 263701e0b77e3160bc6a835087f838bd6b24092a +# Parent 6c47c6d2033e20e9b35f1d22e0e797961d6e680f +Issue #22023: Fix %S, %R and %V formats of PyUnicode_FromFormat(). + +diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c +--- a/Objects/unicodeobject.c ++++ b/Objects/unicodeobject.c +@@ -690,7 +690,12 @@ makefmt(char *fmt, int longflag, int siz + *fmt = '\0'; + } + +-#define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;} ++#define appendstring(string) \ ++ do { \ ++ for (copy = string;*copy; copy++) { \ ++ *s++ = (unsigned char)*copy; \ ++ } \ ++ } while (0) + + PyObject * + PyUnicode_FromFormatV(const char *format, va_list vargs) +@@ -845,7 +850,7 @@ PyUnicode_FromFormatV(const char *format + str = PyObject_Str(obj); + if (!str) + goto fail; +- n += PyUnicode_GET_SIZE(str); ++ n += PyString_GET_SIZE(str); + /* Remember the str and switch to the next slot */ + *callresult++ = str; + break; +@@ -1006,15 +1011,10 @@ PyUnicode_FromFormatV(const char *format + case 'S': + case 'R': + { +- Py_UNICODE *ucopy; +- Py_ssize_t usize; +- Py_ssize_t upos; ++ const char *str = PyString_AS_STRING(*callresult); + /* unused, since we already have the result */ + (void) va_arg(vargs, PyObject *); +- ucopy = PyUnicode_AS_UNICODE(*callresult); +- usize = PyUnicode_GET_SIZE(*callresult); +- for (upos = 0; upos forget it */ + Py_DECREF(*callresult); + /* switch to next unicode()/repr() result */ + + +diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py +index f068ca6..883e93e 100644 +--- a/Lib/test/test_unicode.py ++++ b/Lib/test/test_unicode.py +@@ -1639,6 +1639,117 @@ class UnicodeTest( + self.assertEqual(u'{:{f}}{g}{}'.format(1, 3, g='g', f=2), u' 1g3') + self.assertEqual(u'{f:{}}{}{g}'.format(2, 4, f=1, g='g'), u' 14g') + ++ # Test PyUnicode_FromFormat() ++ def test_from_format(self): ++ test_support.import_module('ctypes') ++ from ctypes import ( ++ pythonapi, py_object, sizeof, ++ c_int, c_long, c_longlong, c_ssize_t, ++ c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p) ++ if sys.maxunicode == 0xffff: ++ name = "PyUnicodeUCS2_FromFormat" ++ else: ++ name = "PyUnicodeUCS4_FromFormat" ++ _PyUnicode_FromFormat = getattr(pythonapi, name) ++ _PyUnicode_FromFormat.restype = py_object ++ ++ def PyUnicode_FromFormat(format, *args): ++ cargs = tuple( ++ py_object(arg) if isinstance(arg, unicode) else arg ++ for arg in args) ++ return _PyUnicode_FromFormat(format, *cargs) ++ ++ def check_format(expected, format, *args): ++ text = PyUnicode_FromFormat(format, *args) ++ self.assertEqual(expected, text) ++ ++ # ascii format, non-ascii argument ++ check_format(u'ascii\x7f=unicode\xe9', ++ b'ascii\x7f=%U', u'unicode\xe9') ++ ++ # non-ascii format, ascii argument: ensure that PyUnicode_FromFormatV() ++ # raises an error ++ #self.assertRaisesRegex(ValueError, ++ # '^PyUnicode_FromFormatV\(\) expects an ASCII-encoded format ' ++ # 'string, got a non-ASCII byte: 0xe9$', ++ # PyUnicode_FromFormat, b'unicode\xe9=%s', u'ascii') ++ ++ # test "%c" ++ check_format(u'\uabcd', ++ b'%c', c_int(0xabcd)) ++ if sys.maxunicode > 0xffff: ++ check_format(u'\U0010ffff', ++ b'%c', c_int(0x10ffff)) ++ with self.assertRaises(OverflowError): ++ PyUnicode_FromFormat(b'%c', c_int(0x110000)) ++ # Issue #18183 ++ if sys.maxunicode > 0xffff: ++ check_format(u'\U00010000\U00100000', ++ b'%c%c', c_int(0x10000), c_int(0x100000)) ++ ++ # test "%" ++ check_format(u'%', ++ b'%') ++ check_format(u'%', ++ b'%%') ++ check_format(u'%s', ++ b'%%s') ++ check_format(u'[%]', ++ b'[%%]') ++ check_format(u'%abc', ++ b'%%%s', b'abc') ++ ++ # test %S ++ check_format(u"repr=abc", ++ b'repr=%S', u'abc') ++ ++ # test %R ++ check_format(u"repr=u'abc'", ++ b'repr=%R', u'abc') ++ ++ # test integer formats (%i, %d, %u) ++ check_format(u'010', ++ b'%03i', c_int(10)) ++ check_format(u'0010', ++ b'%0.4i', c_int(10)) ++ check_format(u'-123', ++ b'%i', c_int(-123)) ++ ++ check_format(u'-123', ++ b'%d', c_int(-123)) ++ check_format(u'-123', ++ b'%ld', c_long(-123)) ++ check_format(u'-123', ++ b'%zd', c_ssize_t(-123)) ++ ++ check_format(u'123', ++ b'%u', c_uint(123)) ++ check_format(u'123', ++ b'%lu', c_ulong(123)) ++ check_format(u'123', ++ b'%zu', c_size_t(123)) ++ ++ # test long output ++ PyUnicode_FromFormat(b'%p', c_void_p(-1)) ++ ++ # test %V ++ check_format(u'repr=abc', ++ b'repr=%V', u'abc', b'xyz') ++ check_format(u'repr=\xe4\xba\xba\xe6\xb0\x91', ++ b'repr=%V', None, b'\xe4\xba\xba\xe6\xb0\x91') ++ check_format(u'repr=abc\xff', ++ b'repr=%V', None, b'abc\xff') ++ ++ # not supported: copy the raw format string. these tests are just here ++ # to check for crashs and should not be considered as specifications ++ check_format(u'%s', ++ b'%1%s', b'abc') ++ check_format(u'%1abc', ++ b'%1abc') ++ check_format(u'%+i', ++ b'%+i', c_int(10)) ++ check_format(u'%s', ++ b'%.%s', b'abc') + def test_raiseMemError(self): + # Ensure that the freelist contains a consistent object, even + # when a string allocation fails with a MemoryError. diff --git a/SOURCES/00214-pep466-backport-py3-ssl-changes.patch b/SOURCES/00214-pep466-backport-py3-ssl-changes.patch new file mode 100644 index 0000000..094533f --- /dev/null +++ b/SOURCES/00214-pep466-backport-py3-ssl-changes.patch @@ -0,0 +1,12893 @@ + +# HG changeset patch +# User Benjamin Peterson +# 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 --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst +--- a/Doc/library/ssl.rst ++++ b/Doc/library/ssl.rst +@@ -28,19 +28,14 @@ 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. + + .. warning:: +- The ssl module won't validate certificates by default. When used in +- client mode, this means you are vulnerable to man-in-the-middle attacks. ++ Don't use this module without reading the :ref:`ssl-security`. Doing so ++ may lead to a false sense of security, as the default settings of the ++ ssl module are not necessarily appropriate for your application. + +-.. warning:: +- +- OpenSSL's internal random number generator does not properly handle fork. +- 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. + + 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 +@@ -49,23 +44,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. + +-.. 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) ++ .. 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 ++ ` 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 ++ ` 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 ++ ++.. 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 +@@ -85,19 +158,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. + +@@ -127,14 +187,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:: + +@@ -161,22 +223,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 +@@ -187,28 +306,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 ++^^^^^^^^^^^^^^^^^^^^ + +- 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. ++.. function:: match_hostname(cert, hostname) + +- Here's an example:: ++ 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. + +- >>> 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 "", line 1, in ++ 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 +@@ -219,36 +376,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 + +@@ -275,9 +540,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 ++ `_. 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 + +@@ -309,9 +701,40 @@ Functions, Constants, and Exceptions + + .. versionadded:: 2.7 + ++.. data:: ALERT_DESCRIPTION_HANDSHAKE_FAILURE ++ ALERT_DESCRIPTION_INTERNAL_ERROR ++ ALERT_DESCRIPTION_* + +-SSLSocket Objects +------------------ ++ Alert Descriptions from :rfc:`5246` and others. The `IANA TLS Alert Registry ++ `_ ++ 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 ++ ++.. 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`: + +@@ -334,37 +757,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 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. ++ 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" 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:: ++ 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:: + +- {'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'),))} ++ {'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 +@@ -380,40 +830,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() + +- 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:: ++ Return the compression algorithm being used as a string, or ``None`` ++ if the connection isn't compressed. + +- 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 ++ 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``. ++ ++ .. 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 ++ `_. ++ ++ 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 ++ `_. ++ 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 ++ `_. 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_* ` 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 `_ ++ 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 ++ `_ 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 + +@@ -460,6 +1258,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, +@@ -483,24 +1284,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`. + +-Some "standard" root certificates are available from various certification +-authorities: `Thawte `_, `Verisign +-`_, `Positive SSL +-`_ +-(used by python.org), `Equifax and GeoTrust +-`_. ++Combined key and certificate ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +-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. ++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----- ++ ++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 +@@ -555,87 +1367,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} + +-which is a fairly poorly-formed ``subject`` field. ++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', ''), ++ ('DNS', 'linuxfr.org'), ++ ('othername', ''), ++ ('DNS', 'dev.linuxfr.org'), ++ ('othername', ''), ++ ('DNS', 'prod.linuxfr.org'), ++ ('othername', ''), ++ ('DNS', 'alpha.linuxfr.org'), ++ ('othername', ''), ++ ('DNS', '*.linuxfr.org'), ++ ('othername', '')), ++ '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. ++ + + 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): +@@ -649,7 +1530,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 `_. ++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:: +@@ -668,3 +1680,15 @@ And go back to listening for new client + + `RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile `_ + Housley et. al. ++ ++ `RFC 4366: Transport Layer Security (TLS) Extensions `_ ++ Blake-Wilson et. al. ++ ++ `RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 `_ ++ T. Dierks et. al. ++ ++ `RFC 6066: Transport Layer Security (TLS) Extensions `_ ++ D. Eastlake ++ ++ `IANA TLS: Transport Layer Security (TLS) Parameters `_ ++ IANA +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,462 @@ 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): ++ ++ self._makefile_refs = 0 ++ 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,160 @@ 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 --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_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -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 platform + import functools +-import platform ++from contextlib import closing + +-from BaseHTTPServer import HTTPServer +-from SimpleHTTPServer import SimpleHTTPRequestHandler ++ssl = support.import_module("ssl") + +-ssl = test_support.import_module("ssl") ++PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) ++HOST = support.HOST + +-HOST = test_support.HOST +-CERTFILE = None +-SVN_PYTHON_ORG_ROOT_CERT = None +-NULLBYTECERT = None ++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()) ++ + + 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,22 @@ 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_4238(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'),), +@@ -137,7 +224,7 @@ class BasicSocketTests(unittest.TestCase + (('emailAddress', 'python-dev@python.org'),)) + self.assertEqual(p['subject'], subject) + self.assertEqual(p['issuer'], subject) +- if ssl.OPENSSL_VERSION_INFO >= (0, 9, 8): ++ if ssl._OPENSSL_API_VERSION >= (0, 9, 8): + san = (('DNS', 'altnull.python.org\x00example.com'), + ('email', 'null@python.org\x00user@example.org'), + ('URI', 'http://null.python.org\x00http://example.org'), +@@ -192,24 +279,7 @@ class BasicSocketTests(unittest.TestCase + self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)), + (s, t)) + +- @test_support.requires_resource('network') +- def test_ciphers(self): +- 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. +@@ -224,17 +294,319 @@ 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', ''))} ++ ok(cert, 'linuxfr.org') ++ ok(cert, 'linuxfr.com') ++ # Not a "DNS" entry ++ fail(cert, '') ++ # 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 test_unsupported_dtls(self): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +@@ -242,29 +614,592 @@ class BasicSocketTests(unittest.TestCase + with self.assertRaises(NotImplementedError) as cx: + ssl.wrap_socket(s, cert_reqs=ssl.CERT_NONE) + self.assertEqual(str(cx.exception), "only stream sockets are supported") ++ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ with self.assertRaises(NotImplementedError) as cx: ++ ctx.wrap_socket(s) ++ self.assertEqual(str(cx.exception), "only stream sockets are supported") ++ ++ 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() ++ try: ++ s.connect(("svn.python.org", 443)) ++ 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) +- try: +- s.connect(("svn.python.org", 443)) +- except ssl.SSLError: +- pass +- finally: +- s.close() ++ 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), +@@ -272,12 +1207,13 @@ class NetworkedTests(unittest.TestCase): + 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) +@@ -290,7 +1226,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, +@@ -307,13 +1243,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: +@@ -322,7 +1255,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, +@@ -337,22 +1270,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() +@@ -368,7 +1388,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) +@@ -381,41 +1401,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), +- ssl.PROTOCOL_SSLv23) +- 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), +- ssl.PROTOCOL_SSLv23, +- 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(("svn.python.org", 443), +- ssl.PROTOCOL_SSLv23, +- 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) ++ 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) + + def test_algorithms(self): + # Issue #8484: all algorithms should be available when verifying a +@@ -423,17 +1459,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" % +@@ -441,6 +1481,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 +@@ -449,6 +1519,8 @@ except ImportError: + else: + _have_threads = True + ++ from test.ssl_servers import make_https_server ++ + class ThreadedEchoServer(threading.Thread): + + class ConnectionHandler(threading.Thread): +@@ -457,48 +1529,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): +@@ -517,48 +1592,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: +@@ -569,36 +1649,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 +@@ -626,10 +1704,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: +@@ -648,11 +1726,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): +@@ -663,12 +1742,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: +@@ -681,12 +1759,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): +@@ -694,14 +1776,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) + +@@ -725,13 +1807,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): +@@ -743,103 +1825,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 +@@ -847,74 +1841,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)]: ++ 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: sending %s...\n" % (repr(arg))) +- s.write(arg) +- outdata = s.read() +- 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 = { +@@ -922,19 +1916,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: +@@ -953,75 +1958,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: +@@ -1032,8 +2000,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, +@@ -1051,25 +2105,84 @@ else: + 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() ++ ++ 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() ++ + @skip_if_broken_ubuntu_ssl ++ @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, False) ++ 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) +@@ -1082,22 +2195,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) +@@ -1105,10 +2234,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, +@@ -1120,119 +2294,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)) ++ finally: + 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) ++ 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, +@@ -1251,12 +2415,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] + +@@ -1275,73 +2439,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 + +@@ -1355,6 +2519,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() +@@ -1372,8 +2538,8 @@ else: + c.close() + try: + c = socket.socket(socket.AF_INET) ++ c = ssl.wrap_socket(c) + c.settimeout(0.2) +- c = ssl.wrap_socket(c) + # Will attempt handshake and time out + self.assertRaisesRegexp(ssl.SSLError, "timed out", + c.connect, (host, port)) +@@ -1384,59 +2550,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 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 + +- 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!") ++ 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 --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/Makefile.pre.in b/Makefile.pre.in +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -930,8 +930,8 @@ 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/audiodata test/data \ +- test/cjkencodings test/decimaltestdata test/xmltestdata \ ++ lib-tk/test/test_ttk site-packages test test/audiodata test/capath \ ++ test/data test/cjkencodings test/decimaltestdata test/xmltestdata \ + test/imghdrdata \ + test/subprocessdata \ + test/tracedmodules \ +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -14,22 +14,28 @@ + 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 +@@ -37,6 +43,68 @@ + + #endif + ++/* Include symbols from _socket module */ ++#include "socketmodule.h" ++ ++#if defined(HAVE_POLL_H) ++#include ++#elif defined(HAVE_SYS_POLL_H) ++#include ++#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, +@@ -49,6 +117,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 + }; + +@@ -64,36 +133,18 @@ 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 ++#endif + }; + +-/* Include symbols from _socket module */ +-#include "socketmodule.h" +- +-#if defined(HAVE_POLL_H) +-#include +-#elif defined(HAVE_SYS_POLL_H) +-#include +-#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 + + /* serves as a flag to see whether we've initialized the SSL thread support. */ +@@ -114,27 +165,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 +- 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); ++ 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; ++ 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); +- +-#define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type) ++static PyObject *PySSL_peercert(PySSLSocket *self, PyObject *args); ++static PyObject *PySSL_cipher(PySSLSocket *self); ++ ++#define PySSLContext_Check(v) (Py_TYPE(v) == &PySSLContext_Type) ++#define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type) + + typedef enum { + SOCKET_IS_NONBLOCKING, +@@ -151,36 +254,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: +@@ -193,213 +400,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; +- long options; +- +- self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ ++ PySSLSocket *self; ++ SSL_CTX *ctx = sslctx->ctx; ++ long mode; ++ ++ 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 */ ++ self->ssl = SSL_new(ctx); ++ PySSL_END_ALLOW_THREADS ++ 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 ++ mode |= SSL_MODE_AUTO_RETRY; + #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 */ +- options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; +- if (proto_version != PY_SSL_VERSION_SSL2) +- options |= SSL_OP_NO_SSLv2; +- SSL_CTX_set_options(self->ctx, options); +- +- 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 */ +- PySSL_END_ALLOW_THREADS +- SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ +-#ifdef SSL_MODE_AUTO_RETRY +- SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); ++ 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); + } +@@ -411,65 +514,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); + +@@ -480,60 +549,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 * +@@ -639,8 +696,8 @@ static PyObject * + /* + 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; +@@ -727,21 +784,24 @@ static PyObject * + /* 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++) { + /* get a rendering of each name in the set of names */ +@@ -888,7 +948,127 @@ static PyObject * + } + + 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; +@@ -897,9 +1077,10 @@ static PyObject * + 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; + +@@ -917,65 +1098,62 @@ static PyObject * + } + 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); +- +- version = PyInt_FromLong(X509_get_version(certificate) + 1); +- if (PyDict_SetItemString(retval, "version", version) < 0) { +- Py_DECREF(version); +- goto fail0; +- } ++ goto fail0; ++ } ++ Py_DECREF(issuer); ++ ++ 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); +- +- (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; +- } ++ 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 = 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); +@@ -1008,6 +1186,41 @@ static PyObject * + 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; + +@@ -1019,6 +1232,24 @@ static PyObject * + 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) { +@@ -1027,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: +@@ -1059,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; +@@ -1070,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; + +@@ -1078,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); + } + } + +@@ -1113,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; +@@ -1140,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); +@@ -1161,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); + } + +@@ -1241,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; +- +- if (!PyArg_ParseTuple(args, "s*:write", &buf)) ++ PySocketSockObject *sock = self->Socket; ++ ++ Py_INCREF(sock); ++ ++ if (!PyArg_ParseTuple(args, "s*:write", &buf)) { ++ Py_DECREF(sock); + return NULL; ++ } + + if (buf.len > INT_MAX) { + PyErr_Format(PyExc_OverflowError, +@@ -1259,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"); +@@ -1286,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; + } +@@ -1305,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); +@@ -1312,6 +1611,7 @@ static PyObject *PySSL_SSLwrite(PySSLObj + return PySSL_SetError(self, len, __FILE__, __LINE__); + + error: ++ Py_DECREF(sock); + PyBuffer_Release(&buf); + return NULL; + } +@@ -1322,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; + +@@ -1341,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; +- +- if (!PyArg_ParseTuple(args, "|i:read", &len)) +- return NULL; +- +- if (!(buf = PyString_FromStringAndSize((char *) 0, len))) +- return NULL; ++ PySocketSockObject *sock = self->Socket; ++ ++ Py_INCREF(sock); ++ ++ 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); + +@@ -1367,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; + } +- if (count != len) +- _PyString_Resize(&buf, count); +- return buf; ++ ++done: ++ Py_DECREF(sock); ++ if (!buf_passed) { ++ _PyBytes_Resize(&dest, count); ++ return dest; ++ } ++ 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, +@@ -1438,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); + +@@ -1486,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) { +@@ -1498,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, +@@ -1524,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, +@@ -1532,39 +1904,1307 @@ 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*/ + }; + ++ ++/* ++ * _SSLContext objects ++ */ ++ ++static PyObject * ++context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ++{ ++ 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; ++ ++ 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; ++ } ++ 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; ++} ++ ++static int ++context_traverse(PySSLContext *self, visitproc visit, void *arg) ++{ ++#ifndef OPENSSL_NO_TLSEXT ++ Py_VISIT(self->set_hostname); ++#endif ++ return 0; ++} ++ ++static int ++context_clear(PySSLContext *self) ++{ ++#ifndef OPENSSL_NO_TLSEXT ++ Py_CLEAR(self->set_hostname); ++#endif ++ return 0; ++} ++ ++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 * ++set_ciphers(PySSLContext *self, PyObject *args) ++{ ++ int ret; ++ const char *cipherlist; ++ ++ 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, ++ "No cipher can be selected."); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++#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; ++ ++ 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; ++ } ++ ++ 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 */ +@@ -1572,12 +3212,21 @@ static PyObject * + PySSL_RAND_add(PyObject *self, PyObject *args) + { + char *buf; +- int len; ++ Py_ssize_t len, written; + double entropy; + + if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) + return NULL; +- RAND_add(buf, len, entropy); ++ 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; + } +@@ -1591,7 +3240,7 @@ bound on the entropy contained in string + static PyObject * + PySSL_RAND_status(PyObject *self) + { +- return PyInt_FromLong(RAND_status()); ++ return PyLong_FromLong(RAND_status()); + } + + PyDoc_STRVAR(PySSL_RAND_status_doc, +@@ -1630,21 +3279,413 @@ fails or if it does not provide enough d + #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 = PyUnicode_InternFromString("x509_asn"); ++ if (x509_asn == NULL) ++ return NULL; ++ } ++ if (pkcs_7_asn == NULL) { ++ pkcs_7_asn = PyUnicode_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 PyLong_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 = PyUnicode_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|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|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 */ + }; + +@@ -1672,16 +3713,17 @@ static unsigned long + } + #endif + +-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. +@@ -1705,10 +3747,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) { +@@ -1716,7 +3759,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; + } + } +@@ -1736,14 +3779,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; +- +- Py_TYPE(&PySSL_Type) = &PyType_Type; ++ struct py_ssl_error_code *errcode; ++ struct py_ssl_library_code *libcode; ++ ++ 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) +@@ -1766,15 +3834,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; +- if (PyDict_SetItemString(d, "SSLType", +- (PyObject *)&PySSL_Type) != 0) ++ ++ ((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, "_SSLSocket", ++ (PyObject *)&PySSLSocket_Type) != 0) + return; + PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", + PY_SSL_ERROR_ZERO_RETURN); +@@ -1802,6 +3908,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 +@@ -1814,6 +3980,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, +@@ -1825,15 +4094,7 @@ 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; +@@ -1841,4 +4102,9 @@ init_ssl(void) + 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/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 --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 ++""" ++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 --git a/SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch b/SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch new file mode 100644 index 0000000..34fd3ba --- /dev/null +++ b/SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch @@ -0,0 +1,26 @@ +diff -up Python-2.7.5/Lib/test/test_ssl.py.ssl2 Python-2.7.5/Lib/test/test_ssl.py +--- Python-2.7.5/Lib/test/test_ssl.py.ssl2 2015-03-04 12:19:26.345387741 +0100 ++++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-04 12:32:43.485702679 +0100 +@@ -689,7 +689,8 @@ class ContextTests(unittest.TestCase): + @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, ctx.options) ++ ctx.options |= ssl.OP_NO_SSLv2 + self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, + ctx.options) + ctx.options |= ssl.OP_NO_SSLv3 +@@ -2142,9 +2143,9 @@ else: + # 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, ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + client_options=ssl.OP_NO_SSLv3) +- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + client_options=ssl.OP_NO_TLSv1) + + @skip_if_broken_ubuntu_ssl + diff --git a/SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch b/SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch new file mode 100644 index 0000000..87ee80b --- /dev/null +++ b/SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch @@ -0,0 +1,72 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1409232801 14400 +# Node ID 97081a80f487841d81aeed55d398a1dba1faca00 +# Parent 3ae399c6ecf685086ebf07e17717955f21e14cb8 +fix load_verify_locations on unicode paths (closes #22244) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -850,11 +850,14 @@ class ContextTests(unittest.TestCase): + ctx.load_verify_locations(cafile=CERTFILE, capath=None) + ctx.load_verify_locations(BYTES_CERTFILE) + ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None) ++ ctx.load_verify_locations(cafile=BYTES_CERTFILE.decode('utf-8')) + 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.assertRaises(IOError): ++ ctx.load_verify_locations(u'') + with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + ctx.load_verify_locations(BADCERT) + ctx.load_verify_locations(CERTFILE, CAPATH) +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -2628,17 +2628,33 @@ load_verify_locations(PySSLContext *self + } + + if (cafile) { +- cafile_bytes = PyString_AsEncodedObject( +- cafile, Py_FileSystemDefaultEncoding, "strict"); +- if (!cafile_bytes) { +- goto error; ++ if (PyString_Check(cafile)) { ++ Py_INCREF(cafile); ++ cafile_bytes = cafile; ++ } else { ++ PyObject *u = PyUnicode_FromObject(cafile); ++ if (!u) ++ goto error; ++ cafile_bytes = PyUnicode_AsEncodedString( ++ u, Py_FileSystemDefaultEncoding, NULL); ++ Py_DECREF(u); ++ if (!cafile_bytes) ++ goto error; + } + } + if (capath) { +- capath_bytes = PyString_AsEncodedObject( +- capath, Py_FileSystemDefaultEncoding, "strict"); +- if (!capath_bytes) { +- goto error; ++ if (PyString_Check(capath)) { ++ Py_INCREF(capath); ++ capath_bytes = capath; ++ } else { ++ PyObject *u = PyUnicode_FromObject(capath); ++ if (!u) ++ goto error; ++ capath_bytes = PyUnicode_AsEncodedString( ++ u, Py_FileSystemDefaultEncoding, NULL); ++ Py_DECREF(u); ++ if (!capath_bytes) ++ goto error; + } + } + + diff --git a/SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch b/SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch new file mode 100644 index 0000000..eb7866c --- /dev/null +++ b/SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch @@ -0,0 +1,189 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1409233289 14400 +# Node ID 3f73c44b1fd1d442d6841493328e9756fb5e7ef5 +# Parent 97081a80f487841d81aeed55d398a1dba1faca00 +PEP 466: backport hashlib algorithm constants (closes #21307) + +diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst +--- a/Doc/library/hashlib.rst ++++ b/Doc/library/hashlib.rst +@@ -88,6 +88,24 @@ This module provides the following const + + .. versionadded:: 2.7 + ++.. data:: algorithms_guaranteed ++ ++ A set containing the names of the hash algorithms guaranteed to be supported ++ by this module on all platforms. ++ ++ .. versionadded:: 2.7.9 ++ ++.. data:: algorithms_available ++ ++ A set containing the names of the hash algorithms that are available in the ++ running Python interpreter. These names will be recognized when passed to ++ :func:`new`. :attr:`algorithms_guaranteed` will always be a subset. The ++ same algorithm may appear multiple times in this set under different names ++ (thanks to OpenSSL). ++ ++ .. versionadded:: 2.7.9 ++ ++ + The following values are provided as constant attributes of the hash objects + returned by the constructors: + +diff -up Python-2.7.5/Lib/hashlib.py.hash Python-2.7.5/Lib/hashlib.py +--- Python-2.7.5/Lib/hashlib.py.hash 2015-03-04 17:05:57.496598686 +0100 ++++ Python-2.7.5/Lib/hashlib.py 2015-03-04 17:11:34.872739103 +0100 +@@ -18,8 +18,9 @@ than using new(): + + md5(), sha1(), sha224(), sha256(), sha384(), and sha512() + +-More algorithms may be available on your platform but the above are +-guaranteed to exist. ++More algorithms may be available on your platform but the above are guaranteed ++to exist. See the algorithms_guaranteed and algorithms_available attributes ++to find out what algorithm names can be passed to new(). + + NOTE: If you want the adler32 or crc32 hash functions they are available in + the zlib module. +@@ -75,9 +76,14 @@ More condensed: + # always available algorithm is added. + __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') + ++algorithms_guaranteed = set(__always_supported) ++algorithms_available = set(__always_supported) ++ + algorithms = __always_supported + +-__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac') ++__all__ = __always_supported + ('new', 'algorithms_guaranteed', ++ 'algorithms_available', 'algorithms', ++ 'pbkdf2_hmac') + + + def __get_openssl_constructor(name): +@@ -110,6 +116,8 @@ try: + import _hashlib + new = __hash_new + __get_hash = __get_openssl_constructor ++ algorithms_available = algorithms_available.union( ++ _hashlib.openssl_md_meth_names) + except ImportError: + # We don't build the legacy modules + raise +diff -up Python-2.7.5/Modules/_hashopenssl.c.hash Python-2.7.5/Modules/_hashopenssl.c +--- Python-2.7.5/Modules/_hashopenssl.c.hash 2015-03-04 17:06:18.246791837 +0100 ++++ Python-2.7.5/Modules/_hashopenssl.c 2015-03-04 17:16:17.696369000 +0100 +@@ -784,6 +784,61 @@ pbkdf2_hmac(PyObject *self, PyObject *ar + + #endif + ++/* State for our callback function so that it can accumulate a result. */ ++typedef struct _internal_name_mapper_state { ++ PyObject *set; ++ int error; ++} _InternalNameMapperState; ++ ++ ++/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */ ++static void ++_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg) ++{ ++ _InternalNameMapperState *state = (_InternalNameMapperState *)arg; ++ PyObject *py_name; ++ ++ assert(state != NULL); ++ if (openssl_obj_name == NULL) ++ return; ++ /* Ignore aliased names, they pollute the list and OpenSSL appears to ++ * have a its own definition of alias as the resulting list still ++ * contains duplicate and alternate names for several algorithms. */ ++ if (openssl_obj_name->alias) ++ return; ++ ++ py_name = PyString_FromString(openssl_obj_name->name); ++ if (py_name == NULL) { ++ state->error = 1; ++ } else { ++ if (PySet_Add(state->set, py_name) != 0) { ++ state->error = 1; ++ } ++ Py_DECREF(py_name); ++ } ++} ++ ++ ++/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */ ++static PyObject* ++generate_hash_name_list(void) ++{ ++ _InternalNameMapperState state; ++ state.set = PyFrozenSet_New(NULL); ++ if (state.set == NULL) ++ return NULL; ++ state.error = 0; ++ ++ OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state); ++ ++ if (state.error) { ++ Py_DECREF(state.set); ++ return NULL; ++ } ++ return state.set; ++} ++ ++ + /* + * This macro and function generates a family of constructor function + * definitions for specific hash algorithms. These constructors are much +@@ -924,11 +979,11 @@ static struct PyMethodDef EVP_functions[ + PyMODINIT_FUNC + init_hashlib(void) + { +- PyObject *m; ++ PyObject *m, *openssl_md_meth_names; + + SSL_load_error_strings(); + SSL_library_init(); +- OpenSSL_add_all_digests(); ++ ERR_load_crypto_strings(); + + Py_TYPE(&EVPtype) = &PyType_Type; + if (PyType_Ready(&EVPtype) < 0) +@@ -938,6 +993,14 @@ init_hashlib(void) + if (m == NULL) + return; + ++ openssl_md_meth_names = generate_hash_name_list(); ++ if (openssl_md_meth_names == NULL) { ++ return; ++ } ++ if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) { ++ return; ++ } ++ + #if HASH_OBJ_CONSTRUCTOR + Py_INCREF(&EVPtype); + PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype); +diff -up Python-2.7.5/Lib/test/test_hashlib.py.hash Python-2.7.5/Lib/test/test_hashlib.py +--- Python-2.7.5/Lib/test/test_hashlib.py.hash 2015-03-04 18:04:57.823553474 +0100 ++++ Python-2.7.5/Lib/test/test_hashlib.py 2015-03-04 18:06:39.395499123 +0100 +@@ -107,6 +107,15 @@ class HashLibTestCase(unittest.TestCase) + tuple([_algo for _algo in self.supported_hash_names if + _algo.islower()])) + ++ def test_algorithms_guaranteed(self): ++ self.assertEqual(hashlib.algorithms_guaranteed, ++ set(_algo for _algo in self.supported_hash_names ++ if _algo.islower())) ++ ++ def test_algorithms_available(self): ++ self.assertTrue(set(hashlib.algorithms_guaranteed). ++ issubset(hashlib.algorithms_available)) ++ + def test_unknown_hash(self): + self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') + self.assertRaises(TypeError, hashlib.new, 1) diff --git a/SOURCES/00218-pep466-backport-urandom-pers-fd.patch b/SOURCES/00218-pep466-backport-urandom-pers-fd.patch new file mode 100644 index 0000000..0d1a810 --- /dev/null +++ b/SOURCES/00218-pep466-backport-urandom-pers-fd.patch @@ -0,0 +1,171 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1409243400 14400 +# Node ID 3e7f8855078855a9409bc2c1372de89cb021d6c8 +# Parent 3f73c44b1fd1d442d6841493328e9756fb5e7ef5 +PEP 466: backport persistent urandom fd (closes #21305) + +Patch from Alex Gaynor. + +diff --git a/Python/pythonrun.c b/Python/pythonrun.c +--- a/Python/pythonrun.c ++++ b/Python/pythonrun.c +@@ -536,6 +536,7 @@ Py_Finalize(void) + PyInt_Fini(); + PyFloat_Fini(); + PyDict_Fini(); ++ _PyRandom_Fini(); + + #ifdef Py_USING_UNICODE + /* Cleanup Unicode implementation */ +diff --git a/Include/pythonrun.h b/Include/pythonrun.h +index c319c52..57ef2bb 100644 +--- a/Include/pythonrun.h ++++ b/Include/pythonrun.h +@@ -145,6 +145,7 @@ PyAPI_FUNC(void) PyInt_Fini(void); + PyAPI_FUNC(void) PyFloat_Fini(void); + PyAPI_FUNC(void) PyOS_FiniInterrupts(void); + PyAPI_FUNC(void) PyByteArray_Fini(void); ++PyAPI_FUNC(void) _PyRandom_Fini(void); + + PyAPI_DATA(PyThreadState *) _Py_Finalizing; + +diff -up Python-2.7.5/Python/random.c.urandom Python-2.7.5/Python/random.c +--- Python-2.7.5/Python/random.c.urandom 2015-03-06 08:22:10.244699950 +0100 ++++ Python-2.7.5/Python/random.c 2015-03-06 08:24:57.907317272 +0100 +@@ -118,10 +118,16 @@ vms_urandom(unsigned char *buffer, Py_ss + + #if !defined(MS_WINDOWS) && !defined(__VMS) + ++static struct { ++ int fd; ++ dev_t st_dev; ++ ino_t st_ino; ++} urandom_cache = { -1 }; ++ + /* Read size bytes from /dev/urandom into buffer. + Call Py_FatalError() on error. */ + static void +-dev_urandom_noraise(char *buffer, Py_ssize_t size) ++dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size) + { + int fd; + Py_ssize_t n; +@@ -156,22 +162,57 @@ dev_urandom_python(char *buffer, Py_ssiz + { + int fd; + Py_ssize_t n; ++ struct stat st; + + if (size <= 0) + return 0; + +- Py_BEGIN_ALLOW_THREADS +- fd = open("/dev/urandom", O_RDONLY); +- Py_END_ALLOW_THREADS +- if (fd < 0) +- { +- if (errno == ENOENT || errno == ENXIO || +- errno == ENODEV || errno == EACCES) +- PyErr_SetString(PyExc_NotImplementedError, +- "/dev/urandom (or equivalent) not found"); +- else +- PyErr_SetFromErrno(PyExc_OSError); +- return -1; ++ if (urandom_cache.fd >= 0) { ++ /* Does the fd point to the same thing as before? (issue #21207) */ ++ if (fstat(urandom_cache.fd, &st) ++ || st.st_dev != urandom_cache.st_dev ++ || st.st_ino != urandom_cache.st_ino) { ++ /* Something changed: forget the cached fd (but don't close it, ++ since it probably points to something important for some ++ third-party code). */ ++ urandom_cache.fd = -1; ++ } ++ } ++ if (urandom_cache.fd >= 0) ++ fd = urandom_cache.fd; ++ else { ++ Py_BEGIN_ALLOW_THREADS ++ fd = open("/dev/urandom", O_RDONLY); ++ Py_END_ALLOW_THREADS ++ if (fd < 0) ++ { ++ if (errno == ENOENT || errno == ENXIO || ++ errno == ENODEV || errno == EACCES) ++ PyErr_SetString(PyExc_NotImplementedError, ++ "/dev/urandom (or equivalent) not found"); ++ else ++ PyErr_SetFromErrno(PyExc_OSError); ++ return -1; ++ } ++ if (urandom_cache.fd >= 0) { ++ /* urandom_fd was initialized by another thread while we were ++ not holding the GIL, keep it. */ ++ close(fd); ++ fd = urandom_cache.fd; ++ } ++ else { ++ if (fstat(fd, &st)) { ++ PyErr_SetFromErrno(PyExc_OSError); ++ close(fd); ++ return -1; ++ } ++ else { ++ urandom_cache.fd = fd; ++ urandom_cache.st_dev = st.st_dev; ++ urandom_cache.st_ino = st.st_ino; ++ } ++ } ++ + } + + Py_BEGIN_ALLOW_THREADS +@@ -191,12 +235,21 @@ dev_urandom_python(char *buffer, Py_ssiz + PyErr_Format(PyExc_RuntimeError, + "Failed to read %zi bytes from /dev/urandom", + size); +- close(fd); + return -1; + } +- close(fd); + return 0; + } ++ ++static void ++dev_urandom_close(void) ++{ ++ if (urandom_cache.fd >= 0) { ++ close(urandom_cache.fd); ++ urandom_cache.fd = -1; ++ } ++} ++ ++ + #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */ + + /* Fill buffer with pseudo-random bytes generated by a linear congruent +@@ -300,8 +353,21 @@ _PyRandom_Init(void) + # ifdef __VMS + vms_urandom((unsigned char *)secret, secret_size, 0); + # else +- dev_urandom_noraise((char*)secret, secret_size); ++ dev_urandom_noraise((unsigned char*)secret, secret_size); + # endif + #endif + } + } ++ ++void ++_PyRandom_Fini(void) ++{ ++#ifdef MS_WINDOWS ++ if (hCryptProv) { ++ CryptReleaseContext(hCryptProv, 0); ++ hCryptProv = 0; ++ } ++#else ++ dev_urandom_close(); ++#endif ++} diff --git a/SOURCES/00219-pep466-fix-referenced-sslwrap.patch b/SOURCES/00219-pep466-fix-referenced-sslwrap.patch new file mode 100644 index 0000000..f8ccc90 --- /dev/null +++ b/SOURCES/00219-pep466-fix-referenced-sslwrap.patch @@ -0,0 +1,91 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1412221981 14400 +# Node ID 1a36d4e8cf4edfdc4c7d59a40075b8cf00e3ad3c +# Parent 222e0faa5fa9567f657f13fc78a60069142e09ae +fix sslwrap_simple (closes #22523) + +Thanks Alex Gaynor. + +diff --git a/Lib/ssl.py b/Lib/ssl.py +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -969,16 +969,16 @@ def get_protocol_name(protocol_code): + # a replacement for the old socket.ssl function + + def sslwrap_simple(sock, keyfile=None, certfile=None): +- + """A replacement for the old socket.ssl function. Designed + for compability with Python 2.5 and earlier. Will disappear in + Python 3.0.""" +- + if hasattr(sock, "_sock"): + sock = sock._sock + +- ssl_sock = _ssl.sslwrap(sock, 0, keyfile, certfile, CERT_NONE, +- PROTOCOL_SSLv23, None) ++ ctx = SSLContext(PROTOCOL_SSLv23) ++ if keyfile or certfile: ++ ctx.load_cert_chain(certfile, keyfile) ++ ssl_sock = ctx._wrap_socket(sock, server_side=False) + try: + sock.getpeername() + except socket_error: +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -94,6 +94,8 @@ 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) +@@ -2944,7 +2946,7 @@ def test_main(verbose=False): + if not os.path.exists(filename): + raise support.TestFailed("Can't read certificate file %r" % filename) + +- tests = [ContextTests, BasicSocketTests, SSLErrorTests] ++ tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests] + + if support.is_resource_enabled('network'): + tests.append(NetworkedTests) +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -517,10 +517,12 @@ newPySSLSocket(PySSLContext *sslctx, PyS + 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; ++ if (ssl_sock != Py_None) { ++ self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL); ++ if (self->ssl_sock == NULL) { ++ Py_DECREF(self); ++ return NULL; ++ } + } + return self; + } +@@ -2931,8 +2933,12 @@ static int + + ssl = SSL_get_app_data(s); + assert(PySSLSocket_Check(ssl)); +- ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); +- Py_INCREF(ssl_socket); ++ if (ssl->ssl_sock == NULL) { ++ ssl_socket = Py_None; ++ } else { ++ ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); ++ Py_INCREF(ssl_socket); ++ } + if (ssl_socket == Py_None) { + goto error; + } + diff --git a/SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch b/SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch new file mode 100644 index 0000000..152868a --- /dev/null +++ b/SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch @@ -0,0 +1,677 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1416764565 21600 +# Node ID 1882157b298a164291d2b3a8b9525eb0902895f6 +# Parent 588ebc8fd3daf7307961cd614c4da9525bb67313 +allow passing cert/ssl information to urllib2.urlopen and httplib.HTTPSConnection + +This is basically a backport of issues #9003 and #22366. + +diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst +--- a/Doc/library/httplib.rst ++++ b/Doc/library/httplib.rst +@@ -70,12 +70,25 @@ The module provides the following classe + *source_address* was added. + + +-.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address]]]]]]) ++.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address, context, check_hostname]]]]]]) + + A subclass of :class:`HTTPConnection` that uses SSL for communication with +- secure servers. Default port is ``443``. *key_file* is the name of a PEM +- formatted file that contains your private key. *cert_file* is a PEM formatted +- certificate chain file. ++ secure servers. Default port is ``443``. If *context* is specified, it must ++ be a :class:`ssl.SSLContext` instance describing the various SSL options. ++ ++ *key_file* and *cert_file* are deprecated, please use ++ :meth:`ssl.SSLContext.load_cert_chain` instead, or let ++ :func:`ssl.create_default_context` select the system's trusted CA ++ certificates for you. ++ ++ Please read :ref:`ssl-security` for more information on best practices. ++ ++ .. note:: ++ If *context* is specified and has a :attr:`~ssl.SSLContext.verify_mode` ++ of either :data:`~ssl.CERT_OPTIONAL` or :data:`~ssl.CERT_REQUIRED`, then ++ by default *host* is matched against the host name(s) allowed by the ++ server's certificate. If you want to change that behaviour, you can ++ explicitly set *check_hostname* to False. + + .. warning:: + This does not do any verification of the server's certificate. +@@ -88,6 +101,9 @@ The module provides the following classe + .. versionchanged:: 2.7 + *source_address* was added. + ++ .. versionchanged:: 2.7.9 ++ *context* and *check_hostname* was added. ++ + + .. class:: HTTPResponse(sock, debuglevel=0, strict=0) + +diff --git a/Lib/test/keycert2.pem b/Lib/test/keycert2.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/keycert2.pem +@@ -0,0 +1,31 @@ ++-----BEGIN PRIVATE KEY----- ++MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANcLaMB7T/Wi9DBc ++PltGzgt8cxsv55m7PQPHMZvn6Ke8xmNqcmEzib8opRwKGrCV6TltKeFlNSg8dwQK ++Tl4ktyTkGCVweRQJ37AkBayvEBml5s+QD4vlhqkJPsL/Nsd+fnqngOGc5+59+C6r ++s3XpiLlF5ah/z8q92Mnw54nypw1JAgMBAAECgYBE3t2Mj7GbDLZB6rj5yKJioVfI ++BD6bSJEQ7bGgqdQkLFwpKMU7BiN+ekjuwvmrRkesYZ7BFgXBPiQrwhU5J28Tpj5B ++EOMYSIOHfzdalhxDGM1q2oK9LDFiCotTaSdEzMYadel5rmKXJ0zcK2Jho0PCuECf ++tf/ghRxK+h1Hm0tKgQJBAO6MdGDSmGKYX6/5kPDje7we/lSLorSDkYmV0tmVShsc ++JxgaGaapazceA/sHL3Myx7Eenkip+yPYDXEDFvAKNDECQQDmxsT9NOp6mo7ISvky ++GFr2vVHsJ745BMWoma4rFjPBVnS8RkgK+b2EpDCdZSrQ9zw2r8sKTgrEyrDiGTEg ++wJyZAkA8OOc0flYMJg2aHnYR6kwVjPmGHI5h5gk648EMPx0rROs1sXkiUwkHLCOz ++HvhCq+Iv+9vX2lnVjbiu/CmxRdIxAkA1YEfzoKeTD+hyXxTgB04Sv5sRGegfXAEz ++i8gC4zG5R/vcCA1lrHmvEiLEZL/QcT6WD3bQvVg0SAU9ZkI8pxARAkA7yqMSvP1l ++gJXy44R+rzpLYb1/PtiLkIkaKG3x9TUfPnfD2jY09fPkZlfsRU3/uS09IkhSwimV ++d5rWoljEfdou ++-----END PRIVATE KEY----- ++-----BEGIN CERTIFICATE----- ++MIICXTCCAcagAwIBAgIJALVQzebTtrXFMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV ++BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u ++IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x ++NDExMjMxNzAwMDdaFw0yNDExMjAxNzAwMDdaMGIxCzAJBgNVBAYTAlhZMRcwFQYD ++VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv ++dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF ++AAOBjQAwgYkCgYEA1wtowHtP9aL0MFw+W0bOC3xzGy/nmbs9A8cxm+fop7zGY2py ++YTOJvyilHAoasJXpOW0p4WU1KDx3BApOXiS3JOQYJXB5FAnfsCQFrK8QGaXmz5AP ++i+WGqQk+wv82x35+eqeA4Zzn7n34LquzdemIuUXlqH/Pyr3YyfDnifKnDUkCAwEA ++AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB ++AKuay3vDKfWzt5+ch/HHBsert84ISot4fUjzXDA/oOgTOEjVcSShHxqNShMOW1oA ++QYBpBB/5Kx5RkD/w6imhucxt2WQPRgjX4x4bwMipVH/HvFDp03mG51/Cpi1TyZ74 ++El7qa/Pd4lHhOLzMKBA6503fpeYSFUIBxZbGLqylqRK7 ++-----END CERTIFICATE----- +diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/selfsigned_pythontestdotnet.pem +@@ -0,0 +1,16 @@ ++-----BEGIN CERTIFICATE----- ++MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV ++BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u ++IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv ++bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG ++A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo ++b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 ++aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ ++Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm ++Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv ++EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl ++bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM ++eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV ++HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97 ++vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9 ++-----END CERTIFICATE----- +diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py +--- a/Lib/test/test_urllib2.py ++++ b/Lib/test/test_urllib2.py +@@ -8,6 +8,11 @@ import StringIO + import urllib2 + from urllib2 import Request, OpenerDirector + ++try: ++ import ssl ++except ImportError: ++ ssl = None ++ + # XXX + # Request + # CacheFTPHandler (hard to write) +@@ -47,6 +52,14 @@ class TrivialTests(unittest.TestCase): + for string, list in tests: + self.assertEqual(urllib2.parse_http_list(string), list) + ++ @unittest.skipUnless(ssl, "ssl module required") ++ def test_cafile_and_context(self): ++ context = ssl.create_default_context() ++ with self.assertRaises(ValueError): ++ urllib2.urlopen( ++ "https://localhost", cafile="/nonexistent/path", context=context ++ ) ++ + + def test_request_headers_dict(): + """ +diff --git a/Lib/urllib2.py b/Lib/urllib2.py +--- a/Lib/urllib2.py ++++ b/Lib/urllib2.py +@@ -109,6 +109,14 @@ try: + except ImportError: + from StringIO import StringIO + ++# check for SSL ++try: ++ import ssl ++except ImportError: ++ _have_ssl = False ++else: ++ _have_ssl = True ++ + from urllib import (unwrap, unquote, splittype, splithost, quote, + addinfourl, splitport, splittag, toBytes, + splitattr, ftpwrapper, splituser, splitpasswd, splitvalue) +@@ -120,11 +128,30 @@ from urllib import localhost, url2pathna + __version__ = sys.version[:3] + + _opener = None +-def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): ++def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, ++ cafile=None, capath=None, cadefault=False, context=None): + global _opener +- if _opener is None: +- _opener = build_opener() +- return _opener.open(url, data, timeout) ++ if cafile or capath or cadefault: ++ if context is not None: ++ raise ValueError( ++ "You can't pass both context and any of cafile, capath, and " ++ "cadefault" ++ ) ++ if not _have_ssl: ++ raise ValueError('SSL support not available') ++ context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED, ++ cafile=cafile, ++ capath=capath) ++ https_handler = HTTPSHandler(context=context, check_hostname=True) ++ opener = build_opener(https_handler) ++ elif context: ++ https_handler = HTTPSHandler(context=context) ++ opener = build_opener(https_handler) ++ elif _opener is None: ++ _opener = opener = build_opener() ++ else: ++ opener = _opener ++ return opener.open(url, data, timeout) + + def install_opener(opener): + global _opener +@@ -1121,7 +1148,7 @@ class AbstractHTTPHandler(BaseHandler): + + return request + +- def do_open(self, http_class, req): ++ def do_open(self, http_class, req, **http_conn_args): + """Return an addinfourl object for the request, using http_class. + + http_class must implement the HTTPConnection API from httplib. +@@ -1135,7 +1162,8 @@ class AbstractHTTPHandler(BaseHandler): + if not host: + raise URLError('no host given') + +- h = http_class(host, timeout=req.timeout) # will parse host:port ++ # will parse host:port ++ h = http_class(host, timeout=req.timeout, **http_conn_args) + h.set_debuglevel(self._debuglevel) + + headers = dict(req.unredirected_hdrs) +@@ -1203,8 +1231,14 @@ class HTTPHandler(AbstractHTTPHandler): + if hasattr(httplib, 'HTTPS'): + class HTTPSHandler(AbstractHTTPHandler): + ++ def __init__(self, debuglevel=0, context=None, check_hostname=None): ++ AbstractHTTPHandler.__init__(self, debuglevel) ++ self._context = context ++ self._check_hostname = check_hostname ++ + def https_open(self, req): +- return self.do_open(httplib.HTTPSConnection, req) ++ return self.do_open(httplib.HTTPSConnection, req, ++ context=self._context, check_hostname=self._check_hostname) + + https_request = AbstractHTTPHandler.do_request_ + +diff -up Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx Python-2.7.5/Lib/test/test_urllib2_localnet.py +--- Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx 2015-03-30 10:13:48.351310552 +0200 ++++ Python-2.7.5/Lib/test/test_urllib2_localnet.py 2015-03-30 10:14:54.715713679 +0200 +@@ -1,3 +1,4 @@ ++import os + import urlparse + import urllib2 + import BaseHTTPServer +@@ -11,6 +12,17 @@ from test import test_support + mimetools = test_support.import_module('mimetools', deprecated=True) + threading = test_support.import_module('threading') + ++try: ++ import ssl ++except ImportError: ++ ssl = None ++ ++here = os.path.dirname(__file__) ++# Self-signed cert file for 'localhost' ++CERT_localhost = os.path.join(here, 'keycert.pem') ++# Self-signed cert file for 'fakehostname' ++CERT_fakehostname = os.path.join(here, 'keycert2.pem') ++ + # Loopback http server infrastructure + + class LoopbackHttpServer(BaseHTTPServer.HTTPServer): +@@ -25,7 +37,7 @@ class LoopbackHttpServer(BaseHTTPServer. + + # Set the timeout of our listening socket really low so + # that we can stop the server easily. +- self.socket.settimeout(1.0) ++ self.socket.settimeout(0.1) + + def get_request(self): + """BaseHTTPServer method, overridden.""" +@@ -354,6 +366,19 @@ class TestUrlopen(BaseTestCase): + urllib2.install_opener(opener) + super(TestUrlopen, self).setUp() + ++ def urlopen(self, url, data=None, **kwargs): ++ l = [] ++ f = urllib2.urlopen(url, data, **kwargs) ++ try: ++ # Exercise various methods ++ l.extend(f.readlines(200)) ++ l.append(f.readline()) ++ l.append(f.read(1024)) ++ l.append(f.read()) ++ finally: ++ f.close() ++ return b"".join(l) ++ + def start_server(self, responses): + handler = GetRequestHandler(responses) + +@@ -364,6 +389,16 @@ class TestUrlopen(BaseTestCase): + handler.port = port + return handler + ++ def start_https_server(self, responses=None, **kwargs): ++ if not hasattr(urllib2, 'HTTPSHandler'): ++ self.skipTest('ssl support required') ++ from test.ssl_servers import make_https_server ++ if responses is None: ++ responses = [(200, [], b"we care a bit")] ++ handler = GetRequestHandler(responses) ++ server = make_https_server(self, handler_class=handler, **kwargs) ++ handler.port = server.port ++ return handler + + def test_redirection(self): + expected_response = 'We got here...' +@@ -434,6 +469,28 @@ class TestUrlopen(BaseTestCase): + finally: + self.server.stop() + ++ def test_https(self): ++ handler = self.start_https_server() ++ context = ssl.create_default_context(cafile=CERT_localhost) ++ data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context) ++ self.assertEqual(data, b"we care a bit") ++ ++ def test_https_with_cafile(self): ++ handler = self.start_https_server(certfile=CERT_localhost) ++ import ssl ++ # Good cert ++ data = self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cafile=CERT_localhost) ++ self.assertEqual(data, b"we care a bit") ++ # Bad cert ++ with self.assertRaises(urllib2.URLError) as cm: ++ self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cafile=CERT_fakehostname) ++ # Good cert, but mismatching hostname ++ handler = self.start_https_server(certfile=CERT_fakehostname) ++ with self.assertRaises(ssl.CertificateError) as cm: ++ self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cafile=CERT_fakehostname) + + def test_sending_headers(self): + handler = self.start_server([(200, [], "we don't care")]) +diff -up Python-2.7.5/Doc/library/urllib2.rst.ctx Python-2.7.5/Doc/library/urllib2.rst +--- Python-2.7.5/Doc/library/urllib2.rst.ctx 2015-03-30 10:20:15.958747076 +0200 ++++ Python-2.7.5/Doc/library/urllib2.rst 2015-03-30 10:30:46.172779366 +0200 +@@ -22,13 +22,10 @@ redirections, cookies and more. + The :mod:`urllib2` module defines the following functions: + + +-.. function:: urlopen(url[, data][, timeout]) ++.. function:: urlopen(url[, data[, timeout[, cafile[, capath[, cadefault[, context]]]]]) + + Open the URL *url*, which can be either a string or a :class:`Request` object. + +- .. warning:: +- HTTPS requests do not do any verification of the server's certificate. +- + *data* may be a string specifying additional data to send to the server, or + ``None`` if no such data is needed. Currently HTTP requests are the only ones + that use *data*; the HTTP request will be a POST instead of a GET when the +@@ -41,7 +38,19 @@ The :mod:`urllib2` module defines the following functions: + The optional *timeout* parameter specifies a timeout in seconds for blocking + operations like the connection attempt (if not specified, the global default + timeout setting will be used). This actually only works for HTTP, HTTPS and +- FTP connections. ++ FTP connections. ++ ++ If *context* is specified, it must be a :class:`ssl.SSLContext` instance ++ describing the various SSL options. See :class:`~httplib.HTTPSConnection` for ++ more details. ++ ++ The optional *cafile* and *capath* parameters specify a set of trusted CA ++ certificates for HTTPS requests. *cafile* should point to a single file ++ containing a bundle of CA certificates, whereas *capath* should point to a ++ directory of hashed certificate files. More information can be found in ++ :meth:`ssl.SSLContext.load_verify_locations`. ++ ++ The *cadefault* parameter is ignored. + + This function returns a file-like object with three additional methods: + +@@ -66,7 +75,10 @@ The :mod:`urllib2` module defines the fo + handled through the proxy. + + .. versionchanged:: 2.6 +- *timeout* was added. ++ *timeout* was added. ++ ++ .. versionchanged:: 2.7.9 ++ *cafile*, *capath*, *cadefault*, and *context* were added. + + + .. function:: install_opener(opener) +@@ -280,9 +292,13 @@ The following classes are provided: + A class to handle opening of HTTP URLs. + + +-.. class:: HTTPSHandler() ++.. class:: HTTPSHandler([debuglevel[, context[, check_hostname]]]) ++ ++ A class to handle opening of HTTPS URLs. *context* and *check_hostname* have ++ the same meaning as for :class:`httplib.HTTPSConnection`. + +- A class to handle opening of HTTPS URLs. ++ .. versionchanged:: 2.7.9 ++ *context* and *check_hostname* were added. + + + .. class:: FileHandler() +diff -up Python-2.7.5/Lib/httplib.py.ctx Python-2.7.5/Lib/httplib.py +--- Python-2.7.5/Lib/httplib.py.ctx 2015-03-30 10:19:52.551521393 +0200 ++++ Python-2.7.5/Lib/httplib.py 2015-03-30 10:30:05.045386751 +0200 +@@ -1159,21 +1159,44 @@ else: + + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, +- source_address=None): ++ source_address=None, context=None, check_hostname=None): + HTTPConnection.__init__(self, host, port, strict, timeout, + source_address) + self.key_file = key_file + self.cert_file = cert_file ++ if context is None: ++ context = ssl.create_default_context() ++ will_verify = context.verify_mode != ssl.CERT_NONE ++ if check_hostname is None: ++ check_hostname = will_verify ++ elif check_hostname and not will_verify: ++ raise ValueError("check_hostname needs a SSL context with " ++ "either CERT_OPTIONAL or CERT_REQUIRED") ++ if key_file or cert_file: ++ context.load_cert_chain(cert_file, key_file) ++ self._context = context ++ self._check_hostname = check_hostname + + def connect(self): + "Connect to a host on a given (SSL) port." + +- sock = self._create_connection((self.host, self.port), +- self.timeout, self.source_address) ++ HTTPConnection.connect(self) ++ + if self._tunnel_host: +- self.sock = sock +- self._tunnel() +- self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) ++ server_hostname = self._tunnel_host ++ else: ++ server_hostname = self.host ++ sni_hostname = server_hostname if ssl.HAS_SNI else None ++ ++ self.sock = self._context.wrap_socket(self.sock, ++ server_hostname=sni_hostname) ++ if not self._context.check_hostname and self._check_hostname: ++ try: ++ ssl.match_hostname(self.sock.getpeercert(), server_hostname) ++ except Exception: ++ self.sock.shutdown(socket.SHUT_RDWR) ++ self.sock.close() ++ raise + + __all__.append("HTTPSConnection") + +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +index 4b2a638..f7e0583 100644 +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -1,6 +1,7 @@ + import httplib + import array + import httplib ++import os + import StringIO + import socket + import errno +@@ -10,6 +11,14 @@ TestCase = unittest.TestCase + + from test import test_support + ++here = os.path.dirname(__file__) ++# Self-signed cert file for 'localhost' ++CERT_localhost = os.path.join(here, 'keycert.pem') ++# Self-signed cert file for 'fakehostname' ++CERT_fakehostname = os.path.join(here, 'keycert2.pem') ++# Self-signed cert file for self-signed.pythontest.net ++CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') ++ + HOST = test_support.HOST + + class FakeSocket: +@@ -507,35 +516,140 @@ class TimeoutTest(TestCase): + httpConn.close() + + +-class HTTPSTimeoutTest(TestCase): ++class HTTPSTest(TestCase): + # XXX Here should be tests for HTTPS, there isn't any right now! ++ def setUp(self): ++ if not hasattr(httplib, 'HTTPSConnection'): ++ self.skipTest('ssl support required') ++ ++ def make_server(self, certfile): ++ from test.ssl_servers import make_https_server ++ return make_https_server(self, certfile=certfile) + + def test_attributes(self): +- # simple test to check it's storing it +- if hasattr(httplib, 'HTTPSConnection'): +- h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) +- self.assertEqual(h.timeout, 30) ++ # simple test to check it's storing the timeout ++ h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) ++ self.assertEqual(h.timeout, 30) ++ ++ def test_networked(self): ++ # Default settings: requires a valid cert from a trusted CA ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) ++ with self.assertRaises(ssl.SSLError) as exc_info: ++ h.request('GET', '/') ++ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') ++ ++ def test_networked_noverification(self): ++ # Switch off cert verification ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ context = ssl._create_stdlib_context() ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, ++ context=context) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ self.assertIn('nginx', resp.getheader('server')) ++ ++ def test_networked_trusted_by_default_cert(self): ++ # Default settings: requires a valid cert from a trusted CA ++ test_support.requires('network') ++ with test_support.transient_internet('www.python.org'): ++ h = httplib.HTTPSConnection('www.python.org', 443) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ content_type = resp.getheader('content-type') ++ self.assertIn('text/html', content_type) ++ ++ def test_networked_good_cert(self): ++ # We feed the server's cert as a validating cert ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_selfsigned_pythontestdotnet) ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ server_string = resp.getheader('server') ++ self.assertIn('nginx', server_string) ++ ++ def test_networked_bad_cert(self): ++ # We feed a "CA" cert that is unrelated to the server's cert ++ import ssl ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_localhost) ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) ++ with self.assertRaises(ssl.SSLError) as exc_info: ++ h.request('GET', '/') ++ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') ++ ++ def test_local_unknown_cert(self): ++ # The custom cert isn't known to the default trust bundle ++ import ssl ++ server = self.make_server(CERT_localhost) ++ h = httplib.HTTPSConnection('localhost', server.port) ++ with self.assertRaises(ssl.SSLError) as exc_info: ++ h.request('GET', '/') ++ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') ++ ++ def test_local_good_hostname(self): ++ # The (valid) cert validates the HTTP hostname ++ import ssl ++ server = self.make_server(CERT_localhost) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_localhost) ++ h = httplib.HTTPSConnection('localhost', server.port, context=context) ++ h.request('GET', '/nonexistent') ++ resp = h.getresponse() ++ self.assertEqual(resp.status, 404) ++ ++ def test_local_bad_hostname(self): ++ # The (valid) cert doesn't validate the HTTP hostname ++ import ssl ++ server = self.make_server(CERT_fakehostname) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.verify_mode = ssl.CERT_REQUIRED ++ context.load_verify_locations(CERT_fakehostname) ++ h = httplib.HTTPSConnection('localhost', server.port, context=context) ++ with self.assertRaises(ssl.CertificateError): ++ h.request('GET', '/') ++ # Same with explicit check_hostname=True ++ h = httplib.HTTPSConnection('localhost', server.port, context=context, ++ check_hostname=True) ++ with self.assertRaises(ssl.CertificateError): ++ h.request('GET', '/') ++ # With check_hostname=False, the mismatching is ignored ++ h = httplib.HTTPSConnection('localhost', server.port, context=context, ++ check_hostname=False) ++ h.request('GET', '/nonexistent') ++ resp = h.getresponse() ++ self.assertEqual(resp.status, 404) + +- @unittest.skipIf(not hasattr(httplib, 'HTTPS'), 'httplib.HTTPS not available') + def test_host_port(self): + # Check invalid host_port + +- # Note that httplib does not accept user:password@ in the host-port. + for hp in ("www.python.org:abc", "user:password@www.python.org"): +- self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp) ++ self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp) + +- for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b", +- 8000), +- ("pypi.python.org:443", "pypi.python.org", 443), +- ("pypi.python.org", "pypi.python.org", 443), +- ("pypi.python.org:", "pypi.python.org", 443), +- ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443)): +- http = httplib.HTTPS(hp) +- c = http._conn +- if h != c.host: +- self.fail("Host incorrectly parsed: %s != %s" % (h, c.host)) +- if p != c.port: +- self.fail("Port incorrectly parsed: %s != %s" % (p, c.host)) ++ for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", ++ "fe80::207:e9ff:fe9b", 8000), ++ ("www.python.org:443", "www.python.org", 443), ++ ("www.python.org:", "www.python.org", 443), ++ ("www.python.org", "www.python.org", 443), ++ ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443), ++ ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", ++ 443)): ++ c = httplib.HTTPSConnection(hp) ++ self.assertEqual(h, c.host) ++ self.assertEqual(p, c.port) + + + class TunnelTests(TestCase): +@@ -576,10 +690,10 @@ class TunnelTests(TestCase): + self.assertTrue('CONNECT destination.com' in conn.sock.data) + self.assertTrue('Host: destination.com' in conn.sock.data) + +- ++@test_support.reap_threads + def test_main(verbose=None): + test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, +- HTTPSTimeoutTest, SourceAddressTest, TunnelTests) ++ HTTPSTest, SourceAddressTest) + + if __name__ == '__main__': + test_main() +diff -up Python-2.7.5/Lib/test/test_ssl.py.ctx Python-2.7.5/Lib/test/test_ssl.py +--- Python-2.7.5/Lib/test/test_ssl.py.ctx 2015-03-30 10:18:55.677973042 +0200 ++++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-30 10:22:02.323772604 +0200 +@@ -14,7 +14,7 @@ import os + import errno + import pprint + import tempfile +-import urllib ++import urllib2 + import traceback + import weakref + import platform +@@ -2332,9 +2332,10 @@ else: + 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) ++ url = 'https://localhost:%d/%s' % ( ++ server.port, os.path.split(CERTFILE)[1]) ++ context = ssl.create_default_context(cafile=CERTFILE) ++ f = urllib2.urlopen(url, context=context) + try: + dlen = f.info().getheader("content-length") + if dlen and (int(dlen) > 0): diff --git a/SOURCES/00221-pep466-backport-sslwrap-c-ssl.patch b/SOURCES/00221-pep466-backport-sslwrap-c-ssl.patch new file mode 100644 index 0000000..521d6b8 --- /dev/null +++ b/SOURCES/00221-pep466-backport-sslwrap-c-ssl.patch @@ -0,0 +1,266 @@ +diff --git a/_ssl.c b/_ssl.c +index 5fb6e28..1332547 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -226,6 +226,19 @@ typedef struct { + enum py_ssl_server_or_client socket_type; + } PySSLSocket; + ++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 PyTypeObject PySSLContext_Type; + static PyTypeObject PySSLSocket_Type; + +@@ -527,6 +540,203 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, + return self; + } + ++static PySSLObject * ++newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file, ++ 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) ++{ ++ PySSLObject *self; ++ char *errstr = NULL; ++ int ret; ++ int verification_mode; ++ long options; ++ ++ self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ ++ 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->shutdown_seen_zero = 0; ++ ++ /* 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 */ ++ options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; ++ if (proto_version != PY_SSL_VERSION_SSL2) ++ options |= SSL_OP_NO_SSLv2; ++ SSL_CTX_set_options(self->ctx, options); ++ ++ 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 */ ++ PySSL_END_ALLOW_THREADS ++ SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ ++#ifdef SSL_MODE_AUTO_RETRY ++ SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); ++#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 */ ++ BIO_set_nbio(SSL_get_rbio(self->ssl), 1); ++ BIO_set_nbio(SSL_get_wbio(self->ssl), 1); ++ } ++ ++ PySSL_BEGIN_ALLOW_THREADS ++ if (socket_type == PY_SSL_CLIENT) ++ SSL_set_connect_state(self->ssl); ++ else ++ SSL_set_accept_state(self->ssl); ++ PySSL_END_ALLOW_THREADS ++ ++ self->Socket = Sock; ++ Py_INCREF(self->Socket); ++ 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 */ + +@@ -1911,6 +2121,7 @@ static PyGetSetDef ssl_getsetlist[] = { + }; + + static PyMethodDef PySSLMethods[] = { ++ {"sslwrap", PySSL_sslwrap, METH_VARARGS, ssl_doc}, + {"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS}, + {"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, + PySSL_SSLwrite_doc}, +@@ -1969,6 +2180,29 @@ static PyTypeObject PySSLSocket_Type = { + ssl_getsetlist, /*tp_getset*/ + }; + ++static PyObject *PySSL_getattr(PySSLObject *self, char *name) ++{ ++ return Py_FindMethod(PySSLMethods, (PyObject *)self, name); ++} ++ ++static PyTypeObject PySSL_Type = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "ssl.SSLContext", /*tp_name*/ ++ sizeof(PySSLObject), /*tp_basicsize*/ ++ 0, /*tp_itemsize*/ ++ /* methods */ ++ (destructor)PySSL_dealloc, /*tp_dealloc*/ ++ 0, /*tp_print*/ ++ (getattrfunc)PySSL_getattr, /*tp_getattr*/ ++ 0, /*tp_setattr*/ ++ 0, /*tp_compare*/ ++ 0, /*tp_repr*/ ++ 0, /*tp_as_number*/ ++ 0, /*tp_as_sequence*/ ++ 0, /*tp_as_mapping*/ ++ 0, /*tp_hash*/ ++}; ++ + + /* + * _SSLContext objects diff --git a/SOURCES/00222-add-2014-bit-dh-key.patch b/SOURCES/00222-add-2014-bit-dh-key.patch new file mode 100644 index 0000000..6a7838e --- /dev/null +++ b/SOURCES/00222-add-2014-bit-dh-key.patch @@ -0,0 +1,49 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1427947446 14400 +# Node ID 4f2391e866434a94ca6d87dff5ea01fcab91d08a +# Parent 5d88f653187203d85f4cfd4877f093af3919035b +replace 512 bit dh key with a 2014 bit one (closes #23844) + +Patch by Cédric Krier. + +diff --git a/Lib/test/dh1024.pem b/Lib/test/dh1024.pem +new file mode 100644 +--- /dev/null ++++ b/Lib/test/dh1024.pem +@@ -0,0 +1,7 @@ ++-----BEGIN DH PARAMETERS----- ++MIGHAoGBAIbzw1s9CT8SV5yv6L7esdAdZYZjPi3qWFs61CYTFFQnf2s/d09NYaJt ++rrvJhIzWavqnue71qXCf83/J3nz3FEwUU/L0mGyheVbsSHiI64wUo3u50wK5Igo0 ++RNs/LD0irs7m0icZ//hijafTU+JOBiuA8zMI+oZfU7BGuc9XrUprAgEC ++-----END DH PARAMETERS----- ++ ++Generated with: openssl dhparam -out dh1024.pem 1024 +diff --git a/Lib/test/dh512.pem b/Lib/test/dh512.pem +deleted file mode 100644 +--- a/Lib/test/dh512.pem ++++ /dev/null +@@ -1,9 +0,0 @@ +------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/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -66,7 +66,7 @@ BADKEY = data_file("badkey.pem") + NOKIACERT = data_file("nokia.pem") + NULLBYTECERT = data_file("nullbytecert.pem") + +-DHFILE = data_file("dh512.pem") ++DHFILE = data_file("dh1024.pem") + BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding()) + + + diff --git a/SOURCES/00223-pep476-verify-certs-by-default.patch b/SOURCES/00223-pep476-verify-certs-by-default.patch new file mode 100644 index 0000000..d62703f --- /dev/null +++ b/SOURCES/00223-pep476-verify-certs-by-default.patch @@ -0,0 +1,153 @@ + +# HG changeset patch +# User Benjamin Peterson +# Date 1416798122 21600 +# Node ID fb83916c3ea12899569e88a7505469a90ab1f674 +# Parent c84f36a5f556867c2ec50453dc879a500032d377 +pep 476: verify certificates by default (#22417) + +diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst +--- a/Doc/library/httplib.rst ++++ b/Doc/library/httplib.rst +@@ -90,9 +90,6 @@ The module provides the following classe + server's certificate. If you want to change that behaviour, you can + explicitly set *check_hostname* to False. + +- .. warning:: +- This does not do any verification of the server's certificate. +- + .. versionadded:: 2.0 + + .. versionchanged:: 2.6 +@@ -104,6 +101,11 @@ The module provides the following classe + .. versionchanged:: 2.7.9 + *context* and *check_hostname* was added. + ++ This class now performs all the necessary certificate and hostname checks ++ by default. To revert to the previous, unverified, behavior ++ :func:`ssl._create_unverified_context` can be passed to the *context* ++ parameter. ++ + + .. class:: HTTPResponse(sock, debuglevel=0, strict=0) + +diff --git a/Lib/httplib.py b/Lib/httplib.py +--- a/Lib/httplib.py ++++ b/Lib/httplib.py +@@ -1193,7 +1193,7 @@ else: + self.key_file = key_file + self.cert_file = cert_file + if context is None: +- context = ssl.create_default_context() ++ context = ssl._create_default_https_context() + will_verify = context.verify_mode != ssl.CERT_NONE + if check_hostname is None: + check_hostname = will_verify +diff --git a/Lib/ssl.py b/Lib/ssl.py +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -427,8 +427,7 @@ def create_default_context(purpose=Purpo + context.load_default_certs(purpose) + return context + +- +-def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, ++def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, + check_hostname=False, purpose=Purpose.SERVER_AUTH, + certfile=None, keyfile=None, + cafile=None, capath=None, cadata=None): +@@ -469,6 +468,14 @@ def _create_stdlib_context(protocol=PROT + + return context + ++# Used by http.client if no context is explicitly passed. ++_create_default_https_context = create_default_context ++ ++ ++# Backwards compatibility alias, even though it's not a public name. ++_create_stdlib_context = _create_unverified_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 +diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -1,10 +1,9 @@ + import httplib + import array +-import httplib +-import os + import StringIO + import socket + import errno ++import os + + import unittest + TestCase = unittest.TestCase +diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py +--- a/Lib/test/test_urllib2_localnet.py ++++ b/Lib/test/test_urllib2_localnet.py +@@ -5,6 +5,7 @@ import urllib2 + import BaseHTTPServer + import unittest + import hashlib ++import ssl + + from test import test_support + +@@ -562,15 +563,37 @@ class TestUrlopen(BaseTestCase): + cafile=CERT_localhost) + self.assertEqual(data, b"we care a bit") + # Bad cert +- with self.assertRaises(urllib2.URLError) as cm: ++ with self.assertRaises(urllib2.URLError): + self.urlopen("https://localhost:%s/bizarre" % handler.port, + cafile=CERT_fakehostname) + # Good cert, but mismatching hostname + handler = self.start_https_server(certfile=CERT_fakehostname) +- with self.assertRaises(ssl.CertificateError) as cm: ++ with self.assertRaises(ssl.CertificateError): + self.urlopen("https://localhost:%s/bizarre" % handler.port, + cafile=CERT_fakehostname) + ++ def test_https_with_cadefault(self): ++ handler = self.start_https_server(certfile=CERT_localhost) ++ # Self-signed cert should fail verification with system certificate store ++ with self.assertRaises(urllib2.URLError): ++ self.urlopen("https://localhost:%s/bizarre" % handler.port, ++ cadefault=True) ++ ++ def test_https_sni(self): ++ if ssl is None: ++ self.skipTest("ssl module required") ++ if not ssl.HAS_SNI: ++ self.skipTest("SNI support required in OpenSSL") ++ sni_name = [None] ++ def cb_sni(ssl_sock, server_name, initial_context): ++ sni_name[0] = server_name ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context.set_servername_callback(cb_sni) ++ handler = self.start_https_server(context=context, certfile=CERT_localhost) ++ context = ssl.create_default_context(cafile=CERT_localhost) ++ self.urlopen("https://localhost:%s" % handler.port, context=context) ++ self.assertEqual(sni_name[0], "localhost") ++ + def test_sending_headers(self): + handler = self.start_server([(200, [], "we don't care")]) + +diff -up Python-2.7.5/Doc/library/xmlrpclib.rst.ver Python-2.7.5/Doc/library/xmlrpclib.rst +--- Python-2.7.5/Doc/library/xmlrpclib.rst.ver 2015-03-30 13:59:29.243493601 +0200 ++++ Python-2.7.5/Doc/library/xmlrpclib.rst 2015-03-30 14:03:40.509532180 +0200 +@@ -34,6 +34,10 @@ between conformable Python objects and X + constructed data. If you need to parse untrusted or unauthenticated data see + :ref:`xml-vulnerabilities`. + ++.. versionchanged:: 2.7.9 ++ ++ For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate ++ and hostname checks by default + + .. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) + diff --git a/SOURCES/00224-pep476-add-toggle-for-cert-verify.patch b/SOURCES/00224-pep476-add-toggle-for-cert-verify.patch new file mode 100644 index 0000000..d0d37ab --- /dev/null +++ b/SOURCES/00224-pep476-add-toggle-for-cert-verify.patch @@ -0,0 +1,104 @@ +diff -up Python-2.7.5/Lib/ssl.py.cert Python-2.7.5/Lib/ssl.py +--- Python-2.7.5/Lib/ssl.py.cert 2015-03-30 14:52:12.172241615 +0200 ++++ Python-2.7.5/Lib/ssl.py 2015-03-30 15:16:49.168185354 +0200 +@@ -466,8 +466,27 @@ def _create_unverified_context(protocol= + + return context + ++_cert_verification_config = '/opt/rh/python27/root/etc/python/cert-verification.cfg' ++ ++def _get_verify_status(protocol): ++ context_factory = { ++ 'platform_default': _create_unverified_context, ++ 'enable': create_default_context, ++ 'disable': _create_unverified_context ++ } ++ import ConfigParser ++ try: ++ config = ConfigParser.RawConfigParser() ++ config.read(_cert_verification_config) ++ status = config.get(protocol, 'verify') ++ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): ++ status = 'platform_default' ++ default = context_factory.get('platform_default') ++ return context_factory.get(status, default) ++ ++ + # Used by http.client if no context is explicitly passed. +-_create_default_https_context = create_default_context ++_create_default_https_context = _get_verify_status('https') + + + # Backwards compatibility alias, even though it's not a public name. +diff -up Python-2.7.5/Lib/test/test_httplib.py.cert Python-2.7.5/Lib/test/test_httplib.py +--- Python-2.7.5/Lib/test/test_httplib.py.cert 2015-03-30 16:45:30.738794461 +0200 ++++ Python-2.7.5/Lib/test/test_httplib.py 2015-03-30 16:54:48.065062351 +0200 +@@ -516,12 +516,24 @@ class HTTPSTest(TestCase): + h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) + self.assertEqual(h.timeout, 30) + ++ def test_networked_default(self): ++ # specific to RHEL ++ # Default settings: doesnt requires a valid cert from a trusted CA ++ test_support.requires('network') ++ with test_support.transient_internet('self-signed.pythontest.net'): ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) ++ h.request('GET', '/') ++ resp = h.getresponse() ++ self.assertIn('nginx', resp.getheader('server')) ++ ++ # We have to pass safe context to test cert verification ++ # RHEL by default disable cert verification + def test_networked(self): +- # Default settings: requires a valid cert from a trusted CA + import ssl + test_support.requires('network') + with test_support.transient_internet('self-signed.pythontest.net'): +- h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) ++ context = ssl.create_default_context() ++ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') +@@ -542,8 +554,10 @@ class HTTPSTest(TestCase): + def test_networked_trusted_by_default_cert(self): + # Default settings: requires a valid cert from a trusted CA + test_support.requires('network') ++ import ssl + with test_support.transient_internet('www.python.org'): +- h = httplib.HTTPSConnection('www.python.org', 443) ++ context = ssl.create_default_context() ++ h = httplib.HTTPSConnection('www.python.org', 443, context=context) + h.request('GET', '/') + resp = h.getresponse() + content_type = resp.getheader('content-type') +@@ -579,7 +592,8 @@ class HTTPSTest(TestCase): + # The custom cert isn't known to the default trust bundle + import ssl + server = self.make_server(CERT_localhost) +- h = httplib.HTTPSConnection('localhost', server.port) ++ context = ssl.create_default_context() ++ h = httplib.HTTPSConnection('localhost', server.port, context=context) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') +@@ -624,6 +638,9 @@ class HTTPSTest(TestCase): + for hp in ("www.python.org:abc", "user:password@www.python.org"): + self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp) + ++ import ssl ++ context = ssl.create_default_context() ++ + for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", + "fe80::207:e9ff:fe9b", 8000), + ("www.python.org:443", "www.python.org", 443), +@@ -632,7 +648,7 @@ class HTTPSTest(TestCase): + ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443), + ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", + 443)): +- c = httplib.HTTPSConnection(hp) ++ c = httplib.HTTPSConnection(hp, context=context) + self.assertEqual(h, c.host) + self.assertEqual(p, c.port) + + diff --git a/SOURCES/00227-accept-none-keyfile-loadcertchain.patch b/SOURCES/00227-accept-none-keyfile-loadcertchain.patch new file mode 100644 index 0000000..28d241b --- /dev/null +++ b/SOURCES/00227-accept-none-keyfile-loadcertchain.patch @@ -0,0 +1,66 @@ +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -2681,8 +2681,8 @@ 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; ++ PyObject *keyfile = NULL, *keyfile_bytes = NULL, *password = NULL; ++ char *certfile_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 }; +@@ -2690,11 +2690,27 @@ load_cert_chain(PySSLContext *self, PyOb + errno = 0; + ERR_clear_error(); + if (!PyArg_ParseTupleAndKeywords(args, kwds, +- "et|etO:load_cert_chain", kwlist, ++ "et|OO:load_cert_chain", kwlist, + Py_FileSystemDefaultEncoding, &certfile_bytes, +- Py_FileSystemDefaultEncoding, &keyfile_bytes, +- &password)) ++ &keyfile, &password)) + return NULL; ++ ++ if (keyfile && keyfile != Py_None) { ++ if (PyString_Check(keyfile)) { ++ Py_INCREF(keyfile); ++ keyfile_bytes = keyfile; ++ } else { ++ PyObject *u = PyUnicode_FromObject(keyfile); ++ if (!u) ++ goto error; ++ keyfile_bytes = PyUnicode_AsEncodedString( ++ u, Py_FileSystemDefaultEncoding, NULL); ++ Py_DECREF(u); ++ if (!keyfile_bytes) ++ goto error; ++ } ++ } ++ + if (password && password != Py_None) { + if (PyCallable_Check(password)) { + pw_info.callable = password; +@@ -2725,7 +2741,7 @@ load_cert_chain(PySSLContext *self, PyOb + } + PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); + r = SSL_CTX_use_PrivateKey_file(self->ctx, +- keyfile_bytes ? keyfile_bytes : certfile_bytes, ++ keyfile_bytes ? PyBytes_AS_STRING(keyfile_bytes) : certfile_bytes, + SSL_FILETYPE_PEM); + PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); + if (r != 1) { +@@ -2756,8 +2772,8 @@ load_cert_chain(PySSLContext *self, PyOb + error: + SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); ++ Py_XDECREF(keyfile_bytes); + PyMem_Free(pw_info.password); +- PyMem_Free(keyfile_bytes); + PyMem_Free(certfile_bytes); + return NULL; + } + + diff --git a/SOURCES/00228-backport-ssl-version.patch b/SOURCES/00228-backport-ssl-version.patch new file mode 100644 index 0000000..40ac04c --- /dev/null +++ b/SOURCES/00228-backport-ssl-version.patch @@ -0,0 +1,260 @@ + +# HG changeset patch +# User Alex Gaynor +# Date 1409862802 25200 +# Node ID 16c86a6bdbe2a545dd2de02dc9f347c2b3ae7220 +# Parent f17ab9fed3b03191df975ecdde2cc07cee915319 +Issue #20421: Add a .version() method to SSL sockets exposing the actual protocol version in use. + +Backport from default. + +diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst +--- a/Doc/library/ssl.rst ++++ b/Doc/library/ssl.rst +@@ -867,10 +867,10 @@ SSL sockets also have the following addi + + .. 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``. ++ Returns the higher-level 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``. + + .. versionadded:: 2.7.9 + +@@ -882,6 +882,16 @@ SSL sockets also have the following addi + returned socket should always be used for further communication with the + other side of the connection, rather than the original socket. + ++.. method:: SSLSocket.version() ++ ++ Return the actual SSL protocol version negotiated by the connection ++ as a string, or ``None`` is no secure connection is established. ++ As of this writing, possible return values include ``"SSLv2"``, ++ ``"SSLv3"``, ``"TLSv1"``, ``"TLSv1.1"`` and ``"TLSv1.2"``. ++ Recent OpenSSL versions may define more return values. ++ ++ .. versionadded:: 3.5 ++ + .. attribute:: SSLSocket.context + + The :class:`SSLContext` object this SSL socket is tied to. If the SSL +diff --git a/Lib/ssl.py b/Lib/ssl.py +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -862,6 +862,15 @@ class SSLSocket(socket): + return None + return self._sslobj.tls_unique_cb() + ++ def version(self): ++ """ ++ Return a string identifying the protocol version used by the ++ current SSL channel, or None if there is no established channel. ++ """ ++ if self._sslobj is None: ++ return None ++ return self._sslobj.version() ++ + + def wrap_socket(sock, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -1904,7 +1904,8 @@ else: + 'compression': s.compression(), + 'cipher': s.cipher(), + 'peercert': s.getpeercert(), +- 'client_npn_protocol': s.selected_npn_protocol() ++ 'client_npn_protocol': s.selected_npn_protocol(), ++ 'version': s.version(), + }) + s.close() + stats['server_npn_protocols'] = server.selected_protocols +@@ -1912,6 +1913,13 @@ else: + + def try_protocol_combo(server_protocol, client_protocol, expect_success, + certsreqs=None, server_options=0, client_options=0): ++ """ ++ Try to SSL-connect using *client_protocol* to *server_protocol*. ++ If *expect_success* is true, assert that the connection succeeds, ++ if it's false, assert that the connection fails. ++ Also, if *expect_success* is a string, assert that it is the protocol ++ version actually used by the connection. ++ """ + if certsreqs is None: + certsreqs = ssl.CERT_NONE + certtype = { +@@ -1941,8 +1949,8 @@ else: + ctx.load_cert_chain(CERTFILE) + ctx.load_verify_locations(CERTFILE) + try: +- server_params_test(client_context, server_context, +- chatty=False, connectionchatty=False) ++ stats = 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: +@@ -1957,6 +1965,10 @@ else: + "Client protocol %s succeeded with server protocol %s!" + % (ssl.get_protocol_name(client_protocol), + ssl.get_protocol_name(server_protocol))) ++ elif (expect_success is not True ++ and expect_success != stats['version']): ++ raise AssertionError("version mismatch: expected %r, got %r" ++ % (expect_success, stats['version'])) + + + class ThreadedTests(unittest.TestCase): +@@ -2186,17 +2198,17 @@ else: + 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_SSLv3, 'SSLv3') + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1') + +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) + +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED) + 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) ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) + + # Server with specific SSL options + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False, +@@ -2213,9 +2225,9 @@ else: + """Connecting to an SSLv3 server with various client options""" + 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) ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3') ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', 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, +@@ -2223,7 +2235,7 @@ else: + 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, ++ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, 'SSLv3', + client_options=ssl.OP_NO_SSLv2) + + @skip_if_broken_ubuntu_ssl +@@ -2231,9 +2243,9 @@ else: + """Connecting to a TLSv1 server with various client options""" + 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) +- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1') ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) + 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) +@@ -2248,14 +2260,14 @@ else: + Testing against older TLS versions.""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, True) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') + 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_SSLv23, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1, False) + +@@ -2268,7 +2280,7 @@ else: + Testing against older TLS versions.""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, True, ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2', + 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'): +@@ -2277,7 +2289,7 @@ else: + 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_SSLv23, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2') + 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) +@@ -2619,6 +2631,21 @@ else: + s.connect((HOST, server.port)) + self.assertIn("no shared cipher", str(server.conn_errors[0])) + ++ def test_version_basic(self): ++ """ ++ Basic tests for SSLSocket.version(). ++ More tests are done in the test_protocol_*() methods. ++ """ ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ with ThreadedEchoServer(CERTFILE, ++ ssl_version=ssl.PROTOCOL_TLSv1, ++ chatty=False) as server: ++ with closing(context.wrap_socket(socket.socket())) as s: ++ self.assertIs(s.version(), None) ++ s.connect((HOST, server.port)) ++ self.assertEqual(s.version(), "TLSv1") ++ self.assertIs(s.version(), None) ++ + @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 +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -1384,6 +1384,18 @@ static PyObject *PySSL_cipher (PySSLSock + return NULL; + } + ++static PyObject *PySSL_version(PySSLSocket *self) ++{ ++ const char *version; ++ ++ if (self->ssl == NULL) ++ Py_RETURN_NONE; ++ version = SSL_get_version(self->ssl); ++ if (!strcmp(version, "unknown")) ++ Py_RETURN_NONE; ++ return PyUnicode_FromString(version); ++} ++ + #ifdef OPENSSL_NPN_NEGOTIATED + static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { + const unsigned char *out; +@@ -1907,6 +1919,7 @@ static PyMethodDef PySSLMethods[] = { + {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, + PySSL_peercert_doc}, + {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, ++ {"version", (PyCFunction)PySSL_version, METH_NOARGS}, + #ifdef OPENSSL_NPN_NEGOTIATED + {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, + #endif + diff --git a/SOURCES/00229-fix-hashlib-openssl-init.patch b/SOURCES/00229-fix-hashlib-openssl-init.patch new file mode 100644 index 0000000..c23ca72 --- /dev/null +++ b/SOURCES/00229-fix-hashlib-openssl-init.patch @@ -0,0 +1,12 @@ +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index a41c97e..2c8a18f 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -984,6 +984,7 @@ init_hashlib(void) + SSL_load_error_strings(); + SSL_library_init(); + ERR_load_crypto_strings(); ++ OpenSSL_add_all_digests(); + + Py_TYPE(&EVPtype) = &PyType_Type; + if (PyType_Ready(&EVPtype) < 0) diff --git a/SOURCES/00230-adjusted-tests-to-determine-if-SSLv2-is-enabled-or-not.patch b/SOURCES/00230-adjusted-tests-to-determine-if-SSLv2-is-enabled-or-not.patch new file mode 100644 index 0000000..9e941e6 --- /dev/null +++ b/SOURCES/00230-adjusted-tests-to-determine-if-SSLv2-is-enabled-or-not.patch @@ -0,0 +1,74 @@ +From 4f118fdad37e47301047a0729552ff8f5e80ffcf Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Tue, 12 Apr 2016 12:59:36 +0200 +Subject: [PATCH] Adjusted tests to determine if SSLv2 is enabled or not + +--- + Lib/test/test_ssl.py | 30 ++++++++++++++++++++++++------ + 1 file changed, 24 insertions(+), 6 deletions(-) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 498a489..9bf3260 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -104,6 +104,12 @@ def no_sslv2_implies_sslv3_hello(): + # 0.9.7h or higher + return ssl.OPENSSL_VERSION_INFO >= (0, 9, 7, 8, 15) + ++def default_context_has_no_sslv2(): ++ # Function for tests to determine if openssl package has disabled SSLv2 or not ++ # See rhbz#1319703 ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ return ctx.options & ssl.OP_NO_SSLv2 ++ + def have_verify_flags(): + # 0.9.8 or higher + return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15) +@@ -709,7 +715,10 @@ class ContextTests(unittest.TestCase): + @skip_if_broken_ubuntu_ssl + def test_options(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- self.assertEqual(ssl.OP_ALL, ctx.options) ++ if default_context_has_no_sslv2(): ++ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, ctx.options) ++ else: ++ self.assertEqual(ssl.OP_ALL, ctx.options) + ctx.options |= ssl.OP_NO_SSLv2 + self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, + ctx.options) +@@ -2170,7 +2179,10 @@ else: + 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) ++ if default_context_has_no_sslv2(): ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False) ++ else: ++ 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 +@@ -2178,10 +2190,16 @@ else: + # 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, True, +- client_options=ssl.OP_NO_SSLv3) +- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, +- client_options=ssl.OP_NO_TLSv1) ++ if default_context_has_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) ++ else: ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, ++ client_options=ssl.OP_NO_SSLv3) ++ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, ++ client_options=ssl.OP_NO_TLSv1) + + @skip_if_broken_ubuntu_ssl + def test_protocol_sslv23(self): +-- +2.5.5 + diff --git a/SOURCES/00231-cprofile-sort-option.patch b/SOURCES/00231-cprofile-sort-option.patch new file mode 100644 index 0000000..92e0150 --- /dev/null +++ b/SOURCES/00231-cprofile-sort-option.patch @@ -0,0 +1,36 @@ +From 0fba878e37390b581b95b31ff7d42041c9a3a370 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Tue, 12 Apr 2016 14:17:32 +0200 +Subject: [PATCH] add choices for sort option of cProfile for better output + message + +--- + Lib/cProfile.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/Lib/cProfile.py b/Lib/cProfile.py +index b2efd04..02acd4e 100755 +--- a/Lib/cProfile.py ++++ b/Lib/cProfile.py +@@ -161,7 +161,7 @@ def label(code): + # ____________________________________________________________ + + def main(): +- import os, sys ++ import os, pstats, sys + from optparse import OptionParser + usage = "cProfile.py [-o output_file_path] [-s sort] scriptfile [arg] ..." + parser = OptionParser(usage=usage) +@@ -170,7 +170,8 @@ def main(): + help="Save stats to ", default=None) + parser.add_option('-s', '--sort', dest="sort", + help="Sort order when printing to stdout, based on pstats.Stats class", +- default=-1) ++ default=-1, ++ choices=list(pstats.Stats.sort_arg_dict_default.keys())) + + if not sys.argv[1:]: + parser.print_usage() +-- +2.5.5 + diff --git a/SOURCES/00232-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch b/SOURCES/00232-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch new file mode 100644 index 0000000..9aaa635 --- /dev/null +++ b/SOURCES/00232-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch @@ -0,0 +1,101 @@ +From ee2958f8a13facbc2bddef1b4b84b0fe0b1bc4c9 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 28 Apr 2016 17:20:09 +0200 +Subject: [PATCH] use Py_ssize_t for file offset and length computations in + iteration + +--- + Lib/test/test_file2k.py | 16 +++++++++++++++- + Objects/fileobject.c | 15 +++++++-------- + 2 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py +index d1c1e35..b640aeb 100644 +--- a/Lib/test/test_file2k.py ++++ b/Lib/test/test_file2k.py +@@ -14,7 +14,7 @@ except ImportError: + threading = None + + from test import test_support +-from test.test_support import TESTFN, run_unittest ++from test.test_support import TESTFN, run_unittest, requires + from UserList import UserList + + class AutoFileTests(unittest.TestCase): +@@ -437,6 +437,20 @@ class OtherFileTests(unittest.TestCase): + finally: + f.close() + ++ @test_support.precisionbigmemtest(2**31, 2.5, dry_run=False) ++ def test_very_long_line(self, size): ++ # Issue #22526 ++ requires('largefile') ++ with open(TESTFN, "wb") as fp: ++ fp.seek(size - 1) ++ fp.write("\0") ++ with open(TESTFN, "rb") as fp: ++ for l in fp: ++ pass ++ self.assertEqual(len(l), size) ++ self.assertEqual(l.count("\0"), size) ++ l = None ++ + class FileSubclassTests(unittest.TestCase): + + def testExit(self): +diff --git a/Objects/fileobject.c b/Objects/fileobject.c +index 5594058..55e074b 100644 +--- a/Objects/fileobject.c ++++ b/Objects/fileobject.c +@@ -2236,7 +2236,7 @@ drop_readahead(PyFileObject *f) + (unless at EOF) and no more than bufsize. Returns negative value on + error, will set MemoryError if bufsize bytes cannot be allocated. */ + static int +-readahead(PyFileObject *f, int bufsize) ++readahead(PyFileObject *f, Py_ssize_t bufsize) + { + Py_ssize_t chunksize; + +@@ -2274,7 +2274,7 @@ readahead(PyFileObject *f, int bufsize) + logarithmic buffer growth to about 50 even when reading a 1gb line. */ + + static PyStringObject * +-readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) ++readahead_get_line_skip(PyFileObject *f, Py_ssize_t skip, Py_ssize_t bufsize) + { + PyStringObject* s; + char *bufptr; +@@ -2294,10 +2294,10 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) + bufptr++; /* Count the '\n' */ + len = bufptr - f->f_bufptr; + s = (PyStringObject *) +- PyString_FromStringAndSize(NULL, skip+len); ++ PyString_FromStringAndSize(NULL, skip + len); + if (s == NULL) + return NULL; +- memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len); ++ memcpy(PyString_AS_STRING(s) + skip, f->f_bufptr, len); + f->f_bufptr = bufptr; + if (bufptr == f->f_bufend) + drop_readahead(f); +@@ -2305,14 +2305,13 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) + bufptr = f->f_bufptr; + buf = f->f_buf; + f->f_buf = NULL; /* Force new readahead buffer */ +- assert(skip+len < INT_MAX); +- s = readahead_get_line_skip( +- f, (int)(skip+len), bufsize + (bufsize>>2) ); ++ assert(len <= PY_SSIZE_T_MAX - skip); ++ s = readahead_get_line_skip(f, skip + len, bufsize + (bufsize>>2)); + if (s == NULL) { + PyMem_Free(buf); + return NULL; + } +- memcpy(PyString_AS_STRING(s)+skip, bufptr, len); ++ memcpy(PyString_AS_STRING(s) + skip, bufptr, len); + PyMem_Free(buf); + } + return s; +-- +2.5.5 + diff --git a/SOURCES/cert-verification.cfg b/SOURCES/cert-verification.cfg new file mode 100755 index 0000000..469f746 --- /dev/null +++ b/SOURCES/cert-verification.cfg @@ -0,0 +1,8 @@ +# Possible values are: +# 'enable' to ensure HTTPS certificate verification is enabled by default +# 'disable' to ensure HTTPS certificate verification is disabled by default +# 'platform_default' to delegate the decision to the redistributor providing this particular Python version + +# For more info refer to https://www.python.org/dev/peps/pep-0493/ +[https] +verify=platform_default \ No newline at end of file diff --git a/SOURCES/pythondeps-scl.sh b/SOURCES/pythondeps-scl.sh deleted file mode 100755 index 7edaa68..0000000 --- a/SOURCES/pythondeps-scl.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# Altered from pythondeps.sh -# The second parameter is %{scl_prefix}, which is used to prefix python(abi). - -[ $# -ge 1 ] || { - cat > /dev/null - exit 0 -} - -case $1 in --P|--provides) - shift - # Match buildroot/payload paths of the form - # /PATH/OF/BUILDROOT/%{_scl_root}/usr/bin/pythonMAJOR.MINOR - # generating a line of the form - # %{scl_prefix}python(abi) = MAJOR.MINOR - # (Don't match against -config tools e.g. /usr/bin/python2.6-config) - if [ "x$1" = "x" ]; then - grep "/usr/bin/python.\..$" \ - | sed -e "s|.*/usr/bin/python\(.\..\)|python(abi) = \1|" - else - grep "/opt/.*/usr/bin/python.\..$" \ - | sed -e "s|.*/usr/bin/python\(.\..\)|$1python(abi) = \1|" - fi - ;; --R|--requires) - shift - # Match buildroot paths of the form - # /PATH/OF/BUILDROOT/%{scl_root}/usr/lib/pythonMAJOR.MINOR/ and - # /PATH/OF/BUILDROOT/%{scl_root}/usr/lib64/pythonMAJOR.MINOR/ - # generating (uniqely) lines of the form: - # %{scl_prefix}python(abi) = MAJOR.MINOR - if [ "x$1" = "x" ]; then - grep "/usr/lib[^/]*/python.\../.*" \ - | sed -e "s|.*/usr/lib[^/]*/python\(.\..\)/.*|python(abi) = \1|g" \ - | sort | uniq - else - grep "/opt/.*/usr/lib[^/]*/python.\../.*" \ - | sed -e "s|.*/usr/lib[^/]*/python\(.\..\)/.*|$1python(abi) = \1|g" \ - | sort | uniq - fi - ;; -esac - -exit 0 diff --git a/SPECS/python.spec b/SPECS/python.spec index 6cd9e8a..42a1a68 100644 --- a/SPECS/python.spec +++ b/SPECS/python.spec @@ -120,7 +120,7 @@ Summary: An interpreted, interactive, object-oriented programming language Name: %{?scl_prefix}%{python} # Remember to also rebase python-docs when changing this: Version: 2.7.8 -Release: 3%{?dist} +Release: 14%{?dist} License: Python Group: Development/Languages %{?scl:Requires: %{scl}-runtime} @@ -184,7 +184,7 @@ BuildRequires: zlib-devel Source: http://www.python.org/ftp/python/%{version}/Python-%{version}.tar.xz # SCL-custom version of pythondeps.sh -Source2: pythondeps-scl.sh +# Moved to metapackage python27 # Work around bug 562906 until it's fixed in rpm-build by providing a fixed # version of pythondeps.sh: @@ -212,6 +212,10 @@ Source6: macros.python2 Source7: brp-python-bytecompile-with-scl-python +# Configuration file to change ssl verification settings globally +# Downstream only see Patch224 +Source8: cert-verification.cfg + # Modules/Setup.dist is ultimately used by the "makesetup" script to construct # the Makefile and config.c # @@ -904,6 +908,104 @@ Patch196: CVE-2013-1752.patch # rhbz#1046170 Patch197: xmlrpc_gzip_27_parameter.patch +# ================== PEP466=========================== +# Massive backport of PEP466 and relevant other fixes +# ================rhbz#1111461======================== +# 00213 # +# Fix %S, %R and %V formats of PyUnicode_FromFormat(). +# http://bugs.python.org/issue122023 +Patch213: 00213-pep466-pyunicode_fromformat-fix-formats.patch + +# 00214 # +# Backport SSL module from Python3 +# http://bugs.python.org/issue21308 +Patch214: 00214-pep466-backport-py3-ssl-changes.patch + +# 00215 # +# OpenSSL disabled various ciphers and protocols +# we have to reflect it in tests +Patch215: 00215-pep466-reflect-openssl-settings-ssltests.patch + +# 00216 # +# fix load_verify_locations on unicode paths +# http://bugs.python.org/issue22244 +Patch216: 00216-pep466-fix-load-verify-locs-unicode.patch + +# 00217 # +# backport hashlib changes +# http://bugs.python.org/issue21307 +Patch217: 00217-pep466-backport-hashlib-algorithm-consts.patch + +# 00218 # +# update os.urandom +# http://bugs.python.org/issue21305 +Patch218: 00218-pep466-backport-urandom-pers-fd.patch + +# 00219 # +# Lib/ssl.py still references _ssl.sslwrap +# http://bugs.python.org/issue22523 +Patch219: 00219-pep466-fix-referenced-sslwrap.patch + +# 00220 # +# allow passing cert/ssl information to urllib2.urlopen and httplib.HTTPSConnection +Patch220: 00220-pep466-allow-passing-ssl-urrlib-httplib.patch + +# 00221 # +# Patch214 remove sslwrap from _ssl.c this so we have to reimplement it +Patch221: 00221-pep466-backport-sslwrap-c-ssl.patch + +# 00222 # +# test_ssl: fails on recent libressl version with BAD_DH_P_LENGTH +# https://bugs.python.org/issue23844 +Patch222: 00222-add-2014-bit-dh-key.patch + +# 00223 # +# PEP 476: verify HTTPS certificates by default +# http://bugs.python.org/issue22417 +# Resolves:rhbz#1219110 +Patch223: 00223-pep476-verify-certs-by-default.patch + +# 00224 # +# Add switch to toggle global verification on and off +# Resolves:rhbz#1219108 +# For more information see PEP493 +Patch224: 00224-pep476-add-toggle-for-cert-verify.patch + +# 00227 # +# Make load_cert_chain function of SSLContext accept +# keyfile which is set to None +# Resolves: rhbz#1250611 +Patch227: 00227-accept-none-keyfile-loadcertchain.patch + +# 00228 # +# Backport SSLSocket.version function +# Resolves: rhbz#1259421 +Patch228: 00228-backport-ssl-version.patch + +# ================== !PEP466 =========================== + +# 00229 # +# Initialize OpenSSL_add_all_digests in _hashlib +# Resolves: rhbz#1318319 +Patch229: 00229-fix-hashlib-openssl-init.patch + +# 00230 # +# Adjusted tests to determine existence or lack of SSLv2 support +# Resolves: rhbz#1319703 +Patch230: 00230-adjusted-tests-to-determine-if-SSLv2-is-enabled-or-not.patch + +# 00231 # +# Add choices for sort option of cProfile for better output message +# http://bugs.python.org/issue23420 +# Resolves: rhbz#1319655 +Patch231: 00231-cprofile-sort-option.patch + +# 00231 # +# Fix for iteration over files vith very long lines +# http://bugs.python.org/issue22526 +# Resolves: rhbz#1329141 +Patch232: 00232-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch + # (New patches go here ^^^) # @@ -960,10 +1062,16 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) URL: http://www.python.org/ +%if ( 0%{?rhel} && 0%{?rhel} < 7 ) # filter pkgconfig Provides %{?scl:%filter_from_provides s|pkgconfig(|%{?scl_prefix}pkgconfig(|g} %{?scl:%filter_from_requires s|python(abi|%{?scl_prefix}python(abi|g} %{?scl:%filter_setup} +%else +# filter pkgconfig Requires/Provides on rhel7 as filter_from doesnt work there +%global __provides_exclude ^pkgconfig\\(.*$ +%endif + %description Python is an interpreted, interactive, object-oriented programming @@ -1013,6 +1121,13 @@ Obsoletes: %{?scl_prefix}python2-devel Provides: %{?scl_prefix}python2-devel = %{version}-%{release} %endif +# we filtered provides of pkgconfig on rhel7 so we need to manully re add them +%if ( 0%{?rhel} && 0%{?rhel} >= 7 ) +Provides: %{?scl_prefix}pkgconfig(python) = %{version}-%{release} +Provides: %{?scl_prefix}pkgconfig(python-2.7) = %{version}-%{release} +Provides: %{?scl_prefix}pkgconfig(python2) = %{version}-%{release} +%endif + %description devel The Python programming language's interpreter can be extended with dynamically loaded extensions and can be embedded in other programs. @@ -1085,6 +1200,13 @@ Requires: %{?scl_prefix}%{pkg_name}-test%{?_isa} = %{version}-%{release} Requires: %{?scl_prefix}tkinter%{?_isa} = %{version}-%{release} Requires: %{?scl_prefix}%{pkg_name}-tools%{?_isa} = %{version}-%{release} +# we filtered provides of pkgconfig on rhel7 so we need to manully re add them +%if ( 0%{?rhel} && 0%{?rhel} >= 7 ) +Provides: %{?scl_prefix}pkgconfig(python-debug) = %{version}-%{release} +Provides: %{?scl_prefix}pkgconfig(python-2.7-debug) = %{version}-%{release} +Provides: %{?scl_prefix}pkgconfig(python2-debug) = %{version}-%{release} +%endif + %description debug python-debug provides a version of the Python runtime with numerous debugging features enabled, aimed at advanced Python users, such as developers of Python @@ -1261,6 +1383,24 @@ mv Modules/cryptmodule.c Modules/_cryptmodule.c %patch196 -p1 %patch197 -p1 +%patch213 -p1 +%patch214 -p1 +%patch215 -p1 +%patch216 -p1 +%patch217 -p1 +%patch218 -p1 +%patch219 -p1 +%patch220 -p1 +%patch221 -p1 +%patch222 -p1 +%patch223 -p1 +%patch224 -p1 +%patch227 -p1 +%patch228 -p1 +%patch229 -p1 +%patch230 -p1 +%patch231 -p1 +%patch232 -p1 # This shouldn't be necesarry, but is right now (2.2a3) find -name "*~" |xargs rm -f @@ -1419,7 +1559,6 @@ done # install SCL custom RPM scripts %{?scl:mkdir -p %{buildroot}%{_root_prefix}/lib/rpm/redhat} -%{?scl:cp -a %{SOURCE2} %{buildroot}%{_root_prefix}/lib/rpm} %{?scl:cp -a %{SOURCE7} %{buildroot}%{_root_prefix}/lib/rpm/redhat} InstallPython() { @@ -1640,6 +1779,10 @@ install -m 644 %{SOURCE6} %{buildroot}/%{?scl:%_root_sysconfdir}%{!?scl:%_syscon %{?scl:sed -i 's|^\(%@scl@__python2\)|\1 %{_bindir}/python2|' %{buildroot}%{_root_sysconfdir}/rpm/macros.python2.%{scl}} %{?scl:sed -i 's|@scl@|%{scl}|g' %{buildroot}%{_root_sysconfdir}/rpm/macros.python2.%{scl}} +# Make python folder for config files under /etc +mkdir -p %{buildroot}/%{_sysconfdir}/python +install -m 644 %{SOURCE8} %{buildroot}/%{_sysconfdir}/python + # Ensure that the curses module was linked against libncursesw.so, rather than # libncurses.so (bug 539917) ldd %{buildroot}/%{dynload_dir}/_curses*.so \ @@ -1788,6 +1931,8 @@ rm -fr %{buildroot} %doc LICENSE README %dir %{pylibdir} %dir %{dynload_dir} +%dir %{_sysconfdir}/python +%config(noreplace) %{_sysconfdir}/python/cert-verification.cfg %{dynload_dir}/Python-%{version}-py%{pybasever}.egg-info %{dynload_dir}/_bisectmodule.so %{dynload_dir}/_bsddb.so @@ -1921,7 +2066,6 @@ rm -fr %{buildroot} %files devel %defattr(-,root,root,-) -%{?scl:%{_root_prefix}/lib/rpm/pythondeps-scl.sh} %{?scl:%{_root_prefix}/lib/rpm/redhat/brp-python-bytecompile-with-scl-python} # we have to own pkgconfig dir, as it's not owned by any other scl package %dir %{_libdir}/pkgconfig @@ -2122,6 +2266,51 @@ rm -fr %{buildroot} # ====================================================== %changelog +* Thu Apr 28 2016 Charalampos Stratakis - 2.7.8-14 +- Fix iteration over files with very long lines +Resolves: rhbz#1329141 + +* Tue Apr 19 2016 Charalampos Stratakis - 2.7.8-13 +- Modified 00214-pep466-backport-py3-ssl-changes.patch to apply correctly +Resolves: rhbz#1111464 + +* Tue Apr 19 2016 Charalampos Stratakis - 2.7.8-12 +- Modified 00224-pep476-add-toggle-for-cert-verify.patch to use certificate verification +config file from python27 SCL directory. +Resolves: rhbz#1111464 + +* Tue Apr 12 2016 Charalampos Stratakis - 2.7.8-11 +- Add choices for sort option of cProfile for better output +Resolves: rhbz#1319655 + +* Tue Apr 12 2016 Charalampos Stratakis - 2.7.8-10 +- Modified patch so tests can acknowledge the existense or lack +of SSLv2 support +Resolves: rhbz#1319703 + +* Wed Apr 06 2016 Charalampos Stratakis - 2.7.8-9 +- Adjusted tests to acknowledge lack of SSLv2 support +Resolves: rhbz#1319703 + +* Wed Apr 06 2016 Charalampos Stratakis - 2.7.8-8 +- Change HTTPS certificate verification to platform_default +Resolves: rhbz#1319774 + +* Wed Mar 09 2016 Michal Cyprian - 2.7.8-7 +- Initialize OpenSSL_add_all_digests in _hashlib +Resolves: rhbz#1318319 + +* Wed Feb 24 2016 Michal Cyprian - 2.7.8-6 +- Add missing cert-verification.cfg file +Resolves: rhbz#1311044 + +* Wed Feb 17 2016 Michal Cyprian - 2.7.8-5 +- Fix filtering pkgconfig Requires/Provides on rhel7 + +* Tue Feb 16 2016 Michal Cyprian - 2.7.8-4 +- Massive backport of ssl module from python3 aka PEP466 +Resolves: rhbz#1111464 + * Tue May 19 2015 Matej Stuchlik - 2.7.8-3 - Add httplib fix for CVE-2013-1752 Resolves: rhbz#1187779