[python] Backport ssl module from python3

Robert Kuska rkuska at fedoraproject.org
Tue Aug 19 08:59:57 UTC 2014


commit 833dc39f61926c2fb84d9880dd43c81aab1479ec
Author: Robert Kuska <rkuska at redhat.com>
Date:   Tue Aug 19 10:59:43 2014 +0200

    Backport ssl module from python3

 00196-ssl-backport.patch       |12637 ++++++++++++++++++++++++++++++++++++++++
 00197-unicode_fromformat.patch |  208 +
 python.spec                    |   22 +-
 3 files changed, 12864 insertions(+), 3 deletions(-)
---
diff --git a/00196-ssl-backport.patch b/00196-ssl-backport.patch
new file mode 100644
index 0000000..a14d626
--- /dev/null
+++ b/00196-ssl-backport.patch
@@ -0,0 +1,12637 @@
+diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
+index c115976..84dd332 100644
+--- a/Doc/library/ssl.rst
++++ b/Doc/library/ssl.rst
+@@ -28,19 +28,14 @@ probably additional platforms, as long as OpenSSL is installed on that platform.
+ 
+    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 at the bottom.
+ This module provides a class, :class:`ssl.SSLSocket`, which is derived from the
+ :class:`socket.socket` type, and provides a socket-like wrapper that also
+ encrypts and decrypts the data going over the socket with SSL.  It supports
+-additional :meth:`read` and :meth:`write` methods, along with a method,
+-:meth:`getpeercert`, to retrieve the certificate of the other side of the
+-connection, and a method, :meth:`cipher`, to retrieve the cipher being used for
+-the secure connection.
++additional methods such as :meth:`getpeercert`, which retrieves the
++certificate of the other side of the connection, and :meth:`cipher`,which
++retrieves the cipher being used for the secure connection.
++
++For more sophisticated applications, the :class:`ssl.SSLContext` class
++helps manage settings and certificates, which can then be inherited
++by SSL sockets created through the :meth:`SSLContext.wrap_socket` method.
++
+ 
+ Functions, Constants, and Exceptions
+ ------------------------------------
+ 
+ .. exception:: SSLError
+ 
+-   Raised to signal an error from the underlying SSL implementation.  This
+-   signifies some problem in the higher-level encryption and authentication
+-   layer that's superimposed on the underlying network connection.  This error
+-   is a subtype of :exc:`socket.error`, which in turn is a subtype of
+-   :exc:`IOError`.
++   Raised to signal an error from the underlying SSL implementation (currently
++   provided by the OpenSSL library).  This signifies some problem in the
++   higher-level encryption and authentication layer that's superimposed on the
++   underlying network connection.  This error is a subtype of
++   :exc:`socket.error`, which in turn is a subtype of :exc:`IOError`.  The
++   error code and message of :exc:`SSLError` instances are provided by the
++   OpenSSL library.
++
++   .. attribute:: library
++
++      A string mnemonic designating the OpenSSL submodule in which the error
++      occurred, such as ``SSL``, ``PEM`` or ``X509``.  The range of possible
++      values depends on the OpenSSL version.
++
++      .. versionadded:: 2.7.9
++
++   .. attribute:: reason
++
++      A string mnemonic designating the reason this error occurred, for
++      example ``CERTIFICATE_VERIFY_FAILED``.  The range of possible
++      values depends on the OpenSSL version.
++
++      .. versionadded:: 2.7.9
++
++.. exception:: SSLZeroReturnError
++
++   A subclass of :exc:`SSLError` raised when trying to read or write and
++   the SSL connection has been closed cleanly.  Note that this doesn't
++   mean that the underlying transport (read TCP) has been closed.
++
++   .. versionadded:: 2.7.9
++
++.. exception:: SSLWantReadError
++
++   A subclass of :exc:`SSLError` raised by a :ref:`non-blocking SSL socket
++   <ssl-nonblocking>` when trying to read or write data, but more data needs
++   to be received on the underlying TCP transport before the request can be
++   fulfilled.
++
++   .. versionadded:: 2.7.9
++
++.. exception:: SSLWantWriteError
++
++   A subclass of :exc:`SSLError` raised by a :ref:`non-blocking SSL socket
++   <ssl-nonblocking>` when trying to read or write data, but more data needs
++   to be sent on the underlying TCP transport before the request can be
++   fulfilled.
+ 
+-.. 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)
++   .. 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
++^^^^^^^^^^^^^^^^^^^^
++
++.. function:: match_hostname(cert, hostname)
++
++   Verify that *cert* (in decoded format as returned by
++   :meth:`SSLSocket.getpeercert`) matches the given *hostname*.  The rules
++   applied are those for checking the identity of HTTPS servers as outlined
++   in :rfc:`2818` and :rfc:`6125`, except that IP addresses are not currently
++   supported. In addition to HTTPS, this function should be suitable for
++   checking the identity of servers in various SSL-based protocols such as
++   FTPS, IMAPS, POPS and others.
++
++   :exc:`CertificateError` is raised on failure. On success, the function
++   returns nothing::
+ 
+-   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.
++      >>> cert = {'subject': ((('commonName', 'example.com'),),)}
++      >>> ssl.match_hostname(cert, "example.com")
++      >>> ssl.match_hostname(cert, "example.org")
++      Traceback (most recent call last):
++        File "<stdin>", line 1, in <module>
++        File "/home/py3k/Lib/ssl.py", line 130, in match_hostname
++      ssl.CertificateError: hostname 'example.org' doesn't match 'example.com'
+ 
+-   Here's an example::
++   .. versionadded:: 2.7.9
+ 
+-     >>> 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'
+-     >>>
+ 
+-.. function:: get_server_certificate (addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None)
++.. 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
++   <http://tools.ietf.org/html/draft-agl-tls-nextprotoneg>`_. When true,
++   you can use the :meth:`SSLContext.set_npn_protocols` method to advertise
++   which protocols you want to support.
++
++   .. versionadded:: 2.7.9
++
++.. data:: CHANNEL_BINDING_TYPES
++
++   List of supported TLS channel binding types.  Strings in this list
++   can be used as arguments to :meth:`SSLSocket.get_channel_binding`.
++
++   .. versionadded:: 2.7.9
+ 
+ .. data:: OPENSSL_VERSION
+ 
+@@ -309,9 +701,40 @@ Functions, Constants, and Exceptions
+ 
+    .. versionadded:: 2.7
+ 
++.. data:: ALERT_DESCRIPTION_HANDSHAKE_FAILURE
++          ALERT_DESCRIPTION_INTERNAL_ERROR
++          ALERT_DESCRIPTION_*
++
++   Alert Descriptions from :rfc:`5246` and others. The `IANA TLS Alert Registry
++   <http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6>`_
++   contains this list and references to the RFCs where their meaning is defined.
++
++   Used as the return value of the callback function in
++   :meth:`SSLContext.set_servername_callback`.
++
++   .. versionadded:: 2.7.9
++
++.. data:: Purpose.SERVER_AUTH
++
++   Option for :func:`create_default_context` and
++   :meth:`SSLContext.load_default_certs`.  This value indicates that the
++   context may be used to authenticate Web servers (therefore, it will
++   be used to create client-side sockets).
++
++   .. versionadded:: 2.7.9
+ 
+-SSLSocket Objects
+------------------
++.. data:: Purpose.CLIENT_AUTH
++
++   Option for :func:`create_default_context` and
++   :meth:`SSLContext.load_default_certs`.  This value indicates that the
++   context may be used to authenticate Web clients (therefore, it will
++   be used to create server-side sockets).
++
++   .. versionadded:: 2.7.9
++
++
++SSL Sockets
++-----------
+ 
+ SSL sockets provide the following methods of :ref:`socket-objects`:
+ 
+@@ -334,37 +757,64 @@ SSL sockets provide the following methods of :ref:`socket-objects`:
+ 
+ However, since the SSL (and TLS) protocol has its own framing atop
+ of TCP, the SSL sockets abstraction can, in certain respects, diverge from
+-the specification of normal, OS-level sockets.
++the specification of normal, OS-level sockets.  See especially the
++:ref:`notes on non-blocking sockets <ssl-nonblocking>`.
+ 
+ SSL sockets also have the following additional methods and attributes:
+ 
++.. method:: SSLSocket.do_handshake()
++
++   Perform the SSL setup handshake.
++
++   .. versionchanged:: 2.7.9
++
++      The handshake method also performs :func:`match_hostname` when the
++      :attr:`~SSLContext.check_hostname` attribute of the socket's
++      :attr:`~SSLSocket.context` is true.
++
+ .. method:: SSLSocket.getpeercert(binary_form=False)
+ 
+    If there is no certificate for the peer on the other end of the connection,
+-   returns ``None``.
++   return ``None``.  If the SSL handshake hasn't been done yet, raise
++   :exc:`ValueError`.
+ 
+    If the ``binary_form`` parameter is :const:`False`, and a certificate was
+    received from the peer, this method returns a :class:`dict` instance.  If the
+    certificate was not validated, the dict is empty.  If the certificate was
+-   validated, it returns a dict with the keys ``subject`` (the principal for
+-   which the certificate was issued), and ``notAfter`` (the time after which the
+-   certificate should not be trusted).  The certificate was already validated,
+-   so the ``notBefore`` and ``issuer`` fields are not returned.  If a
+-   certificate contains an instance of the *Subject Alternative Name* extension
+-   (see :rfc:`3280`), there will also be a ``subjectAltName`` key in the
+-   dictionary.
+-
+-   The "subject" field is a tuple containing the sequence of relative
+-   distinguished names (RDNs) given in the certificate's data structure for the
+-   principal, and each RDN is a sequence of name-value pairs::
+-
+-      {'notAfter': 'Feb 16 16:54:50 2013 GMT',
+-       'subject': ((('countryName', u'US'),),
+-                   (('stateOrProvinceName', u'Delaware'),),
+-                   (('localityName', u'Wilmington'),),
+-                   (('organizationName', u'Python Software Foundation'),),
+-                   (('organizationalUnitName', u'SSL'),),
+-                   (('commonName', u'somemachine.python.org'),))}
++   validated, it returns a dict with several keys, amongst them ``subject``
++   (the principal for which the certificate was issued) and ``issuer``
++   (the principal issuing the certificate).  If a certificate contains an
++   instance of the *Subject Alternative Name* extension (see :rfc:`3280`),
++   there will also be a ``subjectAltName`` key in the dictionary.
++
++   The ``subject`` and ``issuer`` fields are tuples containing the sequence
++   of relative distinguished names (RDNs) given in the certificate's data
++   structure for the respective fields, and each RDN is a sequence of
++   name-value pairs.  Here is a real-world example::
++
++      {'issuer': ((('countryName', 'IL'),),
++                  (('organizationName', 'StartCom Ltd.'),),
++                  (('organizationalUnitName',
++                    'Secure Digital Certificate Signing'),),
++                  (('commonName',
++                    'StartCom Class 2 Primary Intermediate Server CA'),)),
++       'notAfter': 'Nov 22 08:15:19 2013 GMT',
++       'notBefore': 'Nov 21 03:09:52 2011 GMT',
++       'serialNumber': '95F0',
++       'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),),
++                   (('countryName', 'US'),),
++                   (('stateOrProvinceName', 'California'),),
++                   (('localityName', 'San Francisco'),),
++                   (('organizationName', 'Electronic Frontier Foundation, Inc.'),),
++                   (('commonName', '*.eff.org'),),
++                   (('emailAddress', 'hostmaster at 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 additional methods and attributes:
+      :const:`None` if you used :const:`CERT_NONE` (rather than
+      :const:`CERT_OPTIONAL` or :const:`CERT_REQUIRED`).
+ 
++   .. versionchanged:: 2.7.9
++      The returned dictionary includes additional items such as ``issuer`` and
++      ``notBefore``. Additionall :exc:`ValueError` is raised when the handshake
++      isn't done. The returned dictionary includes additional X509v3 extension
++      items such as ``crlDistributionPoints``, ``caIssuers`` and ``OCSP`` URIs.
++
+ .. method:: SSLSocket.cipher()
+ 
+    Returns a three-value tuple containing the name of the cipher being used, the
+    version of the SSL protocol that defines its use, and the number of secret
+    bits being used.  If no connection has been established, returns ``None``.
+ 
+-.. method:: SSLSocket.do_handshake()
++.. method:: SSLSocket.compression()
++
++   Return the compression algorithm being used as a string, or ``None``
++   if the connection isn't compressed.
++
++   If the higher-level protocol supports its own compression mechanism,
++   you can use :data:`OP_NO_COMPRESSION` to disable SSL-level compression.
++
++   .. versionadded:: 2.7.9
++
++.. method:: SSLSocket.get_channel_binding(cb_type="tls-unique")
+ 
+-   Perform a TLS/SSL handshake.  If this is used with a non-blocking socket, it
+-   may raise :exc:`SSLError` with an ``arg[0]`` of :const:`SSL_ERROR_WANT_READ`
+-   or :const:`SSL_ERROR_WANT_WRITE`, in which case it must be called again until
+-   it completes successfully.  For example, to simulate the behavior of a
+-   blocking socket, one might write::
+-
+-        while True:
+-            try:
+-                s.do_handshake()
+-                break
+-            except ssl.SSLError as err:
+-                if err.args[0] == ssl.SSL_ERROR_WANT_READ:
+-                    select.select([s], [], [])
+-                elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
+-                    select.select([], [s], [])
+-                else:
+-                    raise
++   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
++   <http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html>`_.
++
++   The *cadata* object, if present, is either an ASCII string of one or more
++   PEM-encoded certificates or a bytes-like object of DER-encoded
++   certificates. Like with *capath* extra lines around PEM-encoded
++   certificates are ignored but at least one certificate must be present.
++
++.. method:: SSLContext.get_ca_certs(binary_form=False)
++
++   Get a list of loaded "certification authority" (CA) certificates. If the
++   ``binary_form`` parameter is :const:`False` each list
++   entry is a dict like the output of :meth:`SSLSocket.getpeercert`. Otherwise
++   the method returns a list of DER-encoded certificates. The returned list
++   does not contain certificates from *capath* unless a certificate was
++   requested and loaded by a SSL connection.
++
++.. method:: SSLContext.set_default_verify_paths()
++
++   Load a set of default "certification authority" (CA) certificates from
++   a filesystem path defined when building the OpenSSL library.  Unfortunately,
++   there's no easy way to know whether this method succeeds: no error is
++   returned if no certificates are to be found.  When the OpenSSL library is
++   provided as part of the operating system, though, it is likely to be
++   configured properly.
++
++.. method:: SSLContext.set_ciphers(ciphers)
++
++   Set the available ciphers for sockets created with this context.
++   It should be a string in the `OpenSSL cipher list format
++   <http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_.
++   If no cipher can be selected (because compile-time options or other
++   configuration forbids use of all the specified ciphers), an
++   :class:`SSLError` will be raised.
++
++   .. note::
++      when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will
++      give the currently selected cipher.
++
++.. method:: SSLContext.set_npn_protocols(protocols)
++
++   Specify which protocols the socket should advertise during the SSL/TLS
++   handshake. It should be a list of strings, like ``['http/1.1', 'spdy/2']``,
++   ordered by preference. The selection of a protocol will happen during the
++   handshake, and will play out according to the `NPN draft specification
++   <http://tools.ietf.org/html/draft-agl-tls-nextprotoneg>`_. After a
++   successful handshake, the :meth:`SSLSocket.selected_npn_protocol` method will
++   return the agreed-upon protocol.
++
++   This method will raise :exc:`NotImplementedError` if :data:`HAS_NPN` is
++   False.
++
++.. method:: SSLContext.set_servername_callback(server_name_callback)
++
++   Register a callback function that will be called after the TLS Client Hello
++   handshake message has been received by the SSL/TLS server when the TLS client
++   specifies a server name indication. The server name indication mechanism
++   is specified in :rfc:`6066` section 3 - Server Name Indication.
++
++   Only one callback can be set per ``SSLContext``.  If *server_name_callback*
++   is ``None`` then the callback is disabled. Calling this function a
++   subsequent time will disable the previously registered callback.
++
++   The callback function, *server_name_callback*, will be called with three
++   arguments; the first being the :class:`ssl.SSLSocket`, the second is a string
++   that represents the server name that the client is intending to communicate
++   (or :const:`None` if the TLS Client Hello does not contain a server name)
++   and the third argument is the original :class:`SSLContext`. The server name
++   argument is the IDNA decoded server name.
++
++   A typical use of this callback is to change the :class:`ssl.SSLSocket`'s
++   :attr:`SSLSocket.context` attribute to a new object of type
++   :class:`SSLContext` representing a certificate chain that matches the server
++   name.
++
++   Due to the early negotiation phase of the TLS connection, only limited
++   methods and attributes are usable like
++   :meth:`SSLSocket.selected_npn_protocol` and :attr:`SSLSocket.context`.
++   :meth:`SSLSocket.getpeercert`, :meth:`SSLSocket.getpeercert`,
++   :meth:`SSLSocket.cipher` and :meth:`SSLSocket.compress` methods require that
++   the TLS connection has progressed beyond the TLS Client Hello and therefore
++   will not contain return meaningful values nor can they be called safely.
++
++   The *server_name_callback* function must return ``None`` to allow the
++   TLS negotiation to continue.  If a TLS failure is required, a constant
++   :const:`ALERT_DESCRIPTION_* <ALERT_DESCRIPTION_INTERNAL_ERROR>` can be
++   returned.  Other return values will result in a TLS fatal error with
++   :const:`ALERT_DESCRIPTION_INTERNAL_ERROR`.
++
++   If there is an IDNA decoding error on the server name, the TLS connection
++   will terminate with an :const:`ALERT_DESCRIPTION_INTERNAL_ERROR` fatal TLS
++   alert message to the client.
++
++   If an exception is raised from the *server_name_callback* function the TLS
++   connection will terminate with a fatal TLS alert message
++   :const:`ALERT_DESCRIPTION_HANDSHAKE_FAILURE`.
++
++   This method will raise :exc:`NotImplementedError` if the OpenSSL library
++   had OPENSSL_NO_TLSEXT defined when it was built.
++
++.. method:: SSLContext.load_dh_params(dhfile)
++
++   Load the key generation parameters for Diffie-Helman (DH) key exchange.
++   Using DH key exchange improves forward secrecy at the expense of
++   computational resources (both on the server and on the client).
++   The *dhfile* parameter should be the path to a file containing DH
++   parameters in PEM format.
++
++   This setting doesn't apply to client sockets.  You can also use the
++   :data:`OP_SINGLE_DH_USE` option to further improve security.
++
++.. method:: SSLContext.set_ecdh_curve(curve_name)
++
++   Set the curve name for Elliptic Curve-based Diffie-Hellman (ECDH) key
++   exchange.  ECDH is significantly faster than regular DH while arguably
++   as secure.  The *curve_name* parameter should be a string describing
++   a well-known elliptic curve, for example ``prime256v1`` for a widely
++   supported curve.
++
++   This setting doesn't apply to client sockets.  You can also use the
++   :data:`OP_SINGLE_ECDH_USE` option to further improve security.
++
++   This method is not available if :data:`HAS_ECDH` is False.
++
++   .. seealso::
++      `SSL/TLS & Perfect Forward Secrecy <http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html>`_
++         Vincent Bernat.
++
++.. method:: SSLContext.wrap_socket(sock, server_side=False, \
++      do_handshake_on_connect=True, suppress_ragged_eofs=True, \
++      server_hostname=None)
++
++   Wrap an existing Python socket *sock* and return an :class:`SSLSocket`
++   object.  *sock* must be a :data:`~socket.SOCK_STREAM` socket; other socket
++   types are unsupported.
++
++   The returned SSL socket is tied to the context, its settings and
++   certificates.  The parameters *server_side*, *do_handshake_on_connect*
++   and *suppress_ragged_eofs* have the same meaning as in the top-level
++   :func:`wrap_socket` function.
++
++   On client connections, the optional parameter *server_hostname* specifies
++   the hostname of the service which we are connecting to.  This allows a
++   single server to host multiple SSL-based services with distinct certificates,
++   quite similarly to HTTP virtual hosts.  Specifying *server_hostname*
++   will raise a :exc:`ValueError` if the OpenSSL library doesn't have support
++   for it (that is, if :data:`HAS_SNI` is :const:`False`).  Specifying
++   *server_hostname* will also raise a :exc:`ValueError` if *server_side*
++   is true.
++
++.. method:: SSLContext.session_stats()
++
++   Get statistics about the SSL sessions created or managed by this context.
++   A dictionary is returned which maps the names of each `piece of information
++   <http://www.openssl.org/docs/ssl/SSL_CTX_sess_number.html>`_ to their
++   numeric values.  For example, here is the total number of hits and misses
++   in the session cache since the context was created::
++
++      >>> stats = context.session_stats()
++      >>> stats['hits'], stats['misses']
++      (0, 0)
++
++.. method:: SSLContext.get_ca_certs(binary_form=False)
++
++   Returns a list of dicts with information of loaded CA certs. If the
++   optional argument is true, returns a DER-encoded copy of the CA
++   certificate.
++
++   .. note::
++      Certificates in a capath directory aren't loaded unless they have
++      been used at least once.
++
++.. attribute:: SSLContext.check_hostname
++
++   Wether to match the peer cert's hostname with :func:`match_hostname` in
++   :meth:`SSLSocket.do_handshake`. The context's
++   :attr:`~SSLContext.verify_mode` must be set to :data:`CERT_OPTIONAL` or
++   :data:`CERT_REQUIRED`, and you must pass *server_hostname* to
++   :meth:`~SSLContext.wrap_socket` in order to match the hostname.
++
++   Example::
++
++      import socket, ssl
++
++      context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++      context.verify_mode = ssl.CERT_REQUIRED
++      context.check_hostname = True
++      context.load_default_certs()
++
++      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
++      ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com')
++      ssl_sock.connect(('www.verisign.com', 443))
++
++   .. note::
++
++     This features requires OpenSSL 0.9.8f or newer.
++
++.. attribute:: SSLContext.options
++
++   An integer representing the set of SSL options enabled on this context.
++   The default value is :data:`OP_ALL`, but you can specify other options
++   such as :data:`OP_NO_SSLv2` by ORing them together.
++
++   .. note::
++      With versions of OpenSSL older than 0.9.8m, it is only possible
++      to set options, not to clear them.  Attempting to clear an option
++      (by resetting the corresponding bits) will raise a ``ValueError``.
++
++.. attribute:: SSLContext.protocol
++
++   The protocol version chosen when constructing the context.  This attribute
++   is read-only.
++
++.. attribute:: SSLContext.verify_flags
++
++   The flags for certificate verification operations. You can set flags like
++   :data:`VERIFY_CRL_CHECK_LEAF` by ORing them together. By default OpenSSL
++   does neither require nor verify certificate revocation lists (CRLs).
++   Available only with openssl version 0.9.8+.
++
++.. attribute:: SSLContext.verify_mode
++
++   Whether to try to verify other peers' certificates and how to behave
++   if verification fails.  This attribute must be one of
++   :data:`CERT_NONE`, :data:`CERT_OPTIONAL` or :data:`CERT_REQUIRED`.
++
+ 
+ .. index:: single: certificates
+ 
+@@ -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`.
++
++Combined key and certificate
++^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++Often the private key is stored in the same file as the certificate; in this
++case, only the ``certfile`` parameter to :meth:`SSLContext.load_cert_chain`
++and :func:`wrap_socket` needs to be passed.  If the private key is stored
++with the certificate, it should come before the first certificate in
++the certificate chain::
+ 
+-Some "standard" root certificates are available from various certification
+-authorities: `Thawte <http://www.thawte.com/roots/>`_, `Verisign
+-<http://www.verisign.com/support/roots.html>`_, `Positive SSL
+-<http://www.PositiveSSL.com/ssl-certificate-support/cert_installation/UTN-USERFirst-Hardware.crt>`_
+-(used by python.org), `Equifax and GeoTrust
+-<http://www.geotrust.com/resources/root_certificates/index.asp>`_.
++   -----BEGIN RSA PRIVATE KEY-----
++   ... (private key in base64 encoding) ...
++   -----END RSA PRIVATE KEY-----
++   -----BEGIN CERTIFICATE-----
++   ... (certificate in base64 PEM encoding) ...
++   -----END 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.
++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'),))}
+-
+-which is a fairly poorly-formed ``subject`` field.
++   {'issuer': ((('countryName', 'US'),),
++               (('organizationName', 'VeriSign, Inc.'),),
++               (('organizationalUnitName', 'VeriSign Trust Network'),),
++               (('organizationalUnitName',
++                 'Terms of use at https://www.verisign.com/rpa (c)06'),),
++               (('commonName',
++                 'VeriSign Class 3 Extended Validation SSL SGC CA'),)),
++    'notAfter': 'May 25 23:59:59 2012 GMT',
++    'notBefore': 'May 26 00:00:00 2010 GMT',
++    'serialNumber': '53D2BEF924A7245E83CA01E46CAA2477',
++    'subject': ((('1.3.6.1.4.1.311.60.2.1.3', 'US'),),
++                (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),),
++                (('businessCategory', 'V1.0, Clause 5.(b)'),),
++                (('serialNumber', '2497886'),),
++                (('countryName', 'US'),),
++                (('postalCode', '94043'),),
++                (('stateOrProvinceName', 'California'),),
++                (('localityName', 'Mountain View'),),
++                (('streetAddress', '487 East Middlefield Road'),),
++                (('organizationName', 'VeriSign, Inc.'),),
++                (('organizationalUnitName', ' Production Security Services'),),
++                (('commonName', 'www.verisign.com'),)),
++    'subjectAltName': (('DNS', 'www.verisign.com'),
++                       ('DNS', 'verisign.com'),
++                       ('DNS', 'www.verisign.net'),
++                       ('DNS', 'verisign.net'),
++                       ('DNS', 'www.verisign.mobi'),
++                       ('DNS', 'verisign.mobi'),
++                       ('DNS', 'www.verisign.eu'),
++                       ('DNS', 'verisign.eu')),
++    'version': 3}
++
++This other example first creates an SSL context, instructs it to verify
++certificates sent by peers, and feeds it a set of recognized certificate
++authorities (CA)::
++
++   >>> context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++   >>> context.verify_mode = ssl.CERT_REQUIRED
++   >>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")
++
++(it is assumed your operating system places a bundle of all CA certificates
++in ``/etc/ssl/certs/ca-bundle.crt``; if not, you'll get an error and have
++to adjust the location)
++
++When you use the context to connect to a server, :const:`CERT_REQUIRED`
++validates the server certificate: it ensures that the server certificate
++was signed with one of the CA certificates, and checks the signature for
++correctness::
++
++   >>> conn = context.wrap_socket(socket.socket(socket.AF_INET))
++   >>> conn.connect(("linuxfr.org", 443))
++
++You should then fetch the certificate and check its fields for conformity::
++
++   >>> cert = conn.getpeercert()
++   >>> ssl.match_hostname(cert, "linuxfr.org")
++
++Visual inspection shows that the certificate does identify the desired service
++(that is, the HTTPS host ``linuxfr.org``)::
++
++   >>> pprint.pprint(cert)
++   {'issuer': ((('organizationName', 'CAcert Inc.'),),
++               (('organizationalUnitName', 'http://www.CAcert.org'),),
++               (('commonName', 'CAcert Class 3 Root'),)),
++    'notAfter': 'Jun  7 21:02:24 2013 GMT',
++    'notBefore': 'Jun  8 21:02:24 2011 GMT',
++    'serialNumber': 'D3E9',
++    'subject': ((('commonName', 'linuxfr.org'),),),
++    'subjectAltName': (('DNS', 'linuxfr.org'),
++                       ('othername', '<unsupported>'),
++                       ('DNS', 'linuxfr.org'),
++                       ('othername', '<unsupported>'),
++                       ('DNS', 'dev.linuxfr.org'),
++                       ('othername', '<unsupported>'),
++                       ('DNS', 'prod.linuxfr.org'),
++                       ('othername', '<unsupported>'),
++                       ('DNS', 'alpha.linuxfr.org'),
++                       ('othername', '<unsupported>'),
++                       ('DNS', '*.linuxfr.org'),
++                       ('othername', '<unsupported>')),
++    'version': 3}
++
++Now that you are assured of its authenticity, you can proceed to talk with
++the server::
++
++   >>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")
++   >>> pprint.pprint(conn.recv(1024).split(b"\r\n"))
++   [b'HTTP/1.1 302 Found',
++    b'Date: Sun, 16 May 2010 13:43:28 GMT',
++    b'Server: Apache/2.2',
++    b'Location: https://linuxfr.org/pub/',
++    b'Vary: Accept-Encoding',
++    b'Connection: close',
++    b'Content-Type: text/html; charset=iso-8859-1',
++    b'',
++    b'']
++
++See the discussion of :ref:`ssl-security` below.
++
+ 
+ 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 client is finished with you)::
+            data = connstream.read()
+        # finished with client
+ 
+-And go back to listening for new client connections.
++And go back to listening for new client connections (of course, a real server
++would probably handle each client connection in a separate thread, or put
++the sockets in non-blocking mode and use an event loop).
++
++
++.. _ssl-nonblocking:
++
++Notes on non-blocking sockets
++-----------------------------
++
++When working with non-blocking sockets, there are several things you need
++to be aware of:
++
++- Calling :func:`~select.select` tells you that the OS-level socket can be
++  read from (or written to), but it does not imply that there is sufficient
++  data at the upper SSL layer.  For example, only part of an SSL frame might
++  have arrived.  Therefore, you must be ready to handle :meth:`SSLSocket.recv`
++  and :meth:`SSLSocket.send` failures, and retry after another call to
++  :func:`~select.select`.
++
++- Conversely, since the SSL layer has its own framing, a SSL socket may
++  still have data available for reading without :func:`~select.select`
++  being aware of it.  Therefore, you should first call
++  :meth:`SSLSocket.recv` to drain any potentially available data, and then
++  only block on a :func:`~select.select` call if still necessary.
++
++  (of course, similar provisions apply when using other primitives such as
++  :func:`~select.poll`, or those in the :mod:`selectors` module)
++
++- The SSL handshake itself will be non-blocking: the
++  :meth:`SSLSocket.do_handshake` method has to be retried until it returns
++  successfully.  Here is a synopsis using :func:`~select.select` to wait for
++  the socket's readiness::
++
++    while True:
++        try:
++            sock.do_handshake()
++            break
++        except ssl.SSLWantReadError:
++            select.select([sock], [], [])
++        except ssl.SSLWantWriteError:
++            select.select([], [sock], [])
++
++
++.. _ssl-security:
++
++Security considerations
++-----------------------
++
++Best defaults
++^^^^^^^^^^^^^
++
++For **client use**, if you don't have any special requirements for your
++security policy, it is highly recommended that you use the
++:func:`create_default_context` function to create your SSL context.
++It will load the system's trusted CA certificates, enable certificate
++validation and hostname checking, and try to choose reasonably secure
++protocol and cipher settings.
++
++If a client certificate is needed for the connection, it can be added with
++:meth:`SSLContext.load_cert_chain`.
++
++By contrast, if you create the SSL context by calling the :class:`SSLContext`
++constructor yourself, it will not have certificate validation nor hostname
++checking enabled by default.  If you do so, please read the paragraphs below
++to achieve a good security level.
++
++Manual settings
++^^^^^^^^^^^^^^^
++
++Verifying certificates
++''''''''''''''''''''''
++
++When calling the :class:`SSLContext` constructor directly,
++:const:`CERT_NONE` is the default.  Since it does not authenticate the other
++peer, it can be insecure, especially in client mode where most of time you
++would like to ensure the authenticity of the server you're talking to.
++Therefore, when in client mode, it is highly recommended to use
++:const:`CERT_REQUIRED`.  However, it is in itself not sufficient; you also
++have to check that the server certificate, which can be obtained by calling
++:meth:`SSLSocket.getpeercert`, matches the desired service.  For many
++protocols and applications, the service can be identified by the hostname;
++in this case, the :func:`match_hostname` function can be used.  This common
++check is automatically performed when :attr:`SSLContext.check_hostname` is
++enabled.
++
++In server mode, if you want to authenticate your clients using the SSL layer
++(rather than using a higher-level authentication mechanism), you'll also have
++to specify :const:`CERT_REQUIRED` and similarly check the client certificate.
++
++   .. note::
++
++      In client mode, :const:`CERT_OPTIONAL` and :const:`CERT_REQUIRED` are
++      equivalent unless anonymous ciphers are enabled (they are disabled
++      by default).
++
++Protocol versions
++'''''''''''''''''
++
++SSL version 2 is considered insecure and is therefore dangerous to use.  If
++you want maximum compatibility between clients and servers, it is recommended
++to use :const:`PROTOCOL_SSLv23` as the protocol version and then disable
++SSLv2 explicitly using the :data:`SSLContext.options` attribute::
++
++   context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++   context.options |= ssl.OP_NO_SSLv2
++
++The SSL context created above will allow SSLv3 and TLSv1 (and later, if
++supported by your system) connections, but not SSLv2.
++
++Cipher selection
++''''''''''''''''
++
++If you have advanced security requirements, fine-tuning of the ciphers
++enabled when negotiating a SSL session is possible through the
++:meth:`SSLContext.set_ciphers` method.  Starting from Python 2.7.9, the
++ssl module disables certain weak ciphers by default, but you may want
++to further restrict the cipher choice. Be sure to read OpenSSL's documentation
++about the `cipher list format <http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_.
++If you want to check which ciphers are enabled by a given cipher list, use the
++``openssl ciphers`` command on your system.
++
++Multi-processing
++^^^^^^^^^^^^^^^^
++
++If using this module as part of a multi-processed application (using,
++for example the :mod:`multiprocessing` or :mod:`concurrent.futures` modules),
++be aware that OpenSSL's internal random number generator does not properly
++handle forked processes.  Applications must change the PRNG state of the
++parent process if they use any SSL feature with :func:`os.fork`.  Any
++successful call of :func:`~ssl.RAND_add`, :func:`~ssl.RAND_bytes` or
++:func:`~ssl.RAND_pseudo_bytes` is sufficient.
+ 
+ 
+ .. seealso::
+@@ -668,3 +1680,15 @@ And go back to listening for new client connections.
+ 
+    `RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile <http://www.ietf.org/rfc/rfc3280>`_
+        Housley et. al.
++
++   `RFC 4366: Transport Layer Security (TLS) Extensions <http://www.ietf.org/rfc/rfc4366>`_
++       Blake-Wilson et. al.
++
++   `RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 <http://www.ietf.org/rfc/rfc5246>`_
++       T. Dierks et. al.
++
++   `RFC 6066: Transport Layer Security (TLS) Extensions <http://www.ietf.org/rfc/rfc6066>`_
++       D. Eastlake
++
++   `IANA TLS: Transport Layer Security (TLS) Parameters <http://www.iana.org/assignments/tls-parameters/tls-parameters.xml>`_
++       IANA
+diff --git a/Lib/ssl.py b/Lib/ssl.py
+index 666cea3..882b60e 100644
+--- a/Lib/ssl.py
++++ b/Lib/ssl.py
+@@ -1,8 +1,7 @@
+ # Wrapper module for _ssl, providing some additional facilities
+ # implemented in Python.  Written by Bill Janssen.
+ 
+-"""\
+-This module provides some more Pythonic support for SSL.
++"""This module provides some more Pythonic support for SSL.
+ 
+ Object types:
+ 
+@@ -53,62 +52,461 @@ PROTOCOL_SSLv2
+ PROTOCOL_SSLv3
+ PROTOCOL_SSLv23
+ PROTOCOL_TLSv1
++PROTOCOL_TLSv1_1
++PROTOCOL_TLSv1_2
++
++The following constants identify various SSL alert message descriptions as per
++http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6
++
++ALERT_DESCRIPTION_CLOSE_NOTIFY
++ALERT_DESCRIPTION_UNEXPECTED_MESSAGE
++ALERT_DESCRIPTION_BAD_RECORD_MAC
++ALERT_DESCRIPTION_RECORD_OVERFLOW
++ALERT_DESCRIPTION_DECOMPRESSION_FAILURE
++ALERT_DESCRIPTION_HANDSHAKE_FAILURE
++ALERT_DESCRIPTION_BAD_CERTIFICATE
++ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE
++ALERT_DESCRIPTION_CERTIFICATE_REVOKED
++ALERT_DESCRIPTION_CERTIFICATE_EXPIRED
++ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN
++ALERT_DESCRIPTION_ILLEGAL_PARAMETER
++ALERT_DESCRIPTION_UNKNOWN_CA
++ALERT_DESCRIPTION_ACCESS_DENIED
++ALERT_DESCRIPTION_DECODE_ERROR
++ALERT_DESCRIPTION_DECRYPT_ERROR
++ALERT_DESCRIPTION_PROTOCOL_VERSION
++ALERT_DESCRIPTION_INSUFFICIENT_SECURITY
++ALERT_DESCRIPTION_INTERNAL_ERROR
++ALERT_DESCRIPTION_USER_CANCELLED
++ALERT_DESCRIPTION_NO_RENEGOTIATION
++ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION
++ALERT_DESCRIPTION_CERTIFICATE_UNOBTAINABLE
++ALERT_DESCRIPTION_UNRECOGNIZED_NAME
++ALERT_DESCRIPTION_BAD_CERTIFICATE_STATUS_RESPONSE
++ALERT_DESCRIPTION_BAD_CERTIFICATE_HASH_VALUE
++ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY
+ """
+ 
+ import textwrap
++import re
++import sys
++import os
++from collections import namedtuple
++from contextlib import closing
+ 
+ import _ssl             # if we can't import it, let the error propagate
+ 
+ from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
+-from _ssl import SSLError
++from _ssl import _SSLContext
++from _ssl import (
++    SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError,
++    SSLSyscallError, SSLEOFError,
++    )
+ from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
++from _ssl import (VERIFY_DEFAULT, VERIFY_CRL_CHECK_LEAF, VERIFY_CRL_CHECK_CHAIN,
++    VERIFY_X509_STRICT)
++from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj
+ from _ssl import RAND_status, RAND_egd, RAND_add
+-from _ssl import \
+-     SSL_ERROR_ZERO_RETURN, \
+-     SSL_ERROR_WANT_READ, \
+-     SSL_ERROR_WANT_WRITE, \
+-     SSL_ERROR_WANT_X509_LOOKUP, \
+-     SSL_ERROR_SYSCALL, \
+-     SSL_ERROR_SSL, \
+-     SSL_ERROR_WANT_CONNECT, \
+-     SSL_ERROR_EOF, \
+-     SSL_ERROR_INVALID_ERROR_CODE
+-from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1
+-_PROTOCOL_NAMES = {
+-    PROTOCOL_TLSv1: "TLSv1",
+-    PROTOCOL_SSLv23: "SSLv23",
+-    PROTOCOL_SSLv3: "SSLv3",
+-}
++
++def _import_symbols(prefix):
++    for n in dir(_ssl):
++        if n.startswith(prefix):
++            globals()[n] = getattr(_ssl, n)
++
++_import_symbols('OP_')
++_import_symbols('ALERT_DESCRIPTION_')
++_import_symbols('SSL_ERROR_')
++_import_symbols('PROTOCOL_')
++
++from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN
++
++from _ssl import _OPENSSL_API_VERSION
++
++_PROTOCOL_NAMES = {value: name for name, value in globals().items() if name.startswith('PROTOCOL_')}
++
+ try:
+-    from _ssl import PROTOCOL_SSLv2
+     _SSLv2_IF_EXISTS = PROTOCOL_SSLv2
+-except ImportError:
++except NameError:
+     _SSLv2_IF_EXISTS = None
+-else:
+-    _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2"
+ 
+ from socket import socket, _fileobject, _delegate_methods, error as socket_error
+-from socket import getnameinfo as _getnameinfo
+-from socket import SOL_SOCKET, SO_TYPE, SOCK_STREAM
++if sys.platform == "win32":
++    from _ssl import enum_certificates, enum_crls
++
++from socket import socket, AF_INET, SOCK_STREAM, create_connection
++from socket import SOL_SOCKET, SO_TYPE
+ import base64        # for DER-to-PEM translation
+ import errno
+ 
++if _ssl.HAS_TLS_UNIQUE:
++    CHANNEL_BINDING_TYPES = ['tls-unique']
++else:
++    CHANNEL_BINDING_TYPES = []
++
+ # Disable weak or insecure ciphers by default
+ # (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
+-_DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2'
+-
++# Enable a better set of ciphers by default
++# This list has been explicitly chosen to:
++#   * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
++#   * Prefer ECDHE over DHE for better performance
++#   * Prefer any AES-GCM over any AES-CBC for better performance and security
++#   * Then Use HIGH cipher suites as a fallback
++#   * Then Use 3DES as fallback which is secure but slow
++#   * Finally use RC4 as a fallback which is problematic but needed for
++#     compatibility some times.
++#   * Disable NULL authentication, NULL encryption, and MD5 MACs for security
++#     reasons
++_DEFAULT_CIPHERS = (
++    'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
++    'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:'
++    'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'
++)
++
++# Restricted and more secure ciphers for the server side
++# This list has been explicitly chosen to:
++#   * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
++#   * Prefer ECDHE over DHE for better performance
++#   * Prefer any AES-GCM over any AES-CBC for better performance and security
++#   * Then Use HIGH cipher suites as a fallback
++#   * Then Use 3DES as fallback which is secure but slow
++#   * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, and RC4 for
++#     security reasons
++_RESTRICTED_SERVER_CIPHERS = (
++    'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
++    'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
++    '!eNULL:!MD5:!DSS:!RC4'
++)
++
++
++class CertificateError(ValueError):
++    pass
++
++
++def _dnsname_match(dn, hostname, max_wildcards=1):
++    """Matching according to RFC 6125, section 6.4.3
++
++    http://tools.ietf.org/html/rfc6125#section-6.4.3
++    """
++    pats = []
++    if not dn:
++        return False
++
++    pieces = dn.split(r'.')
++    leftmost = pieces[0]
++    remainder = pieces[1:]
++
++    wildcards = leftmost.count('*')
++    if wildcards > max_wildcards:
++        # Issue #17980: avoid denials of service by refusing more
++        # than one wildcard per fragment.  A survery of established
++        # policy among SSL implementations showed it to be a
++        # reasonable choice.
++        raise CertificateError(
++            "too many wildcards in certificate DNS name: " + repr(dn))
++
++    # speed up common case w/o wildcards
++    if not wildcards:
++        return dn.lower() == hostname.lower()
++
++    # RFC 6125, section 6.4.3, subitem 1.
++    # The client SHOULD NOT attempt to match a presented identifier in which
++    # the wildcard character comprises a label other than the left-most label.
++    if leftmost == '*':
++        # When '*' is a fragment by itself, it matches a non-empty dotless
++        # fragment.
++        pats.append('[^.]+')
++    elif leftmost.startswith('xn--') or hostname.startswith('xn--'):
++        # RFC 6125, section 6.4.3, subitem 3.
++        # The client SHOULD NOT attempt to match a presented identifier
++        # where the wildcard character is embedded within an A-label or
++        # U-label of an internationalized domain name.
++        pats.append(re.escape(leftmost))
++    else:
++        # Otherwise, '*' matches any dotless string, e.g. www*
++        pats.append(re.escape(leftmost).replace(r'\*', '[^.]*'))
++
++    # add the remaining fragments, ignore any wildcards
++    for frag in remainder:
++        pats.append(re.escape(frag))
++
++    pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
++    return pat.match(hostname)
++
++
++def match_hostname(cert, hostname):
++    """Verify that *cert* (in decoded format as returned by
++    SSLSocket.getpeercert()) matches the *hostname*.  RFC 2818 and RFC 6125
++    rules are followed, but IP addresses are not accepted for *hostname*.
++
++    CertificateError is raised on failure. On success, the function
++    returns nothing.
++    """
++    if not cert:
++        raise ValueError("empty or no certificate, match_hostname needs a "
++                         "SSL socket or SSL context with either "
++                         "CERT_OPTIONAL or CERT_REQUIRED")
++    dnsnames = []
++    san = cert.get('subjectAltName', ())
++    for key, value in san:
++        if key == 'DNS':
++            if _dnsname_match(value, hostname):
++                return
++            dnsnames.append(value)
++    if not dnsnames:
++        # The subject is only checked when there is no dNSName entry
++        # in subjectAltName
++        for sub in cert.get('subject', ()):
++            for key, value in sub:
++                # XXX according to RFC 2818, the most specific Common Name
++                # must be used.
++                if key == 'commonName':
++                    if _dnsname_match(value, hostname):
++                        return
++                    dnsnames.append(value)
++    if len(dnsnames) > 1:
++        raise CertificateError("hostname %r "
++            "doesn't match either of %s"
++            % (hostname, ', '.join(map(repr, dnsnames))))
++    elif len(dnsnames) == 1:
++        raise CertificateError("hostname %r "
++            "doesn't match %r"
++            % (hostname, dnsnames[0]))
++    else:
++        raise CertificateError("no appropriate commonName or "
++            "subjectAltName fields were found")
++
++
++DefaultVerifyPaths = namedtuple("DefaultVerifyPaths",
++    "cafile capath openssl_cafile_env openssl_cafile openssl_capath_env "
++    "openssl_capath")
++
++def get_default_verify_paths():
++    """Return paths to default cafile and capath.
++    """
++    parts = _ssl.get_default_verify_paths()
++
++    # environment vars shadow paths
++    cafile = os.environ.get(parts[0], parts[1])
++    capath = os.environ.get(parts[2], parts[3])
++
++    return DefaultVerifyPaths(cafile if os.path.isfile(cafile) else None,
++                              capath if os.path.isdir(capath) else None,
++                              *parts)
++
++
++class _ASN1Object(namedtuple("_ASN1Object", "nid shortname longname oid")):
++    """ASN.1 object identifier lookup
++    """
++    __slots__ = ()
++
++    def __new__(cls, oid):
++        return super(_ASN1Object, cls).__new__(cls, *_txt2obj(oid, name=False))
++
++    @classmethod
++    def fromnid(cls, nid):
++        """Create _ASN1Object from OpenSSL numeric ID
++        """
++        return super(_ASN1Object, cls).__new__(cls, *_nid2obj(nid))
++
++    @classmethod
++    def fromname(cls, name):
++        """Create _ASN1Object from short name, long name or OID
++        """
++        return super(_ASN1Object, cls).__new__(cls, *_txt2obj(name, name=True))
++
++
++class Purpose(_ASN1Object):
++    """SSLContext purpose flags with X509v3 Extended Key Usage objects
++    """
++
++Purpose.SERVER_AUTH = Purpose('1.3.6.1.5.5.7.3.1')
++Purpose.CLIENT_AUTH = Purpose('1.3.6.1.5.5.7.3.2')
++
++
++class SSLContext(_SSLContext):
++    """An SSLContext holds various SSL-related configuration options and
++    data, such as certificates and possibly a private key."""
++
++    __slots__ = ('protocol', '__weakref__')
++    _windows_cert_stores = ("CA", "ROOT")
++
++    def __new__(cls, protocol, *args, **kwargs):
++        self = _SSLContext.__new__(cls, protocol)
++        if protocol != _SSLv2_IF_EXISTS:
++            self.set_ciphers(_DEFAULT_CIPHERS)
++        return self
++
++    def __init__(self, protocol):
++        self.protocol = protocol
++
++    def wrap_socket(self, sock, server_side=False,
++                    do_handshake_on_connect=True,
++                    suppress_ragged_eofs=True,
++                    server_hostname=None):
++        return SSLSocket(sock=sock, server_side=server_side,
++                         do_handshake_on_connect=do_handshake_on_connect,
++                         suppress_ragged_eofs=suppress_ragged_eofs,
++                         server_hostname=server_hostname,
++                         _context=self)
++
++    def set_npn_protocols(self, npn_protocols):
++        protos = bytearray()
++        for protocol in npn_protocols:
++            b = protocol.encode('ascii')
++            if len(b) == 0 or len(b) > 255:
++                raise SSLError('NPN protocols must be 1 to 255 in length')
++            protos.append(len(b))
++            protos.extend(b)
++
++        self._set_npn_protocols(protos)
++
++    def _load_windows_store_certs(self, storename, purpose):
++        certs = bytearray()
++        for cert, encoding, trust in enum_certificates(storename):
++            # CA certs are never PKCS#7 encoded
++            if encoding == "x509_asn":
++                if trust is True or purpose.oid in trust:
++                    certs.extend(cert)
++        self.load_verify_locations(cadata=certs)
++        return certs
++
++    def load_default_certs(self, purpose=Purpose.SERVER_AUTH):
++        if not isinstance(purpose, _ASN1Object):
++            raise TypeError(purpose)
++        if sys.platform == "win32":
++            for storename in self._windows_cert_stores:
++                self._load_windows_store_certs(storename, purpose)
++        else:
++            self.set_default_verify_paths()
++
++
++def create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None,
++                           capath=None, cadata=None):
++    """Create a SSLContext object with default settings.
++
++    NOTE: The protocol and settings may change anytime without prior
++          deprecation. The values represent a fair balance between maximum
++          compatibility and security.
++    """
++    if not isinstance(purpose, _ASN1Object):
++        raise TypeError(purpose)
++
++    context = SSLContext(PROTOCOL_SSLv23)
++
++    # SSLv2 considered harmful.
++    context.options |= OP_NO_SSLv2
++
++    # SSLv3 has problematic security and is only required for really old
++    # clients such as IE6 on Windows XP
++    context.options |= OP_NO_SSLv3
++
++    # disable compression to prevent CRIME attacks (OpenSSL 1.0+)
++    context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0)
++
++    if purpose == Purpose.SERVER_AUTH:
++        # verify certs and host name in client mode
++        context.verify_mode = CERT_REQUIRED
++        context.check_hostname = True
++    elif purpose == Purpose.CLIENT_AUTH:
++        # Prefer the server's ciphers by default so that we get stronger
++        # encryption
++        context.options |= getattr(_ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
++
++        # Use single use keys in order to improve forward secrecy
++        context.options |= getattr(_ssl, "OP_SINGLE_DH_USE", 0)
++        context.options |= getattr(_ssl, "OP_SINGLE_ECDH_USE", 0)
++
++        # disallow ciphers with known vulnerabilities
++        context.set_ciphers(_RESTRICTED_SERVER_CIPHERS)
++
++    if cafile or capath or cadata:
++        context.load_verify_locations(cafile, capath, cadata)
++    elif context.verify_mode != CERT_NONE:
++        # no explicit cafile, capath or cadata but the verify mode is
++        # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system
++        # root CA certificates for the given purpose. This may fail silently.
++        context.load_default_certs(purpose)
++    return context
++
++
++def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None,
++                           check_hostname=False, purpose=Purpose.SERVER_AUTH,
++                           certfile=None, keyfile=None,
++                           cafile=None, capath=None, cadata=None):
++    """Create a SSLContext object for Python stdlib modules
++
++    All Python stdlib modules shall use this function to create SSLContext
++    objects in order to keep common settings in one place. The configuration
++    is less restrict than create_default_context()'s to increase backward
++    compatibility.
++    """
++    if not isinstance(purpose, _ASN1Object):
++        raise TypeError(purpose)
++
++    context = SSLContext(protocol)
++    # SSLv2 considered harmful.
++    context.options |= OP_NO_SSLv2
++
++    if cert_reqs is not None:
++        context.verify_mode = cert_reqs
++    context.check_hostname = check_hostname
++
++    if keyfile and not certfile:
++        raise ValueError("certfile must be specified")
++    if certfile or keyfile:
++        context.load_cert_chain(certfile, keyfile)
++
++    # load CA root certs
++    if cafile or capath or cadata:
++        context.load_verify_locations(cafile, capath, cadata)
++    elif context.verify_mode != CERT_NONE:
++        # no explicit cafile, capath or cadata but the verify mode is
++        # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system
++        # root CA certificates for the given purpose. This may fail silently.
++        context.load_default_certs(purpose)
++
++    return context
+ 
+ class SSLSocket(socket):
+-
+     """This class implements a subtype of socket.socket that wraps
+     the underlying OS socket in an SSL context when necessary, and
+     provides read and write methods over that channel."""
+ 
+-    def __init__(self, sock, keyfile=None, certfile=None,
++    def __init__(self, sock=None, keyfile=None, certfile=None,
+                  server_side=False, cert_reqs=CERT_NONE,
+                  ssl_version=PROTOCOL_SSLv23, ca_certs=None,
+                  do_handshake_on_connect=True,
+-                 suppress_ragged_eofs=True, ciphers=None):
++                 family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
++                 suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
++                 server_hostname=None,
++                 _context=None):
++
++        if _context:
++            self._context = _context
++        else:
++            if server_side and not certfile:
++                raise ValueError("certfile must be specified for server-side "
++                                 "operations")
++            if keyfile and not certfile:
++                raise ValueError("certfile must be specified")
++            if certfile and not keyfile:
++                keyfile = certfile
++            self._context = SSLContext(ssl_version)
++            self._context.verify_mode = cert_reqs
++            if ca_certs:
++                self._context.load_verify_locations(ca_certs)
++            if certfile:
++                self._context.load_cert_chain(certfile, keyfile)
++            if npn_protocols:
++                self._context.set_npn_protocols(npn_protocols)
++            if ciphers:
++                self._context.set_ciphers(ciphers)
++            self.keyfile = keyfile
++            self.certfile = certfile
++            self.cert_reqs = cert_reqs
++            self.ssl_version = ssl_version
++            self.ca_certs = ca_certs
++            self.ciphers = ciphers
+         # Can't use sock.type as other flags (such as SOCK_NONBLOCK) get
+         # mixed in.
+         if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
+@@ -122,98 +520,161 @@ class SSLSocket(socket):
+                 delattr(self, attr)
+             except AttributeError:
+                 pass
++        if server_side and server_hostname:
++            raise ValueError("server_hostname can only be specified "
++                             "in client mode")
++        if self._context.check_hostname and not server_hostname:
++            if HAS_SNI:
++                raise ValueError("check_hostname requires server_hostname")
++            else:
++                raise ValueError("check_hostname requires server_hostname, "
++                                 "but it's not supported by your OpenSSL "
++                                 "library")
++        self.server_side = server_side
++        self.server_hostname = server_hostname
++        self.do_handshake_on_connect = do_handshake_on_connect
++        self.suppress_ragged_eofs = suppress_ragged_eofs
+ 
+-        if ciphers is None and ssl_version != _SSLv2_IF_EXISTS:
+-            ciphers = _DEFAULT_CIPHERS
+-
+-        if certfile and not keyfile:
+-            keyfile = certfile
+-        # see if it's connected
++        # See if we are connected
+         try:
+-            socket.getpeername(self)
+-        except socket_error, e:
++            self.getpeername()
++        except socket_error as e:
+             if e.errno != errno.ENOTCONN:
+                 raise
+-            # no, no connection yet
+-            self._connected = False
+-            self._sslobj = None
++            connected = False
+         else:
+-            # yes, create the SSL object
+-            self._connected = True
+-            self._sslobj = _ssl.sslwrap(self._sock, server_side,
+-                                        keyfile, certfile,
+-                                        cert_reqs, ssl_version, ca_certs,
+-                                        ciphers)
+-            if do_handshake_on_connect:
+-                self.do_handshake()
+-        self.keyfile = keyfile
+-        self.certfile = certfile
+-        self.cert_reqs = cert_reqs
+-        self.ssl_version = ssl_version
+-        self.ca_certs = ca_certs
+-        self.ciphers = ciphers
+-        self.do_handshake_on_connect = do_handshake_on_connect
+-        self.suppress_ragged_eofs = suppress_ragged_eofs
++            connected = True
++
++        self._closed = False
++        self._sslobj = None
++        self._connected = connected
++        if connected:
++            # create the SSL object
++            try:
++                self._sslobj = self._context._wrap_socket(self._sock, server_side,
++                                                          server_hostname, ssl_sock=self)
++                if do_handshake_on_connect:
++                    timeout = self.gettimeout()
++                    if timeout == 0.0:
++                        # non-blocking
++                        raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
++                    self.do_handshake()
++
++            except (OSError, ValueError):
++                self.close()
++                raise
+         self._makefile_refs = 0
+ 
+-    def read(self, len=1024):
++    @property
++    def context(self):
++        return self._context
++
++    @context.setter
++    def context(self, ctx):
++        self._context = ctx
++        self._sslobj.context = ctx
++
++    def dup(self):
++        raise NotImplemented("Can't dup() %s instances" %
++                             self.__class__.__name__)
++
++    def _checkClosed(self, msg=None):
++        # raise an exception here if you wish to check for spurious closes
++        pass
+ 
++    def _check_connected(self):
++        if not self._connected:
++            # getpeername() will raise ENOTCONN if the socket is really
++            # not connected; note that we can be connected even without
++            # _connected being set, e.g. if connect() first returned
++            # EAGAIN.
++            self.getpeername()
++
++    def read(self, len=0, buffer=None):
+         """Read up to LEN bytes and return them.
+         Return zero-length string on EOF."""
+ 
++        self._checkClosed()
++        if not self._sslobj:
++            raise ValueError("Read on closed or unwrapped SSL socket.")
+         try:
+-            return self._sslobj.read(len)
+-        except SSLError, x:
++            if buffer is not None:
++                v = self._sslobj.read(len, buffer)
++            else:
++                v = self._sslobj.read(len or 1024)
++            return v
++        except SSLError as x:
+             if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:
+-                return ''
++                if buffer is not None:
++                    return 0
++                else:
++                    return b''
+             else:
+                 raise
+ 
+     def write(self, data):
+-
+         """Write DATA to the underlying SSL channel.  Returns
+         number of bytes of DATA actually transmitted."""
+ 
++        self._checkClosed()
++        if not self._sslobj:
++            raise ValueError("Write on closed or unwrapped SSL socket.")
+         return self._sslobj.write(data)
+ 
+     def getpeercert(self, binary_form=False):
+-
+         """Returns a formatted version of the data in the
+         certificate provided by the other end of the SSL channel.
+         Return None if no certificate was provided, {} if a
+         certificate was provided, but not validated."""
+ 
++        self._checkClosed()
++        self._check_connected()
+         return self._sslobj.peer_certificate(binary_form)
+ 
+-    def cipher(self):
++    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):
+-
+-        """Perform a TLS/SSL handshake."""
++    def unwrap(self):
++        if self._sslobj:
++            s = self._sslobj.shutdown()
++            self._sslobj = None
++            return s
++        else:
++            raise ValueError("No SSL wrapper around " + str(self))
+ 
+-        self._sslobj.do_handshake()
++    def _real_close(self):
++        self._sslobj = None
++        socket._real_close(self)
+ 
+-    def _real_connect(self, addr, return_errno):
++    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)
++
++        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, 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):
+-
+-    """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."""
+-
+-    import time
+-    return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT"))
++    """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).
++
++    "notBefore" or "notAfter" dates must use UTC (RFC 5280).
++
++    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)
+-
+-def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None):
++    return base64.decodestring(d.encode('ASCII', 'strict'))
+ 
++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
+index 0000000..9d7ac23
+--- /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
+index 0000000..e7dfc82
+--- /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
+index 0000000..9d7ac23
+--- /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
+index 0000000..e7dfc82
+--- /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
+index 0000000..200d16c
+--- /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
+index 0000000..e905748
+--- /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
+index 0000000..5bfa62c
+--- /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
+index 0000000..53355c8
+--- /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
+index 0000000..81d04f8
+--- /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
+index 0000000..09b1f3e
+--- /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
+index 0000000..6d89b08
+--- /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
+index 9475576..d3db4b8 100644
+--- 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
+index 0000000..47a7d7e
+--- /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
+index 0000000..2524672
+--- /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
+index 0000000..3fd3bbd
+--- /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
+index 0000000..a312e28
+--- /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
+index 91b8029..54dbbd5 100644
+--- a/Lib/test/test_ssl.py
++++ b/Lib/test/test_ssl.py
+@@ -1,35 +1,78 @@
++# -*- encoding: utf-8 -*-
+ # Test the support for SSL and sockets
+ 
+ import sys
+ import unittest
+-from test import test_support
++from test import test_support as support
+ import asyncore
+ import socket
+ import select
+ import time
++import datetime
+ import gc
+ import os
+ import errno
+ import pprint
+-import urllib, urlparse
++import tempfile
++import urllib
+ import traceback
+ import weakref
+-import functools
+ import platform
++import functools
++from contextlib import closing
++
++ssl = support.import_module("ssl")
++
++PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
++HOST = support.HOST
++
++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")
+ 
+-from BaseHTTPServer import HTTPServer
+-from SimpleHTTPServer import SimpleHTTPRequestHandler
++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")
+ 
+-ssl = test_support.import_module("ssl")
++DHFILE = data_file("dh512.pem")
++BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding())
+ 
+-HOST = test_support.HOST
+-CERTFILE = None
+-SVN_PYTHON_ORG_ROOT_CERT = None
+-NULLBYTECERT = None
+ 
+ def handle_error(prefix):
+     exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
+-    if test_support.verbose:
++    if support.verbose:
+         sys.stdout.write(prefix + exc_format)
+ 
+ 
+@@ -51,48 +94,76 @@ class BasicTests(unittest.TestCase):
+                 pass
+             else:
+                 raise
++def can_clear_options():
++    # 0.9.8m or higher
++    return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15)
++
++def no_sslv2_implies_sslv3_hello():
++    # 0.9.7h or higher
++    return ssl.OPENSSL_VERSION_INFO >= (0, 9, 7, 8, 15)
++
++def have_verify_flags():
++    # 0.9.8 or higher
++    return ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 0, 15)
++
++def utc_offset(): #NOTE: ignore issues like #1647654
++    # local time = utc time + utc offset
++    if time.daylight and time.localtime().tm_isdst > 0:
++        return -time.altzone  # seconds
++    return -time.timezone
++
++def asn1time(cert_time):
++    # Some versions of OpenSSL ignore seconds, see #18207
++    # 0.9.8.i
++    if ssl._OPENSSL_API_VERSION == (0, 9, 8, 9, 15):
++        fmt = "%b %d %H:%M:%S %Y GMT"
++        dt = datetime.datetime.strptime(cert_time, fmt)
++        dt = dt.replace(second=0)
++        cert_time = dt.strftime(fmt)
++        # %d adds leading zero but ASN1_TIME_print() uses leading space
++        if cert_time[4] == "0":
++            cert_time = cert_time[:4] + " " + cert_time[5:]
++
++    return cert_time
+ 
+ # Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2
+ def skip_if_broken_ubuntu_ssl(func):
+     if hasattr(ssl, 'PROTOCOL_SSLv2'):
+-        # We need to access the lower-level wrapper in order to create an
+-        # implicit SSL context without trying to connect or listen.
+-        try:
+-            import _ssl
+-        except ImportError:
+-            # The returned function won't get executed, just ignore the error
+-            pass
+         @functools.wraps(func)
+         def f(*args, **kwargs):
+             try:
+-                s = socket.socket(socket.AF_INET)
+-                _ssl.sslwrap(s._sock, 0, None, None,
+-                             ssl.CERT_NONE, ssl.PROTOCOL_SSLv2, None, None)
+-            except ssl.SSLError as e:
++                ssl.SSLContext(ssl.PROTOCOL_SSLv2)
++            except ssl.SSLError:
+                 if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and
+-                    platform.linux_distribution() == ('debian', 'squeeze/sid', '')
+-                    and 'Invalid SSL protocol variant specified' in str(e)):
++                    platform.linux_distribution() == ('debian', 'squeeze/sid', '')):
+                     raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour")
+             return func(*args, **kwargs)
+         return f
+     else:
+         return func
+ 
++needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test")
++
+ 
+ class BasicSocketTests(unittest.TestCase):
+ 
+     def test_constants(self):
+-        #ssl.PROTOCOL_SSLv2
+-        ssl.PROTOCOL_SSLv23
+-        ssl.PROTOCOL_SSLv3
+-        ssl.PROTOCOL_TLSv1
+         ssl.CERT_NONE
+         ssl.CERT_OPTIONAL
+         ssl.CERT_REQUIRED
++        ssl.OP_CIPHER_SERVER_PREFERENCE
++        ssl.OP_SINGLE_DH_USE
++        if ssl.HAS_ECDH:
++            ssl.OP_SINGLE_ECDH_USE
++        if ssl.OPENSSL_VERSION_INFO >= (1, 0):
++            ssl.OP_NO_COMPRESSION
++        self.assertIn(ssl.HAS_SNI, {True, False})
++        self.assertIn(ssl.HAS_ECDH, {True, False})
++
+ 
+     def test_random(self):
+         v = ssl.RAND_status()
+-        if test_support.verbose:
++        if support.verbose:
+             sys.stdout.write("\n RAND_status is %d (%s)\n"
+                              % (v, (v and "sufficient randomness") or
+                                 "insufficient randomness"))
+@@ -104,9 +175,19 @@ class BasicSocketTests(unittest.TestCase):
+         # note that this uses an 'unofficial' function in _ssl.c,
+         # provided solely for this test, to exercise the certificate
+         # parsing code
+-        p = ssl._ssl._test_decode_cert(CERTFILE, False)
+-        if test_support.verbose:
++        p = ssl._ssl._test_decode_cert(CERTFILE)
++        if support.verbose:
+             sys.stdout.write("\n" + pprint.pformat(p) + "\n")
++        self.assertEqual(p['issuer'],
++                         ((('countryName', 'XY'),),
++                          (('localityName', 'Castle Anthrax'),),
++                          (('organizationName', 'Python Software Foundation'),),
++                          (('commonName', 'localhost'),))
++                        )
++        # Note the next three asserts will fail if the keys are regenerated
++        self.assertEqual(p['notAfter'], asn1time('Oct  5 23:01:56 2020 GMT'))
++        self.assertEqual(p['notBefore'], asn1time('Oct  8 23:01:56 2010 GMT'))
++        self.assertEqual(p['serialNumber'], 'D7C7381919AFC24E')
+         self.assertEqual(p['subject'],
+                          ((('countryName', 'XY'),),
+                           (('localityName', 'Castle Anthrax'),),
+@@ -117,16 +198,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 at 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 at python.org\x00user at 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', '<unsupported>'))}
++        ok(cert, 'linuxfr.org')
++        ok(cert, 'linuxfr.com')
++        # Not a "DNS" entry
++        fail(cert, '<unsupported>')
++        # When there is a subjectAltName, commonName isn't used
++        fail(cert, 'linuxfrz.org')
++
++        # A pristine real-world example
++        cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
++                'subject': ((('countryName', 'US'),),
++                            (('stateOrProvinceName', 'California'),),
++                            (('localityName', 'Mountain View'),),
++                            (('organizationName', 'Google Inc'),),
++                            (('commonName', 'mail.google.com'),))}
++        ok(cert, 'mail.google.com')
++        fail(cert, 'gmail.com')
++        # Only commonName is considered
++        fail(cert, 'California')
++
++        # Neither commonName nor subjectAltName
++        cert = {'notAfter': 'Dec 18 23:59:59 2011 GMT',
++                'subject': ((('countryName', 'US'),),
++                            (('stateOrProvinceName', 'California'),),
++                            (('localityName', 'Mountain View'),),
++                            (('organizationName', 'Google Inc'),))}
++        fail(cert, 'mail.google.com')
++
++        # No DNS entry in subjectAltName but a commonName
++        cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
++                'subject': ((('countryName', 'US'),),
++                            (('stateOrProvinceName', 'California'),),
++                            (('localityName', 'Mountain View'),),
++                            (('commonName', 'mail.google.com'),)),
++                'subjectAltName': (('othername', 'blabla'), )}
++        ok(cert, 'mail.google.com')
++
++        # No DNS entry subjectAltName and no commonName
++        cert = {'notAfter': 'Dec 18 23:59:59 2099 GMT',
++                'subject': ((('countryName', 'US'),),
++                            (('stateOrProvinceName', 'California'),),
++                            (('localityName', 'Mountain View'),),
++                            (('organizationName', 'Google Inc'),)),
++                'subjectAltName': (('othername', 'blabla'),)}
++        fail(cert, 'google.com')
++
++        # Empty cert / no cert
++        self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com')
++        self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com')
++
++        # Issue #17980: avoid denials of service by refusing more than one
++        # wildcard per fragment.
++        cert = {'subject': ((('commonName', 'a*b.com'),),)}
++        ok(cert, 'axxb.com')
++        cert = {'subject': ((('commonName', 'a*b.co*'),),)}
++        fail(cert, 'axxb.com')
++        cert = {'subject': ((('commonName', 'a*b*.com'),),)}
++        with self.assertRaises(ssl.CertificateError) as cm:
++            ssl.match_hostname(cert, 'axxbxxc.com')
++        self.assertIn("too many wildcards", str(cm.exception))
++
++    def test_server_side(self):
++        # server_hostname doesn't work for server sockets
++        ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++        with closing(socket.socket()) as sock:
++            self.assertRaises(ValueError, ctx.wrap_socket, sock, True,
++                              server_hostname="some.hostname")
++
++    def test_unknown_channel_binding(self):
++        # should raise ValueError for unknown type
++        s = socket.socket(socket.AF_INET)
++        with closing(ssl.wrap_socket(s)) as ss:
++            with self.assertRaises(ValueError):
++                ss.get_channel_binding("unknown-type")
++
++    @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
++                         "'tls-unique' channel binding not available")
++    def test_tls_unique_channel_binding(self):
++        # unconnected should return None for known type
++        s = socket.socket(socket.AF_INET)
++        with closing(ssl.wrap_socket(s)) as ss:
++            self.assertIsNone(ss.get_channel_binding("tls-unique"))
++        # the same for server-side
++        s = socket.socket(socket.AF_INET)
++        with closing(ssl.wrap_socket(s, server_side=True, certfile=CERTFILE)) as ss:
++            self.assertIsNone(ss.get_channel_binding("tls-unique"))
++
++    def test_get_default_verify_paths(self):
++        paths = ssl.get_default_verify_paths()
++        self.assertEqual(len(paths), 6)
++        self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
++
++        with support.EnvironmentVarGuard() as env:
++            env["SSL_CERT_DIR"] = CAPATH
++            env["SSL_CERT_FILE"] = CERTFILE
++            paths = ssl.get_default_verify_paths()
++            self.assertEqual(paths.cafile, CERTFILE)
++            self.assertEqual(paths.capath, CAPATH)
++
++    @unittest.skipUnless(sys.platform == "win32", "Windows specific")
++    def test_enum_certificates(self):
++        self.assertTrue(ssl.enum_certificates("CA"))
++        self.assertTrue(ssl.enum_certificates("ROOT"))
++
++        self.assertRaises(TypeError, ssl.enum_certificates)
++        self.assertRaises(WindowsError, ssl.enum_certificates, "")
++
++        trust_oids = set()
++        for storename in ("CA", "ROOT"):
++            store = ssl.enum_certificates(storename)
++            self.assertIsInstance(store, list)
++            for element in store:
++                self.assertIsInstance(element, tuple)
++                self.assertEqual(len(element), 3)
++                cert, enc, trust = element
++                self.assertIsInstance(cert, bytes)
++                self.assertIn(enc, {"x509_asn", "pkcs_7_asn"})
++                self.assertIsInstance(trust, (set, bool))
++                if isinstance(trust, set):
++                    trust_oids.update(trust)
++
++        serverAuth = "1.3.6.1.5.5.7.3.1"
++        self.assertIn(serverAuth, trust_oids)
++
++    @unittest.skipUnless(sys.platform == "win32", "Windows specific")
++    def test_enum_crls(self):
++        self.assertTrue(ssl.enum_crls("CA"))
++        self.assertRaises(TypeError, ssl.enum_crls)
++        self.assertRaises(WindowsError, ssl.enum_crls, "")
++
++        crls = ssl.enum_crls("CA")
++        self.assertIsInstance(crls, list)
++        for element in crls:
++            self.assertIsInstance(element, tuple)
++            self.assertEqual(len(element), 2)
++            self.assertIsInstance(element[0], bytes)
++            self.assertIn(element[1], {"x509_asn", "pkcs_7_asn"})
++
++
++    def test_asn1object(self):
++        expected = (129, 'serverAuth', 'TLS Web Server Authentication',
++                    '1.3.6.1.5.5.7.3.1')
++
++        val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
++        self.assertEqual(val, expected)
++        self.assertEqual(val.nid, 129)
++        self.assertEqual(val.shortname, 'serverAuth')
++        self.assertEqual(val.longname, 'TLS Web Server Authentication')
++        self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1')
++        self.assertIsInstance(val, ssl._ASN1Object)
++        self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
++
++        val = ssl._ASN1Object.fromnid(129)
++        self.assertEqual(val, expected)
++        self.assertIsInstance(val, ssl._ASN1Object)
++        self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1)
++        with self.assertRaisesRegexp(ValueError, "unknown NID 100000"):
++            ssl._ASN1Object.fromnid(100000)
++        for i in range(1000):
++            try:
++                obj = ssl._ASN1Object.fromnid(i)
++            except ValueError:
++                pass
++            else:
++                self.assertIsInstance(obj.nid, int)
++                self.assertIsInstance(obj.shortname, str)
++                self.assertIsInstance(obj.longname, str)
++                self.assertIsInstance(obj.oid, (str, type(None)))
++
++        val = ssl._ASN1Object.fromname('TLS Web Server Authentication')
++        self.assertEqual(val, expected)
++        self.assertIsInstance(val, ssl._ASN1Object)
++        self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected)
++        self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'),
++                         expected)
++        with self.assertRaisesRegexp(ValueError, "unknown object 'serverauth'"):
++            ssl._ASN1Object.fromname('serverauth')
++
++    def test_purpose_enum(self):
++        val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1')
++        self.assertIsInstance(ssl.Purpose.SERVER_AUTH, ssl._ASN1Object)
++        self.assertEqual(ssl.Purpose.SERVER_AUTH, val)
++        self.assertEqual(ssl.Purpose.SERVER_AUTH.nid, 129)
++        self.assertEqual(ssl.Purpose.SERVER_AUTH.shortname, 'serverAuth')
++        self.assertEqual(ssl.Purpose.SERVER_AUTH.oid,
++                              '1.3.6.1.5.5.7.3.1')
++
++        val = ssl._ASN1Object('1.3.6.1.5.5.7.3.2')
++        self.assertIsInstance(ssl.Purpose.CLIENT_AUTH, ssl._ASN1Object)
++        self.assertEqual(ssl.Purpose.CLIENT_AUTH, val)
++        self.assertEqual(ssl.Purpose.CLIENT_AUTH.nid, 130)
++        self.assertEqual(ssl.Purpose.CLIENT_AUTH.shortname, 'clientAuth')
++        self.assertEqual(ssl.Purpose.CLIENT_AUTH.oid,
++                              '1.3.6.1.5.5.7.3.2')
+ 
+     def test_unsupported_dtls(self):
+         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+@@ -242,42 +614,606 @@ 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 at 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 at cacert.org'),)),
++              'version': 3}])
++
++        with open(SVN_PYTHON_ORG_ROOT_CERT) as f:
++            pem = f.read()
++        der = ssl.PEM_cert_to_DER_cert(pem)
++        self.assertEqual(ctx.get_ca_certs(True), [der])
++
++    def test_load_default_certs(self):
++        ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++        ctx.load_default_certs()
++
++        ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++        ctx.load_default_certs(ssl.Purpose.SERVER_AUTH)
++        ctx.load_default_certs()
++
++        ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++        ctx.load_default_certs(ssl.Purpose.CLIENT_AUTH)
++
++        ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++        self.assertRaises(TypeError, ctx.load_default_certs, None)
++        self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
++
++    def test_create_default_context(self):
++        ctx = ssl.create_default_context()
++        self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
++        self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
++        self.assertTrue(ctx.check_hostname)
++        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
++        self.assertEqual(
++            ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
++            getattr(ssl, "OP_NO_COMPRESSION", 0),
++        )
++
++        with open(SIGNING_CA) as f:
++            cadata = f.read().decode("ascii")
++        ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
++                                         cadata=cadata)
++        self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
++        self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
++        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
++        self.assertEqual(
++            ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
++            getattr(ssl, "OP_NO_COMPRESSION", 0),
++        )
++
++        ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
++        self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
++        self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
++        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
++        self.assertEqual(
++            ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
++            getattr(ssl, "OP_NO_COMPRESSION", 0),
++        )
++        self.assertEqual(
++            ctx.options & getattr(ssl, "OP_SINGLE_DH_USE", 0),
++            getattr(ssl, "OP_SINGLE_DH_USE", 0),
++        )
++        self.assertEqual(
++            ctx.options & getattr(ssl, "OP_SINGLE_ECDH_USE", 0),
++            getattr(ssl, "OP_SINGLE_ECDH_USE", 0),
++        )
++
++    def test__create_stdlib_context(self):
++        ctx = ssl._create_stdlib_context()
++        self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
++        self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
++        self.assertFalse(ctx.check_hostname)
++        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
++
++        ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1)
++        self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
++        self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
++        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
++
++        ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1,
++                                         cert_reqs=ssl.CERT_REQUIRED,
++                                         check_hostname=True)
++        self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
++        self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
++        self.assertTrue(ctx.check_hostname)
++        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
++
++        ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH)
++        self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
++        self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
++        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
++
++    def test_check_hostname(self):
++        ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++        self.assertFalse(ctx.check_hostname)
++
++        # Requires CERT_REQUIRED or CERT_OPTIONAL
++        with self.assertRaises(ValueError):
++            ctx.check_hostname = True
++        ctx.verify_mode = ssl.CERT_REQUIRED
++        self.assertFalse(ctx.check_hostname)
++        ctx.check_hostname = True
++        self.assertTrue(ctx.check_hostname)
++
++        ctx.verify_mode = ssl.CERT_OPTIONAL
++        ctx.check_hostname = True
++        self.assertTrue(ctx.check_hostname)
++
++        # Cannot set CERT_NONE with check_hostname enabled
++        with self.assertRaises(ValueError):
++            ctx.verify_mode = ssl.CERT_NONE
++        ctx.check_hostname = False
++        self.assertFalse(ctx.check_hostname)
++
++
++class SSLErrorTests(unittest.TestCase):
++
++    def test_str(self):
++        # The str() of a SSLError doesn't include the errno
++        e = ssl.SSLError(1, "foo")
++        self.assertEqual(str(e), "foo")
++        self.assertEqual(e.errno, 1)
++        # Same for a subclass
++        e = ssl.SSLZeroReturnError(1, "foo")
++        self.assertEqual(str(e), "foo")
++        self.assertEqual(e.errno, 1)
++
++    def test_lib_reason(self):
++        # Test the library and reason attributes
++        ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++        with self.assertRaises(ssl.SSLError) as cm:
++            ctx.load_dh_params(CERTFILE)
++        self.assertEqual(cm.exception.library, 'PEM')
++        self.assertEqual(cm.exception.reason, 'NO_START_LINE')
++        s = str(cm.exception)
++        self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
++
++    def test_subclass(self):
++        # Check that the appropriate SSLError subclass is raised
++        # (this only tests one of them)
++        ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++        with closing(socket.socket()) as s:
++            s.bind(("127.0.0.1", 0))
++            s.listen(5)
++            c = socket.socket()
++            c.connect(s.getsockname())
++            c.setblocking(False)
++            with closing(ctx.wrap_socket(c, False, do_handshake_on_connect=False)) as c:
++                with self.assertRaises(ssl.SSLWantReadError) as cm:
++                    c.do_handshake()
++                s = str(cm.exception)
++                self.assertTrue(s.startswith("The operation did not complete (read)"), s)
++                # For compatibility
++                self.assertEqual(cm.exception.errno, ssl.SSL_ERROR_WANT_READ)
+ 
+ 
+ class NetworkedTests(unittest.TestCase):
+ 
+     def test_connect(self):
+-        with test_support.transient_internet("svn.python.org"):
++        with support.transient_internet("svn.python.org"):
+             s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+                                 cert_reqs=ssl.CERT_NONE)
+-            s.connect(("svn.python.org", 443))
+-            c = s.getpeercert()
+-            if c:
+-                self.fail("Peer cert %s shouldn't be here!")
+-            s.close()
+-
+-            # this should fail because we have no verification certs
+-            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+-                                cert_reqs=ssl.CERT_REQUIRED)
+             try:
+                 s.connect(("svn.python.org", 443))
+-            except ssl.SSLError:
+-                pass
++                self.assertEqual({}, s.getpeercert())
+             finally:
+                 s.close()
+ 
++            # this should fail because we have no verification certs
++            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
++                                cert_reqs=ssl.CERT_REQUIRED)
++            self.assertRaisesRegexp(ssl.SSLError, "certificate verify failed",
++                                   s.connect, ("svn.python.org", 443))
++            s.close()
++
+             # this should succeed because we specify the root cert
+             s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+                                 cert_reqs=ssl.CERT_REQUIRED,
+                                 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
+             try:
+                 s.connect(("svn.python.org", 443))
++                self.assertTrue(s.getpeercert())
+             finally:
+                 s.close()
+ 
+     def test_connect_ex(self):
+         # Issue #11326: check connect_ex() implementation
+-        with test_support.transient_internet("svn.python.org"):
++        with support.transient_internet("svn.python.org"):
+             s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+                                 cert_reqs=ssl.CERT_REQUIRED,
+                                 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
+@@ -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((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)
+ 
+-            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)
++    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,45 @@ 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)
++                    self.sslconn = self.server.context.wrap_socket(
++                        self.sock, server_side=True)
++                    self.server.selected_protocols.append(self.sslconn.selected_npn_protocol())
+                 except ssl.SSLError as e:
+                     # 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.
+                     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 +1586,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 +1643,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 +1698,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 +1720,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 +1736,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 +1753,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 +1770,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 +1801,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 +1819,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 +1835,74 @@ else:
+         """
+         server = ThreadedEchoServer(CERTFILE,
+                                     certreqs=ssl.CERT_REQUIRED,
+-                                    cacerts=CERTFILE, chatty=False)
++                                    cacerts=CERTFILE, chatty=False,
++                                    connectionchatty=False)
+         with server:
+             try:
+-                s = ssl.wrap_socket(socket.socket(),
+-                                    certfile=certfile,
+-                                    ssl_version=ssl.PROTOCOL_TLSv1)
+-                s.connect((HOST, server.port))
+-            except ssl.SSLError, x:
+-                if test_support.verbose:
+-                    sys.stdout.write("\nSSLError is %s\n" % x[1])
+-            except socket.error, x:
+-                if test_support.verbose:
+-                    sys.stdout.write("\nsocket.error is %s\n" % x[1])
++                with closing(socket.socket()) as sock:
++                    s = ssl.wrap_socket(sock,
++                                        certfile=certfile,
++                                        ssl_version=ssl.PROTOCOL_TLSv1)
++                    s.connect((HOST, server.port))
++            except ssl.SSLError as x:
++                if support.verbose:
++                    sys.stdout.write("\nSSLError is %s\n" % x.args[1])
++            except OSError as x:
++                if support.verbose:
++                    sys.stdout.write("\nOSError is %s\n" % x.args[1])
++            except OSError as x:
++                if x.errno != errno.ENOENT:
++                    raise
++                if support.verbose:
++                    sys.stdout.write("\OSError is %s\n" % str(x))
+             else:
+                 raise AssertionError("Use of invalid cert should have failed!")
+ 
+-    def server_params_test(certfile, protocol, certreqs, cacertsfile,
+-                           client_certfile, client_protocol=None, indata="FOO\n",
+-                           ciphers=None, chatty=True, connectionchatty=False,
+-                           wrap_accepting_socket=False):
++    def server_params_test(client_context, server_context, indata=b"FOO\n",
++                           chatty=True, connectionchatty=False, sni_name=None):
+         """
+         Launch a server, connect a client to it and try various reads
+         and writes.
+         """
+-        server = ThreadedEchoServer(certfile,
+-                                    certreqs=certreqs,
+-                                    ssl_version=protocol,
+-                                    cacerts=cacertsfile,
+-                                    ciphers=ciphers,
++        stats = {}
++        server = ThreadedEchoServer(context=server_context,
+                                     chatty=chatty,
+-                                    connectionchatty=connectionchatty,
+-                                    wrap_accepting_socket=wrap_accepting_socket)
++                                    connectionchatty=False)
+         with server:
+-            # try to connect
+-            if client_protocol is None:
+-                client_protocol = protocol
+-            s = ssl.wrap_socket(socket.socket(),
+-                                certfile=client_certfile,
+-                                ca_certs=cacertsfile,
+-                                ciphers=ciphers,
+-                                cert_reqs=certreqs,
+-                                ssl_version=client_protocol)
+-            s.connect((HOST, server.port))
+-            for arg in [indata, bytearray(indata), memoryview(indata)]:
+-                if connectionchatty:
+-                    if test_support.verbose:
+-                        sys.stdout.write(
+-                            " client:  sending %s...\n" % (repr(arg)))
+-                s.write(arg)
+-                outdata = s.read()
++            with closing(client_context.wrap_socket(socket.socket(),
++                    server_hostname=sni_name)) as s:
++                s.connect((HOST, server.port))
++                for arg in [indata, bytearray(indata), memoryview(indata)]:
++                    if connectionchatty:
++                        if support.verbose:
++                            sys.stdout.write(
++                                " client:  sending %r...\n" % indata)
++                    s.write(arg)
++                    outdata = s.read()
++                    if connectionchatty:
++                        if support.verbose:
++                            sys.stdout.write(" client:  read %r\n" % outdata)
++                    if outdata != indata.lower():
++                        raise AssertionError(
++                            "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
++                            % (outdata[:20], len(outdata),
++                               indata[:20].lower(), len(indata)))
++                s.write(b"over\n")
+                 if connectionchatty:
+-                    if test_support.verbose:
+-                        sys.stdout.write(" client:  read %s\n" % repr(outdata))
+-                if outdata != indata.lower():
+-                    raise AssertionError(
+-                        "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
+-                        % (outdata[:min(len(outdata),20)], len(outdata),
+-                           indata[:min(len(indata),20)].lower(), len(indata)))
+-            s.write("over\n")
+-            if connectionchatty:
+-                if test_support.verbose:
+-                    sys.stdout.write(" client:  closing connection.\n")
+-            s.close()
++                    if support.verbose:
++                        sys.stdout.write(" client:  closing connection.\n")
++                stats.update({
++                    'compression': s.compression(),
++                    'cipher': s.cipher(),
++                    'peercert': s.getpeercert(),
++                    'client_npn_protocol': s.selected_npn_protocol()
++                })
++                s.close()
++            stats['server_npn_protocols'] = server.selected_protocols
++        return stats
+ 
+-    def try_protocol_combo(server_protocol,
+-                           client_protocol,
+-                           expect_success,
+-                           certsreqs=None):
++    def try_protocol_combo(server_protocol, client_protocol, expect_success,
++                           certsreqs=None, server_options=0, client_options=0):
+         if certsreqs is None:
+             certsreqs = ssl.CERT_NONE
+         certtype = {
+@@ -922,19 +1910,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 +1952,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 +1994,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 +2099,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_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 +2189,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 +2228,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 +2288,109 @@ else:
+                 s = socket.socket()
+                 s.setblocking(1)
+                 s.connect((HOST, server.port))
+-                if test_support.verbose:
++                if support.verbose:
+                     sys.stdout.write("\n")
+                 for indata in msgs:
+-                    if test_support.verbose:
++                    if support.verbose:
+                         sys.stdout.write(
+-                            " client:  sending %s...\n" % repr(indata))
++                            " client:  sending %r...\n" % indata)
+                     if wrapped:
+                         conn.write(indata)
+                         outdata = conn.read()
+                     else:
+                         s.send(indata)
+                         outdata = s.recv(1024)
+-                    if (indata == "STARTTLS" and
+-                        outdata.strip().lower().startswith("ok")):
++                    msg = outdata.strip().lower()
++                    if indata == b"STARTTLS" and msg.startswith(b"ok"):
+                         # STARTTLS ok, switch to secure mode
+-                        if test_support.verbose:
++                        if support.verbose:
+                             sys.stdout.write(
+-                                " client:  read %s from server, starting TLS...\n"
+-                                % repr(outdata))
++                                " client:  read %r from server, starting TLS...\n"
++                                % msg)
+                         conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
+                         wrapped = True
+-                    elif (indata == "ENDTLS" and
+-                        outdata.strip().lower().startswith("ok")):
++                    elif indata == b"ENDTLS" and msg.startswith(b"ok"):
+                         # ENDTLS ok, switch back to clear text
+-                        if test_support.verbose:
++                        if support.verbose:
+                             sys.stdout.write(
+-                                " client:  read %s from server, ending TLS...\n"
+-                                % repr(outdata))
++                                " client:  read %r from server, ending TLS...\n"
++                                % msg)
+                         s = conn.unwrap()
+                         wrapped = False
+                     else:
+-                        if test_support.verbose:
++                        if support.verbose:
+                             sys.stdout.write(
+-                                " client:  read %s from server\n" % repr(outdata))
+-                if test_support.verbose:
++                                " client:  read %r from server\n" % msg)
++                if support.verbose:
+                     sys.stdout.write(" client:  closing connection.\n")
+                 if wrapped:
+-                    conn.write("over\n")
++                    conn.write(b"over\n")
+                 else:
+-                    s.send("over\n")
+-                s.close()
++                    s.send(b"over\n")
++                if wrapped:
++                    conn.close()
++                else:
++                    s.close()
+ 
+         def test_socketserver(self):
+             """Using a SocketServer to create and manage SSL connections."""
+-            server = SocketServerHTTPSServer(CERTFILE)
+-            flag = threading.Event()
+-            server.start(flag)
+-            # wait for it to start
+-            flag.wait()
++            server = make_https_server(self, certfile=CERTFILE)
+             # try to connect
++            if support.verbose:
++                sys.stdout.write('\n')
++            with open(CERTFILE, 'rb') as f:
++                d1 = f.read()
++            d2 = ''
++            # now fetch the same data from the HTTPS server
++            url = 'https://%s:%d/%s' % (
++                HOST, server.port, os.path.split(CERTFILE)[1])
++            f = urllib.urlopen(url)
+             try:
+-                if test_support.verbose:
+-                    sys.stdout.write('\n')
+-                with open(CERTFILE, 'rb') as f:
+-                    d1 = f.read()
+-                d2 = ''
+-                # now fetch the same data from the HTTPS server
+-                url = 'https://127.0.0.1:%d/%s' % (
+-                    server.port, os.path.split(CERTFILE)[1])
+-                with test_support.check_py3k_warnings():
+-                    f = urllib.urlopen(url)
+                 dlen = f.info().getheader("content-length")
+                 if dlen and (int(dlen) > 0):
+                     d2 = f.read(int(dlen))
+-                    if test_support.verbose:
++                    if support.verbose:
+                         sys.stdout.write(
+                             " client: read %d bytes from remote server '%s'\n"
+                             % (len(d2), server))
+-                f.close()
+-                self.assertEqual(d1, d2)
+             finally:
+-                server.stop()
+-                server.join()
+-
+-        def test_wrapped_accept(self):
+-            """Check the accept() method on SSL sockets."""
+-            if test_support.verbose:
+-                sys.stdout.write("\n")
+-            server_params_test(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED,
+-                               CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23,
+-                               chatty=True, connectionchatty=True,
+-                               wrap_accepting_socket=True)
++                f.close()
++            self.assertEqual(d1, d2)
+ 
+         def test_asyncore_server(self):
+             """Check the example asyncore integration."""
+             indata = "TEST MESSAGE of mixed case\n"
+ 
+-            if test_support.verbose:
++            if support.verbose:
+                 sys.stdout.write("\n")
++
++            indata = b"FOO\n"
+             server = AsyncoreEchoServer(CERTFILE)
+             with server:
+                 s = ssl.wrap_socket(socket.socket())
+                 s.connect(('127.0.0.1', server.port))
+-                if test_support.verbose:
++                if support.verbose:
+                     sys.stdout.write(
+-                        " client:  sending %s...\n" % (repr(indata)))
++                        " client:  sending %r...\n" % indata)
+                 s.write(indata)
+                 outdata = s.read()
+-                if test_support.verbose:
+-                    sys.stdout.write(" client:  read %s\n" % repr(outdata))
++                if support.verbose:
++                    sys.stdout.write(" client:  read %r\n" % outdata)
+                 if outdata != indata.lower():
+                     self.fail(
+-                        "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
+-                        % (outdata[:min(len(outdata),20)], len(outdata),
+-                           indata[:min(len(indata),20)].lower(), len(indata)))
+-                s.write("over\n")
+-                if test_support.verbose:
++                        "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
++                        % (outdata[:20], len(outdata),
++                           indata[:20].lower(), len(indata)))
++                s.write(b"over\n")
++                if support.verbose:
+                     sys.stdout.write(" client:  closing connection.\n")
+                 s.close()
++                if support.verbose:
++                    sys.stdout.write(" client:  connection closed.\n")
+ 
+         def test_recv_send(self):
+             """Test recv(), send() and friends."""
+-            if test_support.verbose:
++            if support.verbose:
+                 sys.stdout.write("\n")
+ 
+             server = ThreadedEchoServer(CERTFILE,
+@@ -1251,12 +2409,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 +2433,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 +2513,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 +2532,8 @@ else:
+                     c.close()
+                 try:
+                     c = socket.socket(socket.AF_INET)
+-                    c.settimeout(0.2)
+                     c = ssl.wrap_socket(c)
++                    c.settimeout(0.2)
+                     # Will attempt handshake and time out
+                     self.assertRaisesRegexp(ssl.SSLError, "timed out",
+                                             c.connect, (host, port))
+@@ -1384,59 +2544,384 @@ else:
+                 t.join()
+                 server.close()
+ 
++        def test_server_accept(self):
++            # Issue #16357: accept() on a SSLSocket created through
++            # SSLContext.wrap_socket().
++            context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++            context.verify_mode = ssl.CERT_REQUIRED
++            context.load_verify_locations(CERTFILE)
++            context.load_cert_chain(CERTFILE)
++            server = socket.socket(socket.AF_INET)
++            host = "127.0.0.1"
++            port = support.bind_port(server)
++            server = context.wrap_socket(server, server_side=True)
++
++            evt = threading.Event()
++            remote = [None]
++            peer = [None]
++            def serve():
++                server.listen(5)
++                # Block on the accept and wait on the connection to close.
++                evt.set()
++                remote[0], peer[0] = server.accept()
++                remote[0].recv(1)
++
++            t = threading.Thread(target=serve)
++            t.start()
++            # Client wait until server setup and perform a connect.
++            evt.wait()
++            client = context.wrap_socket(socket.socket())
++            client.connect((host, port))
++            client_addr = client.getsockname()
++            client.close()
++            t.join()
++            remote[0].close()
++            server.close()
++            # Sanity checks.
++            self.assertIsInstance(remote[0], ssl.SSLSocket)
++            self.assertEqual(peer[0], client_addr)
++
++        def test_getpeercert_enotconn(self):
++            context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++            with closing(context.wrap_socket(socket.socket())) as sock:
++                with self.assertRaises(socket.error) as cm:
++                    sock.getpeercert()
++                self.assertEqual(cm.exception.errno, errno.ENOTCONN)
++
++        def test_do_handshake_enotconn(self):
++            context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++            with closing(context.wrap_socket(socket.socket())) as sock:
++                with self.assertRaises(socket.error) as cm:
++                    sock.do_handshake()
++                self.assertEqual(cm.exception.errno, errno.ENOTCONN)
++
+         def test_default_ciphers(self):
++            context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++            try:
++                # Force a set of weak ciphers on our client context
++                context.set_ciphers("DES")
++            except ssl.SSLError:
++                self.skipTest("no DES cipher available")
+             with ThreadedEchoServer(CERTFILE,
+                                     ssl_version=ssl.PROTOCOL_SSLv23,
+                                     chatty=False) as server:
+-                sock = socket.socket()
+-                try:
+-                    # Force a set of weak ciphers on our client socket
+-                    try:
+-                        s = ssl.wrap_socket(sock,
+-                                            ssl_version=ssl.PROTOCOL_SSLv23,
+-                                            ciphers="DES")
+-                    except ssl.SSLError:
+-                        self.skipTest("no DES cipher available")
+-                    with self.assertRaises((OSError, ssl.SSLError)):
++                with closing(context.wrap_socket(socket.socket())) as s:
++                    with self.assertRaises(ssl.SSLError):
+                         s.connect((HOST, server.port))
+-                finally:
+-                    sock.close()
+             self.assertIn("no shared cipher", str(server.conn_errors[0]))
+ 
++        @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
++        def test_default_ecdh_curve(self):
++            # Issue #21015: elliptic curve-based Diffie Hellman key exchange
++            # should be enabled by default on SSL contexts.
++            context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++            context.load_cert_chain(CERTFILE)
++            # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
++            # explicitly using the 'ECCdraft' cipher alias.  Otherwise,
++            # our default cipher list should prefer ECDH-based ciphers
++            # automatically.
++            if ssl.OPENSSL_VERSION_INFO < (1, 0, 0):
++                context.set_ciphers("ECCdraft:ECDH")
++            with ThreadedEchoServer(context=context) as server:
++                with closing(context.wrap_socket(socket.socket())) as s:
++                    s.connect((HOST, server.port))
++                    self.assertIn("ECDH", s.cipher()[0])
++
++        @unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
++                             "'tls-unique' channel binding not available")
++        def test_tls_unique_channel_binding(self):
++            """Test tls-unique channel binding."""
++            if support.verbose:
++                sys.stdout.write("\n")
++
++            server = ThreadedEchoServer(CERTFILE,
++                                        certreqs=ssl.CERT_NONE,
++                                        ssl_version=ssl.PROTOCOL_TLSv1,
++                                        cacerts=CERTFILE,
++                                        chatty=True,
++                                        connectionchatty=False)
++            with server:
++                s = ssl.wrap_socket(socket.socket(),
++                                    server_side=False,
++                                    certfile=CERTFILE,
++                                    ca_certs=CERTFILE,
++                                    cert_reqs=ssl.CERT_NONE,
++                                    ssl_version=ssl.PROTOCOL_TLSv1)
++                s.connect((HOST, server.port))
++                # get the data
++                cb_data = s.get_channel_binding("tls-unique")
++                if support.verbose:
++                    sys.stdout.write(" got channel binding data: {0!r}\n"
++                                     .format(cb_data))
++
++                # check if it is sane
++                self.assertIsNotNone(cb_data)
++                self.assertEqual(len(cb_data), 12) # True for TLSv1
++
++                # and compare with the peers version
++                s.write(b"CB tls-unique\n")
++                peer_data_repr = s.read().strip()
++                self.assertEqual(peer_data_repr,
++                                 repr(cb_data).encode("us-ascii"))
++                s.close()
++
++                # now, again
++                s = ssl.wrap_socket(socket.socket(),
++                                    server_side=False,
++                                    certfile=CERTFILE,
++                                    ca_certs=CERTFILE,
++                                    cert_reqs=ssl.CERT_NONE,
++                                    ssl_version=ssl.PROTOCOL_TLSv1)
++                s.connect((HOST, server.port))
++                new_cb_data = s.get_channel_binding("tls-unique")
++                if support.verbose:
++                    sys.stdout.write(" got another channel binding data: {0!r}\n"
++                                     .format(new_cb_data))
++                # is it really unique
++                self.assertNotEqual(cb_data, new_cb_data)
++                self.assertIsNotNone(cb_data)
++                self.assertEqual(len(cb_data), 12) # True for TLSv1
++                s.write(b"CB tls-unique\n")
++                peer_data_repr = s.read().strip()
++                self.assertEqual(peer_data_repr,
++                                 repr(new_cb_data).encode("us-ascii"))
++                s.close()
++
++        def test_compression(self):
++            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++            context.load_cert_chain(CERTFILE)
++            stats = server_params_test(context, context,
++                                       chatty=True, connectionchatty=True)
++            if support.verbose:
++                sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
++            self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
++
++        @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
++                             "ssl.OP_NO_COMPRESSION needed for this test")
++        def test_compression_disabled(self):
++            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++            context.load_cert_chain(CERTFILE)
++            context.options |= ssl.OP_NO_COMPRESSION
++            stats = server_params_test(context, context,
++                                       chatty=True, connectionchatty=True)
++            self.assertIs(stats['compression'], None)
++
++        def test_dh_params(self):
++            # Check we can get a connection with ephemeral Diffie-Hellman
++            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++            context.load_cert_chain(CERTFILE)
++            context.load_dh_params(DHFILE)
++            context.set_ciphers("kEDH")
++            stats = server_params_test(context, context,
++                                       chatty=True, connectionchatty=True)
++            cipher = stats["cipher"][0]
++            parts = cipher.split("-")
++            if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
++                self.fail("Non-DH cipher: " + cipher[0])
++
++        def test_selected_npn_protocol(self):
++            # selected_npn_protocol() is None unless NPN is used
++            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++            context.load_cert_chain(CERTFILE)
++            stats = server_params_test(context, context,
++                                       chatty=True, connectionchatty=True)
++            self.assertIs(stats['client_npn_protocol'], None)
++
++        @unittest.skipUnless(ssl.HAS_NPN, "NPN support needed for this test")
++        def test_npn_protocols(self):
++            server_protocols = ['http/1.1', 'spdy/2']
++            protocol_tests = [
++                (['http/1.1', 'spdy/2'], 'http/1.1'),
++                (['spdy/2', 'http/1.1'], 'http/1.1'),
++                (['spdy/2', 'test'], 'spdy/2'),
++                (['abc', 'def'], 'abc')
++            ]
++            for client_protocols, expected in protocol_tests:
++                server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++                server_context.load_cert_chain(CERTFILE)
++                server_context.set_npn_protocols(server_protocols)
++                client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++                client_context.load_cert_chain(CERTFILE)
++                client_context.set_npn_protocols(client_protocols)
++                stats = server_params_test(client_context, server_context,
++                                           chatty=True, connectionchatty=True)
++
++                msg = "failed trying %s (s) and %s (c).\n" \
++                      "was expecting %s, but got %%s from the %%s" \
++                          % (str(server_protocols), str(client_protocols),
++                             str(expected))
++                client_result = stats['client_npn_protocol']
++                self.assertEqual(client_result, expected, msg % (client_result, "client"))
++                server_result = stats['server_npn_protocols'][-1] \
++                    if len(stats['server_npn_protocols']) else 'nothing'
++                self.assertEqual(server_result, expected, msg % (server_result, "server"))
++
++        def sni_contexts(self):
++            server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++            server_context.load_cert_chain(SIGNED_CERTFILE)
++            other_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++            other_context.load_cert_chain(SIGNED_CERTFILE2)
++            client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
++            client_context.verify_mode = ssl.CERT_REQUIRED
++            client_context.load_verify_locations(SIGNING_CA)
++            return server_context, other_context, client_context
++
++        def check_common_name(self, stats, name):
++            cert = stats['peercert']
++            self.assertIn((('commonName', name),), cert['subject'])
++
++        @needs_sni
++        def test_sni_callback(self):
++            calls = []
++            server_context, other_context, client_context = self.sni_contexts()
++
++            def servername_cb(ssl_sock, server_name, initial_context):
++                calls.append((server_name, initial_context))
++                if server_name is not None:
++                    ssl_sock.context = other_context
++            server_context.set_servername_callback(servername_cb)
++
++            stats = server_params_test(client_context, server_context,
++                                       chatty=True,
++                                       sni_name='supermessage')
++            # The hostname was fetched properly, and the certificate was
++            # changed for the connection.
++            self.assertEqual(calls, [("supermessage", server_context)])
++            # CERTFILE4 was selected
++            self.check_common_name(stats, 'fakehostname')
++
++            calls = []
++            # The callback is called with server_name=None
++            stats = server_params_test(client_context, server_context,
++                                       chatty=True,
++                                       sni_name=None)
++            self.assertEqual(calls, [(None, server_context)])
++            self.check_common_name(stats, 'localhost')
++
++            # Check disabling the callback
++            calls = []
++            server_context.set_servername_callback(None)
++
++            stats = server_params_test(client_context, server_context,
++                                       chatty=True,
++                                       sni_name='notfunny')
++            # Certificate didn't change
++            self.check_common_name(stats, 'localhost')
++            self.assertEqual(calls, [])
++
++        @needs_sni
++        def test_sni_callback_alert(self):
++            # Returning a TLS alert is reflected to the connecting client
++            server_context, other_context, client_context = self.sni_contexts()
++
++            def cb_returning_alert(ssl_sock, server_name, initial_context):
++                return ssl.ALERT_DESCRIPTION_ACCESS_DENIED
++            server_context.set_servername_callback(cb_returning_alert)
++
++            with self.assertRaises(ssl.SSLError) as cm:
++                stats = server_params_test(client_context, server_context,
++                                           chatty=False,
++                                           sni_name='supermessage')
++            self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_ACCESS_DENIED')
++
++        @needs_sni
++        def test_sni_callback_raising(self):
++            # Raising fails the connection with a TLS handshake failure alert.
++            server_context, other_context, client_context = self.sni_contexts()
++
++            def cb_raising(ssl_sock, server_name, initial_context):
++                1/0
++            server_context.set_servername_callback(cb_raising)
++
++            with self.assertRaises(ssl.SSLError) as cm, \
++                 support.captured_stderr() as stderr:
++                stats = server_params_test(client_context, server_context,
++                                           chatty=False,
++                                           sni_name='supermessage')
++            self.assertEqual(cm.exception.reason, 'SSLV3_ALERT_HANDSHAKE_FAILURE')
++            self.assertIn("ZeroDivisionError", stderr.getvalue())
++
++        @needs_sni
++        def test_sni_callback_wrong_return_type(self):
++            # Returning the wrong return type terminates the TLS connection
++            # with an internal error alert.
++            server_context, other_context, client_context = self.sni_contexts()
++
++            def cb_wrong_return_type(ssl_sock, server_name, initial_context):
++                return "foo"
++            server_context.set_servername_callback(cb_wrong_return_type)
++
++            with self.assertRaises(ssl.SSLError) as cm, \
++                 support.captured_stderr() as stderr:
++                stats = server_params_test(client_context, server_context,
++                                           chatty=False,
++                                           sni_name='supermessage')
++            self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
++            self.assertIn("TypeError", stderr.getvalue())
++
++        def test_read_write_after_close_raises_valuerror(self):
++            context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++            context.verify_mode = ssl.CERT_REQUIRED
++            context.load_verify_locations(CERTFILE)
++            context.load_cert_chain(CERTFILE)
++            server = ThreadedEchoServer(context=context, chatty=False)
++
++            with server:
++                s = context.wrap_socket(socket.socket())
++                s.connect((HOST, server.port))
++                s.close()
++
++                self.assertRaises(ValueError, s.read, 1024)
++                self.assertRaises(ValueError, s.write, b'hello')
++
+ 
+ def test_main(verbose=False):
+-    global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, NOKIACERT, NULLBYTECERT
+-    CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
+-                            "keycert.pem")
+-    SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
+-        os.path.dirname(__file__) or os.curdir,
+-        "https_svn_python_org_root.pem")
+-    NOKIACERT = os.path.join(os.path.dirname(__file__) or os.curdir,
+-                             "nokia.pem")
+-    NULLBYTECERT = os.path.join(os.path.dirname(__file__) or os.curdir,
+-                                "nullbytecert.pem")
+-
+-    if (not os.path.exists(CERTFILE) or
+-        not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT) or
+-        not os.path.exists(NOKIACERT) or
+-        not os.path.exists(NULLBYTECERT)):
+-        raise test_support.TestFailed("Can't read certificate files!")
+-
+-    tests = [BasicTests, BasicSocketTests]
+-
+-    if test_support.is_resource_enabled('network'):
++    if support.verbose:
++        plats = {
++            'Linux': platform.linux_distribution,
++            'Mac': platform.mac_ver,
++            'Windows': platform.win32_ver,
++        }
++        for name, func in plats.items():
++            plat = func()
++            if plat and plat[0]:
++                plat = '%s %r' % (name, plat)
++                break
++        else:
++            plat = repr(platform.platform())
++        print("test_ssl: testing with %r %r" %
++            (ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO))
++        print("          under %s" % plat)
++        print("          HAS_SNI = %r" % ssl.HAS_SNI)
++        print("          OP_ALL = 0x%8x" % ssl.OP_ALL)
++        try:
++            print("          OP_NO_TLSv1_1 = 0x%8x" % ssl.OP_NO_TLSv1_1)
++        except AttributeError:
++            pass
++
++    for filename in [
++        CERTFILE, SVN_PYTHON_ORG_ROOT_CERT, BYTES_CERTFILE,
++        ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
++        SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
++        BADCERT, BADKEY, EMPTYCERT]:
++        if not os.path.exists(filename):
++            raise support.TestFailed("Can't read certificate file %r" % filename)
++
++    tests = [ContextTests, BasicSocketTests, SSLErrorTests]
++
++    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
+index 695ac95..c1c8799 100644
+--- a/Lib/test/test_support.py
++++ b/Lib/test/test_support.py
+@@ -39,7 +39,7 @@ __all__ = ["Error", "TestFailed", "ResourceDenied", "import_module",
+            "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
+index bcd83bf..80a0926 100644
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -930,8 +930,8 @@ PLATMACDIRS= plat-mac plat-mac/Carbon plat-mac/lib-scriptpackages \
+ 	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
+index 752b033..493eeea 100644
+--- 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 <poll.h>
++#elif defined(HAVE_SYS_POLL_H)
++#include <sys/poll.h>
++#endif
++
++/* Include OpenSSL header files */
++#include "openssl/rsa.h"
++#include "openssl/crypto.h"
++#include "openssl/x509.h"
++#include "openssl/x509v3.h"
++#include "openssl/pem.h"
++#include "openssl/ssl.h"
++#include "openssl/err.h"
++#include "openssl/rand.h"
++
++/* SSL error object */
++static PyObject *PySSLErrorObject;
++static PyObject *PySSLZeroReturnErrorObject;
++static PyObject *PySSLWantReadErrorObject;
++static PyObject *PySSLWantWriteErrorObject;
++static PyObject *PySSLSyscallErrorObject;
++static PyObject *PySSLEOFErrorObject;
++
++/* Error mappings */
++static PyObject *err_codes_to_names;
++static PyObject *err_names_to_codes;
++static PyObject *lib_codes_to_names;
++
++struct py_ssl_error_code {
++    const char *mnemonic;
++    int library, reason;
++};
++struct py_ssl_library_code {
++    const char *library;
++    int code;
++};
++
++/* Include generated data (error codes) */
++#include "_ssl_data.h"
++
++/* Openssl comes with TLSv1.1 and TLSv1.2 between 1.0.0h and 1.0.1
++    http://www.openssl.org/news/changelog.html
++ */
++#if OPENSSL_VERSION_NUMBER >= 0x10001000L
++# define HAVE_TLSv1_2 1
++#else
++# define HAVE_TLSv1_2 0
++#endif
++
++/* SNI support (client- and server-side) appeared in OpenSSL 1.0.0 and 0.9.8f
++ * This includes the SSL_set_SSL_CTX() function.
++ */
++#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
++# define HAVE_SNI 1
++#else
++# define HAVE_SNI 0
++#endif
++
+ enum py_ssl_error {
+     /* these mirror ssl.h */
+     PY_SSL_ERROR_NONE,
+@@ -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,35 +133,17 @@ enum py_ssl_cert_requirements {
+ };
+ 
+ enum py_ssl_version {
+-#ifndef OPENSSL_NO_SSL2
+     PY_SSL_VERSION_SSL2,
+-#endif
+     PY_SSL_VERSION_SSL3=1,
+     PY_SSL_VERSION_SSL23,
++#if HAVE_TLSv1_2
++    PY_SSL_VERSION_TLS1,
++    PY_SSL_VERSION_TLS1_1,
++    PY_SSL_VERSION_TLS1_2
++#else
+     PY_SSL_VERSION_TLS1
+-};
+-
+-/* Include symbols from _socket module */
+-#include "socketmodule.h"
+-
+-#if defined(HAVE_POLL_H)
+-#include <poll.h>
+-#elif defined(HAVE_SYS_POLL_H)
+-#include <sys/poll.h>
+ #endif
+-
+-/* Include OpenSSL header files */
+-#include "openssl/rsa.h"
+-#include "openssl/crypto.h"
+-#include "openssl/x509.h"
+-#include "openssl/x509v3.h"
+-#include "openssl/pem.h"
+-#include "openssl/ssl.h"
+-#include "openssl/err.h"
+-#include "openssl/rand.h"
+-
+-/* SSL error object */
+-static PyObject *PySSLErrorObject;
++};
+ 
+ #ifdef WITH_THREAD
+ 
+@@ -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
++    SSL_CTX *ctx;
++#ifdef OPENSSL_NPN_NEGOTIATED
++    char *npn_protocols;
++    int npn_protocols_len;
++#endif
++#ifndef OPENSSL_NO_TLSEXT
++    PyObject *set_hostname;
++#endif
++    int check_hostname;
++} PySSLContext;
++
+ typedef struct {
+     PyObject_HEAD
+-    PySocketSockObject *Socket;         /* Socket on which we're layered */
+-    SSL_CTX*            ctx;
+-    SSL*                ssl;
+-    X509*               peer_cert;
+-    char                server[X509_NAME_MAXLEN];
+-    char                issuer[X509_NAME_MAXLEN];
+-    int                 shutdown_seen_zero;
+-
+-} PySSLObject;
+-
+-static PyTypeObject PySSL_Type;
+-static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args);
+-static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args);
++    PySocketSockObject *Socket;
++    PyObject *ssl_sock;
++    SSL *ssl;
++    PySSLContext *ctx; /* weakref to SSL context */
++    X509 *peer_cert;
++    char shutdown_seen_zero;
++    char handshake_done;
++    enum py_ssl_server_or_client socket_type;
++} PySSLSocket;
++
++static PyTypeObject PySSLContext_Type;
++static PyTypeObject PySSLSocket_Type;
++
++static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args);
++static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args);
+ static int check_socket_and_wait_for_timeout(PySocketSockObject *s,
+                                              int writing);
+-static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args);
+-static PyObject *PySSL_cipher(PySSLObject *self);
++static PyObject *PySSL_peercert(PySSLSocket *self, PyObject *args);
++static PyObject *PySSL_cipher(PySSLSocket *self);
+ 
+-#define PySSLObject_Check(v)    (Py_TYPE(v) == &PySSL_Type)
++#define PySSLContext_Check(v)   (Py_TYPE(v) == &PySSLContext_Type)
++#define PySSLSocket_Check(v)    (Py_TYPE(v) == &PySSLSocket_Type)
+ 
+ typedef enum {
+     SOCKET_IS_NONBLOCKING,
+@@ -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, char *filename, int lineno)
+             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;
++    PySSLSocket *self;
++    SSL_CTX *ctx = sslctx->ctx;
++    long mode;
+ 
+-    self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
++    self = PyObject_New(PySSLSocket, &PySSLSocket_Type);
+     if (self == NULL)
+         return NULL;
+-    memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN);
+-    memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN);
++
+     self->peer_cert = NULL;
+     self->ssl = NULL;
+-    self->ctx = NULL;
+     self->Socket = NULL;
++    self->ssl_sock = NULL;
++    self->ctx = sslctx;
+     self->shutdown_seen_zero = 0;
++    self->handshake_done = 0;
++    Py_INCREF(sslctx);
+ 
+     /* Make sure the SSL error state is initialized */
+     (void) ERR_get_state();
+     ERR_clear_error();
+ 
+-    if ((key_file && !cert_file) || (!key_file && cert_file)) {
+-        errstr = ERRSTR("Both the key & certificate files "
+-                        "must be specified");
+-        goto fail;
+-    }
+-
+-    if ((socket_type == PY_SSL_SERVER) &&
+-        ((key_file == NULL) || (cert_file == NULL))) {
+-        errstr = ERRSTR("Both the key & certificate files "
+-                        "must be specified for server-side operation");
+-        goto fail;
+-    }
+-
+-    PySSL_BEGIN_ALLOW_THREADS
+-    if (proto_version == PY_SSL_VERSION_TLS1)
+-        self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */
+-    else if (proto_version == PY_SSL_VERSION_SSL3)
+-        self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */
+-#ifndef OPENSSL_NO_SSL2
+-    else if (proto_version == PY_SSL_VERSION_SSL2)
+-        self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */
+-#endif
+-    else if (proto_version == PY_SSL_VERSION_SSL23)
+-        self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */
+-    PySSL_END_ALLOW_THREADS
+-
+-    if (self->ctx == NULL) {
+-        errstr = ERRSTR("Invalid SSL protocol variant specified.");
+-        goto fail;
+-    }
+-
+-    if (ciphers != NULL) {
+-        ret = SSL_CTX_set_cipher_list(self->ctx, ciphers);
+-        if (ret == 0) {
+-            errstr = ERRSTR("No cipher can be selected.");
+-            goto fail;
+-        }
+-    }
+-
+-    if (certreq != PY_SSL_CERT_NONE) {
+-        if (cacerts_file == NULL) {
+-            errstr = ERRSTR("No root certificates specified for "
+-                            "verification of other-side certificates.");
+-            goto fail;
+-        } else {
+-            PySSL_BEGIN_ALLOW_THREADS
+-            ret = SSL_CTX_load_verify_locations(self->ctx,
+-                                                cacerts_file,
+-                                                NULL);
+-            PySSL_END_ALLOW_THREADS
+-            if (ret != 1) {
+-                _setSSLError(NULL, 0, __FILE__, __LINE__);
+-                goto fail;
+-            }
+-        }
+-    }
+-    if (key_file) {
+-        PySSL_BEGIN_ALLOW_THREADS
+-        ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
+-                                          SSL_FILETYPE_PEM);
+-        PySSL_END_ALLOW_THREADS
+-        if (ret != 1) {
+-            _setSSLError(NULL, ret, __FILE__, __LINE__);
+-            goto fail;
+-        }
+-
+-        PySSL_BEGIN_ALLOW_THREADS
+-        ret = SSL_CTX_use_certificate_chain_file(self->ctx,
+-                                                 cert_file);
+-        PySSL_END_ALLOW_THREADS
+-        if (ret != 1) {
+-            /*
+-            fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
+-                ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
+-                */
+-            if (ERR_peek_last_error() != 0) {
+-                _setSSLError(NULL, ret, __FILE__, __LINE__);
+-                goto fail;
+-            }
+-        }
+-    }
+-
+-    /* ssl compatibility */
+-    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 */
++    self->ssl = SSL_new(ctx);
+     PySSL_END_ALLOW_THREADS
+-    SSL_set_fd(self->ssl, Sock->sock_fd);       /* Set the socket for SSL */
++    SSL_set_app_data(self->ssl,self);
++    SSL_set_fd(self->ssl, Py_SAFE_DOWNCAST(sock->sock_fd, SOCKET_T, int));
++    mode = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
+ #ifdef SSL_MODE_AUTO_RETRY
+-    SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY);
++    mode |= SSL_MODE_AUTO_RETRY;
++#endif
++    SSL_set_mode(self->ssl, mode);
++
++#if HAVE_SNI
++    if (server_hostname != NULL)
++        SSL_set_tlsext_host_name(self->ssl, server_hostname);
+ #endif
+ 
+     /* If the socket is in non-blocking mode or timeout mode, set the BIO
+      * to non-blocking mode (blocking is the default)
+      */
+-    if (Sock->sock_timeout >= 0.0) {
+-        /* Set both the read and write BIO's to non-blocking mode */
++    if (sock->sock_timeout >= 0.0) {
+         BIO_set_nbio(SSL_get_rbio(self->ssl), 1);
+         BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
+     }
+@@ -411,65 +514,31 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
+         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);
+-    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))
++    self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL);
++    if (self->ssl_sock == NULL) {
++        Py_DECREF(self);
+         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);
++    }
++    return self;
+ }
+ 
+-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(PySSLObject *self)
+         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 @@ _create_tuple_for_X509_NAME (X509_NAME *xname)
+         /*
+         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 @@ _get_peer_alt_names (X509 *certificate) {
+         /* now decode the altName */
+         ext = X509_get_ext(certificate, i);
+         if(!(method = X509V3_EXT_get(ext))) {
+-            PyErr_SetString(PySSLErrorObject,
+-                            ERRSTR("No method for internalizing subjectAltName!"));
++            PyErr_SetString
++              (PySSLErrorObject,
++               ERRSTR("No method for internalizing subjectAltName!"));
+             goto fail;
+         }
+ 
+         p = ext->value->data;
+         if (method->it)
+-            names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL,
+-                                                    &p,
+-                                                    ext->value->length,
+-                                                    ASN1_ITEM_ptr(method->it)));
++            names = (GENERAL_NAMES*)
++              (ASN1_item_d2i(NULL,
++                             &p,
++                             ext->value->length,
++                             ASN1_ITEM_ptr(method->it)));
+         else
+-            names = (GENERAL_NAMES*) (method->d2i(NULL,
+-                                                  &p,
+-                                                  ext->value->length));
++            names = (GENERAL_NAMES*)
++              (method->d2i(NULL,
++                           &p,
++                           ext->value->length));
+ 
+         for(j = 0; j < sk_GENERAL_NAME_num(names); j++) {
+             /* get a rendering of each name in the set of names */
+@@ -888,94 +948,212 @@ _get_peer_alt_names (X509 *certificate) {
+ }
+ 
+ static PyObject *
+-_decode_certificate (X509 *certificate, int verbose) {
+-
+-    PyObject *retval = NULL;
+-    BIO *biobuf = NULL;
+-    PyObject *peer;
+-    PyObject *peer_alt_names = NULL;
+-    PyObject *issuer;
+-    PyObject *version;
+-    PyObject *sn_obj;
+-    ASN1_INTEGER *serialNumber;
+-    char buf[2048];
+-    int len;
+-    ASN1_TIME *notBefore, *notAfter;
+-    PyObject *pnotBefore, *pnotAfter;
+-
+-    retval = PyDict_New();
+-    if (retval == NULL)
+-        return NULL;
++_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;
++    }
+ 
+-    peer = _create_tuple_for_X509_NAME(
+-        X509_get_subject_name(certificate));
+-    if (peer == NULL)
+-        goto fail0;
+-    if (PyDict_SetItemString(retval, (const char *) "subject", peer) < 0) {
+-        Py_DECREF(peer);
+-        goto fail0;
++    if ((lst = PyList_New(0)) == NULL) {
++        goto fail;
+     }
+-    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;
+-        }
+-        Py_DECREF(issuer);
++    for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
++        ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
++        ASN1_IA5STRING *uri;
+ 
+-        version = PyInt_FromLong(X509_get_version(certificate) + 1);
+-        if (PyDict_SetItemString(retval, "version", version) < 0) {
+-            Py_DECREF(version);
+-            goto fail0;
++        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;
+         }
+-        Py_DECREF(version);
+     }
++    AUTHORITY_INFO_ACCESS_free(info);
+ 
+-    /* get a memory buffer */
+-    biobuf = BIO_new(BIO_s_mem());
+-
+-    if (verbose) {
++    /* 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;
++    }
+ 
+-        (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;
++  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;
++    PyObject *peer;
++    PyObject *peer_alt_names = NULL;
++    PyObject *issuer;
++    PyObject *version;
++    PyObject *sn_obj;
++    PyObject *obj;
++    ASN1_INTEGER *serialNumber;
++    char buf[2048];
++    int len, result;
++    ASN1_TIME *notBefore, *notAfter;
++    PyObject *pnotBefore, *pnotAfter;
++
++    retval = PyDict_New();
++    if (retval == NULL)
++        return NULL;
++
++    peer = _create_tuple_for_X509_NAME(
++        X509_get_subject_name(certificate));
++    if (peer == NULL)
++        goto fail0;
++    if (PyDict_SetItemString(retval, (const char *) "subject", peer) < 0) {
++        Py_DECREF(peer);
++        goto fail0;
++    }
++    Py_DECREF(peer);
++
++    issuer = _create_tuple_for_X509_NAME(
++        X509_get_issuer_name(certificate));
++    if (issuer == NULL)
++        goto fail0;
++    if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) {
++        Py_DECREF(issuer);
++        goto fail0;
++    }
++    Py_DECREF(issuer);
++
++    version = 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());
++
++    (void) BIO_reset(biobuf);
++    serialNumber = X509_get_serialNumber(certificate);
++    /* should not exceed 20 octets, 160 bits, so buf is big enough */
++    i2a_ASN1_INTEGER(biobuf, serialNumber);
++    len = BIO_gets(biobuf, buf, sizeof(buf)-1);
++    if (len < 0) {
++        _setSSLError(NULL, 0, __FILE__, __LINE__);
++        goto fail1;
++    }
++    sn_obj = PyUnicode_FromStringAndSize(buf, len);
++    if (sn_obj == NULL)
++        goto fail1;
++    if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) {
+         Py_DECREF(sn_obj);
++        goto fail1;
++    }
++    Py_DECREF(sn_obj);
+ 
+-        (void) BIO_reset(biobuf);
+-        notBefore = X509_get_notBefore(certificate);
+-        ASN1_TIME_print(biobuf, notBefore);
+-        len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+-        if (len < 0) {
+-            _setSSLError(NULL, 0, __FILE__, __LINE__);
+-            goto fail1;
+-        }
+-        pnotBefore = PyString_FromStringAndSize(buf, len);
+-        if (pnotBefore == NULL)
+-            goto fail1;
+-        if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) {
+-            Py_DECREF(pnotBefore);
+-            goto fail1;
+-        }
++    (void) BIO_reset(biobuf);
++    notBefore = X509_get_notBefore(certificate);
++    ASN1_TIME_print(biobuf, notBefore);
++    len = BIO_gets(biobuf, buf, sizeof(buf)-1);
++    if (len < 0) {
++        _setSSLError(NULL, 0, __FILE__, __LINE__);
++        goto fail1;
++    }
++    pnotBefore = PyUnicode_FromStringAndSize(buf, len);
++    if (pnotBefore == NULL)
++        goto fail1;
++    if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) {
+         Py_DECREF(pnotBefore);
++        goto fail1;
+     }
++    Py_DECREF(pnotBefore);
+ 
+     (void) BIO_reset(biobuf);
+     notAfter = X509_get_notAfter(certificate);
+@@ -1008,6 +1186,41 @@ _decode_certificate (X509 *certificate, int verbose) {
+         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 @@ _decode_certificate (X509 *certificate, int verbose) {
+     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 *mod, PyObject *args) {
+     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 *mod, PyObject *args) {
+ 
+ 
+ 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, PyObject *args)
+     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, PyObject *args)
+         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, returns a DER-encoded copy of the\n\
+ peer certificate, or None if no certificate was provided.  This will\n\
+ return the certificate even if it wasn't validated.");
+ 
+-static PyObject *PySSL_cipher (PySSLObject *self) {
++static PyObject *PySSL_cipher (PySSLSocket *self) {
+ 
+     PyObject *retval, *v;
+     const SSL_CIPHER *current;
+@@ -1140,7 +1363,7 @@ static PyObject *PySSL_cipher (PySSLObject *self) {
+             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 (PySSLObject *self) {
+     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;
++    PySocketSockObject *sock = self->Socket;
++
++    Py_INCREF(sock);
+ 
+-    if (!PyArg_ParseTuple(args, "s*:write", &buf))
++    if (!PyArg_ParseTuple(args, "s*:write", &buf)) {
++        Py_DECREF(sock);
+         return NULL;
++    }
+ 
+     if (buf.len > INT_MAX) {
+         PyErr_Format(PyExc_OverflowError,
+@@ -1259,11 +1557,11 @@ static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args)
+     }
+ 
+     /* 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(PySSLObject *self, PyObject *args)
+             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(PySSLObject *self, PyObject *args)
+         }
+     } 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(PySSLObject *self, PyObject *args)
+         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;
++    PySocketSockObject *sock = self->Socket;
+ 
+-    if (!PyArg_ParseTuple(args, "|i:read", &len))
+-        return NULL;
++    Py_INCREF(sock);
+ 
+-    if (!(buf = PyString_FromStringAndSize((char *) 0, len)))
+-        return NULL;
++    buf.obj = NULL;
++    buf.buf = NULL;
++    if (!PyArg_ParseTuple(args, "i|w*:read", &len, &buf))
++        goto error;
++
++    if ((buf.buf == NULL) && (buf.obj == NULL)) {
++        dest = PyBytes_FromStringAndSize(NULL, len);
++        if (dest == NULL)
++            goto error;
++        mem = PyBytes_AS_STRING(dest);
++    }
++    else {
++        buf_passed = 1;
++        mem = buf.buf;
++        if (len <= 0 || len > buf.len) {
++            len = (int) buf.len;
++            if (buf.len != len) {
++                PyErr_SetString(PyExc_OverflowError,
++                                "maximum length can't fit in a C 'int'");
++                goto error;
++            }
++        }
++    }
+ 
+     /* just in case the blocking state of the socket has been changed */
+-    nonblocking = (self->Socket->sock_timeout >= 0.0);
++    nonblocking = (sock->sock_timeout >= 0.0);
+     BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
+     BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
+ 
+@@ -1367,70 +1690,71 @@ static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
+     PySSL_END_ALLOW_THREADS
+ 
+     if (!count) {
+-        sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
++        sockstate = check_socket_and_wait_for_timeout(sock, 0);
+         if (sockstate == SOCKET_HAS_TIMED_OUT) {
+             PyErr_SetString(PySSLErrorObject,
+                             "The read operation timed out");
+-            Py_DECREF(buf);
+-            return NULL;
++            goto error;
+         } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
+             PyErr_SetString(PySSLErrorObject,
+                             "Underlying socket too large for select().");
+-            Py_DECREF(buf);
+-            return NULL;
++            goto error;
+         } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
+-            if (SSL_get_shutdown(self->ssl) !=
+-                SSL_RECEIVED_SHUTDOWN)
+-            {
+-                Py_DECREF(buf);
+-                PyErr_SetString(PySSLErrorObject,
+-                                "Socket closed without SSL shutdown handshake");
+-                return NULL;
+-            } else {
+-                /* should contain a zero-length string */
+-                _PyString_Resize(&buf, 0);
+-                return buf;
+-            }
++            count = 0;
++            goto done;
+         }
+     }
+     do {
+         PySSL_BEGIN_ALLOW_THREADS
+-        count = SSL_read(self->ssl, PyString_AsString(buf), len);
++        count = SSL_read(self->ssl, mem, len);
+         err = SSL_get_error(self->ssl, count);
+         PySSL_END_ALLOW_THREADS
+-        if(PyErr_CheckSignals()) {
+-            Py_DECREF(buf);
+-            return NULL;
+-        }
++        if (PyErr_CheckSignals())
++            goto error;
+         if (err == SSL_ERROR_WANT_READ) {
+-            sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
++            sockstate = check_socket_and_wait_for_timeout(sock, 0);
+         } else if (err == SSL_ERROR_WANT_WRITE) {
+-            sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
++            sockstate = check_socket_and_wait_for_timeout(sock, 1);
+         } else if ((err == SSL_ERROR_ZERO_RETURN) &&
+                    (SSL_get_shutdown(self->ssl) ==
+                     SSL_RECEIVED_SHUTDOWN))
+         {
+-            _PyString_Resize(&buf, 0);
+-            return buf;
++            count = 0;
++            goto done;
+         } else {
+             sockstate = SOCKET_OPERATION_OK;
+         }
+         if (sockstate == SOCKET_HAS_TIMED_OUT) {
+             PyErr_SetString(PySSLErrorObject,
+                             "The read operation timed out");
+-            Py_DECREF(buf);
+-            return NULL;
++            goto error;
+         } else if (sockstate == SOCKET_IS_NONBLOCKING) {
+             break;
+         }
+     } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+     if (count <= 0) {
+-        Py_DECREF(buf);
+-        return PySSL_SetError(self, count, __FILE__, __LINE__);
++        PySSL_SetError(self, count, __FILE__, __LINE__);
++        goto error;
++    }
++
++done:
++    Py_DECREF(sock);
++    if (!buf_passed) {
++        _PyBytes_Resize(&dest, count);
++        return dest;
+     }
+-    if (count != len)
+-        _PyString_Resize(&buf, count);
+-    return buf;
++    else {
++        PyBuffer_Release(&buf);
++        return PyLong_FromLong(count);
++    }
++
++error:
++    Py_DECREF(sock);
++    if (!buf_passed)
++        Py_XDECREF(dest);
++    else
++        PyBuffer_Release(&buf);
++    return NULL;
+ }
+ 
+ PyDoc_STRVAR(PySSL_SSLread_doc,
+@@ -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(PySSLObject *self)
+         /* 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(PySSLObject *self)
+             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,66 +1904,1345 @@ static PyMethodDef PySSLMethods[] = {
+      PySSL_SSLread_doc},
+     {"pending", (PyCFunction)PySSL_SSLpending, METH_NOARGS,
+      PySSL_SSLpending_doc},
+-    {"server", (PyCFunction)PySSL_server, METH_NOARGS},
+-    {"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS},
+     {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS,
+      PySSL_peercert_doc},
+     {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS},
++#ifdef OPENSSL_NPN_NEGOTIATED
++    {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS},
++#endif
++    {"compression", (PyCFunction)PySSL_compression, METH_NOARGS},
+     {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS,
+      PySSL_SSLshutdown_doc},
++#if HAVE_OPENSSL_FINISHED
++    {"tls_unique_cb", (PyCFunction)PySSL_tls_unique_cb, METH_NOARGS,
++     PySSL_tls_unique_cb_doc},
++#endif
+     {NULL, NULL}
+ };
+ 
+-static PyObject *PySSL_getattr(PySSLObject *self, char *name)
+-{
+-    return Py_FindMethod(PySSLMethods, (PyObject *)self, name);
+-}
+-
+-static PyTypeObject PySSL_Type = {
++static PyTypeObject PySSLSocket_Type = {
+     PyVarObject_HEAD_INIT(NULL, 0)
+-    "ssl.SSLContext",                   /*tp_name*/
+-    sizeof(PySSLObject),                /*tp_basicsize*/
++    "_ssl._SSLSocket",                  /*tp_name*/
++    sizeof(PySSLSocket),                /*tp_basicsize*/
+     0,                                  /*tp_itemsize*/
+     /* methods */
+     (destructor)PySSL_dealloc,          /*tp_dealloc*/
+     0,                                  /*tp_print*/
+-    (getattrfunc)PySSL_getattr,         /*tp_getattr*/
++    0,                                  /*tp_getattr*/
+     0,                                  /*tp_setattr*/
+-    0,                                  /*tp_compare*/
++    0,                                  /*tp_reserved*/
+     0,                                  /*tp_repr*/
+     0,                                  /*tp_as_number*/
+     0,                                  /*tp_as_sequence*/
+     0,                                  /*tp_as_mapping*/
+     0,                                  /*tp_hash*/
++    0,                                  /*tp_call*/
++    0,                                  /*tp_str*/
++    0,                                  /*tp_getattro*/
++    0,                                  /*tp_setattro*/
++    0,                                  /*tp_as_buffer*/
++    Py_TPFLAGS_DEFAULT,                 /*tp_flags*/
++    0,                                  /*tp_doc*/
++    0,                                  /*tp_traverse*/
++    0,                                  /*tp_clear*/
++    0,                                  /*tp_richcompare*/
++    0,                                  /*tp_weaklistoffset*/
++    0,                                  /*tp_iter*/
++    0,                                  /*tp_iternext*/
++    PySSLMethods,                       /*tp_methods*/
++    0,                                  /*tp_members*/
++    ssl_getsetlist,                     /*tp_getset*/
+ };
+ 
+-#ifdef HAVE_OPENSSL_RAND
+ 
+-/* helper routines for seeding the SSL PRNG */
++/*
++ * _SSLContext objects
++ */
++
+ static PyObject *
+-PySSL_RAND_add(PyObject *self, PyObject *args)
++context_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+ {
+-    char *buf;
+-    int len;
+-    double entropy;
++    char *kwlist[] = {"protocol", NULL};
++    PySSLContext *self;
++    int proto_version = PY_SSL_VERSION_SSL23;
++    long options;
++    SSL_CTX *ctx = NULL;
+ 
+-    if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy))
++    if (!PyArg_ParseTupleAndKeywords(
++        args, kwds, "i:_SSLContext", kwlist,
++        &proto_version))
+         return NULL;
+-    RAND_add(buf, len, entropy);
+-    Py_INCREF(Py_None);
+-    return Py_None;
+-}
+-
+-PyDoc_STRVAR(PySSL_RAND_add_doc,
+-"RAND_add(string, entropy)\n\
+-\n\
+-Mix string into the OpenSSL PRNG state.  entropy (a float) is a lower\n\
+-bound on the entropy contained in string.  See RFC 1750.");
+ 
+-static PyObject *
+-PySSL_RAND_status(PyObject *self)
+-{
+-    return PyInt_FromLong(RAND_status());
++    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;
++    if (proto_version != PY_SSL_VERSION_SSL2)
++        options |= SSL_OP_NO_SSLv2;
++    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);
++    Py_CLEAR(keyfile_bytes);
++    Py_CLEAR(certfile_bytes);
++    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);
++    Py_XDECREF(keyfile_bytes);
++    Py_XDECREF(certfile_bytes);
++    return NULL;
++}
++
++/* internal helper function, returns -1 on error
++ */
++static int
++_add_ca_certs(PySSLContext *self, void *data, Py_ssize_t len,
++              int filetype)
++{
++    BIO *biobuf = NULL;
++    X509_STORE *store;
++    int retval = 0, err, loaded = 0;
++
++    assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM);
++
++    if (len <= 0) {
++        PyErr_SetString(PyExc_ValueError,
++                        "Empty certificate data");
++        return -1;
++    } else if (len > INT_MAX) {
++        PyErr_SetString(PyExc_OverflowError,
++                        "Certificate data is too long.");
++        return -1;
++    }
++
++    biobuf = BIO_new_mem_buf(data, (int)len);
++    if (biobuf == NULL) {
++        _setSSLError("Can't allocate buffer", 0, __FILE__, __LINE__);
++        return -1;
++    }
++
++    store = SSL_CTX_get_cert_store(self->ctx);
++    assert(store != NULL);
++
++    while (1) {
++        X509 *cert = NULL;
++        int r;
++
++        if (filetype == SSL_FILETYPE_ASN1) {
++            cert = d2i_X509_bio(biobuf, NULL);
++        } else {
++            cert = PEM_read_bio_X509(biobuf, NULL,
++                                     self->ctx->default_passwd_callback,
++                                     self->ctx->default_passwd_callback_userdata);
++        }
++        if (cert == NULL) {
++            break;
++        }
++        r = X509_STORE_add_cert(store, cert);
++        X509_free(cert);
++        if (!r) {
++            err = ERR_peek_last_error();
++            if ((ERR_GET_LIB(err) == ERR_LIB_X509) &&
++                (ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE)) {
++                /* cert already in hash table, not an error */
++                ERR_clear_error();
++            } else {
++                break;
++            }
++        }
++        loaded++;
++    }
++
++    err = ERR_peek_last_error();
++    if ((filetype == SSL_FILETYPE_ASN1) &&
++            (loaded > 0) &&
++            (ERR_GET_LIB(err) == ERR_LIB_ASN1) &&
++            (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) {
++        /* EOF ASN1 file, not an error */
++        ERR_clear_error();
++        retval = 0;
++    } else if ((filetype == SSL_FILETYPE_PEM) &&
++                   (loaded > 0) &&
++                   (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
++                   (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
++        /* EOF PEM file, not an error */
++        ERR_clear_error();
++        retval = 0;
++    } else {
++        _setSSLError(NULL, 0, __FILE__, __LINE__);
++        retval = -1;
++    }
++
++    BIO_free(biobuf);
++    return retval;
++}
++
++
++static PyObject *
++load_verify_locations(PySSLContext *self, PyObject *args, PyObject *kwds)
++{
++    char *kwlist[] = {"cafile", "capath", "cadata", NULL};
++    PyObject *cadata = NULL, *cafile = NULL, *capath = NULL;
++    PyObject *cafile_bytes = NULL, *capath_bytes = NULL;
++    const char *cafile_buf = NULL, *capath_buf = NULL;
++    int r = 0, ok = 1;
++
++    errno = 0;
++    if (!PyArg_ParseTupleAndKeywords(args, kwds,
++            "|OOO:load_verify_locations", kwlist,
++            &cafile, &capath, &cadata))
++        return NULL;
++
++    if (cafile == Py_None)
++        cafile = NULL;
++    if (capath == Py_None)
++        capath = NULL;
++    if (cadata == Py_None)
++        cadata = NULL;
++
++    if (cafile == NULL && capath == NULL && cadata == NULL) {
++        PyErr_SetString(PyExc_TypeError,
++                        "cafile, capath and cadata cannot be all omitted");
++        goto error;
++    }
++
++    if (cafile) {
++        cafile_bytes = PyString_AsEncodedObject(
++            cafile, Py_FileSystemDefaultEncoding, "strict");
++        if (!cafile_bytes) {
++            goto error;
++        }
++    }
++    if (capath) {
++        capath_bytes = PyString_AsEncodedObject(
++            capath, Py_FileSystemDefaultEncoding, "strict");
++        if (!capath_bytes) {
++            goto error;
++        }
++    }
++
++    /* validata cadata type and load cadata */
++    if (cadata) {
++        Py_buffer buf;
++        PyObject *cadata_ascii = NULL;
++
++        if (!PyUnicode_Check(cadata) && PyObject_GetBuffer(cadata, &buf, PyBUF_SIMPLE) == 0) {
++            if (!PyBuffer_IsContiguous(&buf, 'C') || buf.ndim > 1) {
++                PyBuffer_Release(&buf);
++                PyErr_SetString(PyExc_TypeError,
++                                "cadata should be a contiguous buffer with "
++                                "a single dimension");
++                goto error;
++            }
++            r = _add_ca_certs(self, buf.buf, buf.len, SSL_FILETYPE_ASN1);
++            PyBuffer_Release(&buf);
++            if (r == -1) {
++                goto error;
++            }
++        } else {
++            PyErr_Clear();
++            cadata_ascii = PyUnicode_AsASCIIString(cadata);
++            if (cadata_ascii == NULL) {
++                PyErr_SetString(PyExc_TypeError,
++                                "cadata should be a ASCII string or a "
++                                "bytes-like object");
++                goto error;
++            }
++            r = _add_ca_certs(self,
++                              PyBytes_AS_STRING(cadata_ascii),
++                              PyBytes_GET_SIZE(cadata_ascii),
++                              SSL_FILETYPE_PEM);
++            Py_DECREF(cadata_ascii);
++            if (r == -1) {
++                goto error;
++            }
++        }
++    }
++
++    /* load cafile or capath */
++    if (cafile_bytes || capath_bytes) {
++        if (cafile)
++            cafile_buf = PyBytes_AS_STRING(cafile_bytes);
++        if (capath)
++            capath_buf = PyBytes_AS_STRING(capath_bytes);
++        PySSL_BEGIN_ALLOW_THREADS
++        r = SSL_CTX_load_verify_locations(
++            self->ctx,
++            cafile_buf,
++            capath_buf);
++        PySSL_END_ALLOW_THREADS
++        if (r != 1) {
++            ok = 0;
++            if (errno != 0) {
++                ERR_clear_error();
++                PyErr_SetFromErrno(PyExc_IOError);
++            }
++            else {
++                _setSSLError(NULL, 0, __FILE__, __LINE__);
++            }
++            goto error;
++        }
++    }
++    goto end;
++
++  error:
++    ok = 0;
++  end:
++    Py_XDECREF(cafile_bytes);
++    Py_XDECREF(capath_bytes);
++    if (ok) {
++        Py_RETURN_NONE;
++    } else {
++        return NULL;
++    }
++}
++
++static PyObject *
++load_dh_params(PySSLContext *self, PyObject *filepath)
++{
++    BIO *bio;
++    DH *dh;
++    char *path = PyBytes_AsString(filepath);
++    if (!path) {
++        return NULL;
++    }
++
++    bio = BIO_new_file(path, "r");
++    if (bio == NULL) {
++        ERR_clear_error();
++        PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, filepath);
++        return NULL;
++    }
++    errno = 0;
++    PySSL_BEGIN_ALLOW_THREADS
++    dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
++    BIO_free(bio);
++    PySSL_END_ALLOW_THREADS
++    if (dh == NULL) {
++        if (errno != 0) {
++            ERR_clear_error();
++            PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);
++        }
++        else {
++            _setSSLError(NULL, 0, __FILE__, __LINE__);
++        }
++        return NULL;
++    }
++    if (SSL_CTX_set_tmp_dh(self->ctx, dh) == 0)
++        _setSSLError(NULL, 0, __FILE__, __LINE__);
++    DH_free(dh);
++    Py_RETURN_NONE;
++}
++
++static PyObject *
++context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds)
++{
++    char *kwlist[] = {"sock", "server_side", "server_hostname", "ssl_sock", NULL};
++    PySocketSockObject *sock;
++    int server_side = 0;
++    char *hostname = NULL;
++    PyObject *hostname_obj, *ssl_sock = Py_None, *res;
++
++    /* server_hostname is either None (or absent), or to be encoded
++       using the idna encoding. */
++    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!i|O!O:_wrap_socket", kwlist,
++                                     PySocketModule.Sock_Type,
++                                     &sock, &server_side,
++                                     Py_TYPE(Py_None), &hostname_obj,
++                                     &ssl_sock)) {
++        PyErr_Clear();
++        if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!iet|O:_wrap_socket", kwlist,
++            PySocketModule.Sock_Type,
++            &sock, &server_side,
++            "idna", &hostname, &ssl_sock))
++            return NULL;
++#if !HAVE_SNI
++        PyMem_Free(hostname);
++        PyErr_SetString(PyExc_ValueError, "server_hostname is not supported "
++                        "by your OpenSSL library");
++        return NULL;
++#endif
++    }
++
++    res = (PyObject *) newPySSLSocket(self, sock, server_side,
++                                      hostname, ssl_sock);
++    if (hostname != NULL)
++        PyMem_Free(hostname);
++    return res;
++}
++
++static PyObject *
++session_stats(PySSLContext *self, PyObject *unused)
++{
++    int r;
++    PyObject *value, *stats = PyDict_New();
++    if (!stats)
++        return NULL;
++
++#define ADD_STATS(SSL_NAME, KEY_NAME) \
++    value = PyLong_FromLong(SSL_CTX_sess_ ## SSL_NAME (self->ctx)); \
++    if (value == NULL) \
++        goto error; \
++    r = PyDict_SetItemString(stats, KEY_NAME, value); \
++    Py_DECREF(value); \
++    if (r < 0) \
++        goto error;
++
++    ADD_STATS(number, "number");
++    ADD_STATS(connect, "connect");
++    ADD_STATS(connect_good, "connect_good");
++    ADD_STATS(connect_renegotiate, "connect_renegotiate");
++    ADD_STATS(accept, "accept");
++    ADD_STATS(accept_good, "accept_good");
++    ADD_STATS(accept_renegotiate, "accept_renegotiate");
++    ADD_STATS(accept, "accept");
++    ADD_STATS(hits, "hits");
++    ADD_STATS(misses, "misses");
++    ADD_STATS(timeouts, "timeouts");
++    ADD_STATS(cache_full, "cache_full");
++
++#undef ADD_STATS
++
++    return stats;
++
++error:
++    Py_DECREF(stats);
++    return NULL;
++}
++
++static PyObject *
++set_default_verify_paths(PySSLContext *self, PyObject *unused)
++{
++    if (!SSL_CTX_set_default_verify_paths(self->ctx)) {
++        _setSSLError(NULL, 0, __FILE__, __LINE__);
++        return NULL;
++    }
++    Py_RETURN_NONE;
++}
++
++#ifndef OPENSSL_NO_ECDH
++static PyObject *
++set_ecdh_curve(PySSLContext *self, PyObject *name)
++{
++    char *name_bytes;
++    int nid;
++    EC_KEY *key;
++
++    name_bytes = PyBytes_AsString(name);
++    if (!name_bytes) {
++        return NULL;
++    }
++    nid = OBJ_sn2nid(name_bytes);
++    if (nid == 0) {
++        PyErr_Format(PyExc_ValueError,
++                     "unknown elliptic curve name %R", name);
++        return NULL;
++    }
++    key = EC_KEY_new_by_curve_name(nid);
++    if (key == NULL) {
++        _setSSLError(NULL, 0, __FILE__, __LINE__);
++        return NULL;
++    }
++    SSL_CTX_set_tmp_ecdh(self->ctx, key);
++    EC_KEY_free(key);
++    Py_RETURN_NONE;
++}
++#endif
++
++#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT)
++static int
++_servername_callback(SSL *s, int *al, void *args)
++{
++    int ret;
++    PySSLContext *ssl_ctx = (PySSLContext *) args;
++    PySSLSocket *ssl;
++    PyObject *servername_o;
++    PyObject *servername_idna;
++    PyObject *result;
++    /* The high-level ssl.SSLSocket object */
++    PyObject *ssl_socket;
++    const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
++#ifdef WITH_THREAD
++    PyGILState_STATE gstate = PyGILState_Ensure();
++#endif
++
++    if (ssl_ctx->set_hostname == NULL) {
++        /* remove race condition in this the call back while if removing the
++         * callback is in progress */
++#ifdef WITH_THREAD
++        PyGILState_Release(gstate);
++#endif
++        return SSL_TLSEXT_ERR_OK;
++    }
++
++    ssl = SSL_get_app_data(s);
++    assert(PySSLSocket_Check(ssl));
++    ssl_socket = PyWeakref_GetObject(ssl->ssl_sock);
++    Py_INCREF(ssl_socket);
++    if (ssl_socket == Py_None) {
++        goto error;
++    }
++
++    if (servername == NULL) {
++        result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket,
++                                              Py_None, ssl_ctx, NULL);
++    }
++    else {
++        servername_o = PyBytes_FromString(servername);
++        if (servername_o == NULL) {
++            PyErr_WriteUnraisable((PyObject *) ssl_ctx);
++            goto error;
++        }
++        servername_idna = PyUnicode_FromEncodedObject(servername_o, "idna", NULL);
++        if (servername_idna == NULL) {
++            PyErr_WriteUnraisable(servername_o);
++            Py_DECREF(servername_o);
++            goto error;
++        }
++        Py_DECREF(servername_o);
++        result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket,
++                                              servername_idna, ssl_ctx, NULL);
++        Py_DECREF(servername_idna);
++    }
++    Py_DECREF(ssl_socket);
++
++    if (result == NULL) {
++        PyErr_WriteUnraisable(ssl_ctx->set_hostname);
++        *al = SSL_AD_HANDSHAKE_FAILURE;
++        ret = SSL_TLSEXT_ERR_ALERT_FATAL;
++    }
++    else {
++        if (result != Py_None) {
++            *al = (int) PyLong_AsLong(result);
++            if (PyErr_Occurred()) {
++                PyErr_WriteUnraisable(result);
++                *al = SSL_AD_INTERNAL_ERROR;
++            }
++            ret = SSL_TLSEXT_ERR_ALERT_FATAL;
++        }
++        else {
++            ret = SSL_TLSEXT_ERR_OK;
++        }
++        Py_DECREF(result);
++    }
++
++#ifdef WITH_THREAD
++    PyGILState_Release(gstate);
++#endif
++    return ret;
++
++error:
++    Py_DECREF(ssl_socket);
++    *al = SSL_AD_INTERNAL_ERROR;
++    ret = SSL_TLSEXT_ERR_ALERT_FATAL;
++#ifdef WITH_THREAD
++    PyGILState_Release(gstate);
++#endif
++    return ret;
++}
++#endif
++
++PyDoc_STRVAR(PySSL_set_servername_callback_doc,
++"set_servername_callback(method)\n\
++\n\
++This sets a callback that will be called when a server name is provided by\n\
++the SSL/TLS client in the SNI extension.\n\
++\n\
++If the argument is None then the callback is disabled. The method is called\n\
++with the SSLSocket, the server name as a string, and the SSLContext object.\n\
++See RFC 6066 for details of the SNI extension.");
++
++static PyObject *
++set_servername_callback(PySSLContext *self, PyObject *args)
++{
++#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT)
++    PyObject *cb;
++
++    if (!PyArg_ParseTuple(args, "O", &cb))
++        return NULL;
++
++    Py_CLEAR(self->set_hostname);
++    if (cb == Py_None) {
++        SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL);
++    }
++    else {
++        if (!PyCallable_Check(cb)) {
++            SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL);
++            PyErr_SetString(PyExc_TypeError,
++                            "not a callable object");
++            return NULL;
++        }
++        Py_INCREF(cb);
++        self->set_hostname = cb;
++        SSL_CTX_set_tlsext_servername_callback(self->ctx, _servername_callback);
++        SSL_CTX_set_tlsext_servername_arg(self->ctx, self);
++    }
++    Py_RETURN_NONE;
++#else
++    PyErr_SetString(PyExc_NotImplementedError,
++                    "The TLS extension servername callback, "
++                    "SSL_CTX_set_tlsext_servername_callback, "
++                    "is not in the current OpenSSL library.");
++    return NULL;
++#endif
++}
++
++PyDoc_STRVAR(PySSL_get_stats_doc,
++"cert_store_stats() -> {'crl': int, 'x509_ca': int, 'x509': int}\n\
++\n\
++Returns quantities of loaded X.509 certificates. X.509 certificates with a\n\
++CA extension and certificate revocation lists inside the context's cert\n\
++store.\n\
++NOTE: Certificates in a capath directory aren't loaded unless they have\n\
++been used at least once.");
++
++static PyObject *
++cert_store_stats(PySSLContext *self)
++{
++    X509_STORE *store;
++    X509_OBJECT *obj;
++    int x509 = 0, crl = 0, pkey = 0, ca = 0, i;
++
++    store = SSL_CTX_get_cert_store(self->ctx);
++    for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) {
++        obj = sk_X509_OBJECT_value(store->objs, i);
++        switch (obj->type) {
++            case X509_LU_X509:
++                x509++;
++                if (X509_check_ca(obj->data.x509)) {
++                    ca++;
++                }
++                break;
++            case X509_LU_CRL:
++                crl++;
++                break;
++            case X509_LU_PKEY:
++                pkey++;
++                break;
++            default:
++                /* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
++                 * As far as I can tell they are internal states and never
++                 * stored in a cert store */
++                break;
++        }
++    }
++    return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
++        "x509_ca", ca);
++}
++
++PyDoc_STRVAR(PySSL_get_ca_certs_doc,
++"get_ca_certs(binary_form=False) -> list of loaded certificate\n\
++\n\
++Returns a list of dicts with information of loaded CA certs. If the\n\
++optional argument is True, returns a DER-encoded copy of the CA certificate.\n\
++NOTE: Certificates in a capath directory aren't loaded unless they have\n\
++been used at least once.");
++
++static PyObject *
++get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds)
++{
++    char *kwlist[] = {"binary_form", NULL};
++    X509_STORE *store;
++    PyObject *ci = NULL, *rlist = NULL, *py_binary_mode = Py_False;
++    int i;
++    int binary_mode = 0;
++
++    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:get_ca_certs",
++                                     kwlist, &py_binary_mode)) {
++        return NULL;
++    }
++    binary_mode = PyObject_IsTrue(py_binary_mode);
++    if (binary_mode < 0) {
++        return NULL;
++    }
++
++    if ((rlist = PyList_New(0)) == NULL) {
++        return NULL;
++    }
++
++    store = SSL_CTX_get_cert_store(self->ctx);
++    for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) {
++        X509_OBJECT *obj;
++        X509 *cert;
++
++        obj = sk_X509_OBJECT_value(store->objs, i);
++        if (obj->type != X509_LU_X509) {
++            /* not a x509 cert */
++            continue;
++        }
++        /* CA for any purpose */
++        cert = obj->data.x509;
++        if (!X509_check_ca(cert)) {
++            continue;
++        }
++        if (binary_mode) {
++            ci = _certificate_to_der(cert);
++        } else {
++            ci = _decode_certificate(cert);
++        }
++        if (ci == NULL) {
++            goto error;
++        }
++        if (PyList_Append(rlist, ci) == -1) {
++            goto error;
++        }
++        Py_CLEAR(ci);
++    }
++    return rlist;
++
++  error:
++    Py_XDECREF(ci);
++    Py_XDECREF(rlist);
++    return NULL;
++}
++
++
++static PyGetSetDef context_getsetlist[] = {
++    {"check_hostname", (getter) get_check_hostname,
++                       (setter) set_check_hostname, NULL},
++    {"options", (getter) get_options,
++                (setter) set_options, NULL},
++#ifdef HAVE_OPENSSL_VERIFY_PARAM
++    {"verify_flags", (getter) get_verify_flags,
++                     (setter) set_verify_flags, NULL},
++#endif
++    {"verify_mode", (getter) get_verify_mode,
++                    (setter) set_verify_mode, NULL},
++    {NULL},            /* sentinel */
++};
++
++static struct PyMethodDef context_methods[] = {
++    {"_wrap_socket", (PyCFunction) context_wrap_socket,
++                       METH_VARARGS | METH_KEYWORDS, NULL},
++    {"set_ciphers", (PyCFunction) set_ciphers,
++                    METH_VARARGS, NULL},
++    {"_set_npn_protocols", (PyCFunction) _set_npn_protocols,
++                           METH_VARARGS, NULL},
++    {"load_cert_chain", (PyCFunction) load_cert_chain,
++                        METH_VARARGS | METH_KEYWORDS, NULL},
++    {"load_dh_params", (PyCFunction) load_dh_params,
++                       METH_O, NULL},
++    {"load_verify_locations", (PyCFunction) load_verify_locations,
++                              METH_VARARGS | METH_KEYWORDS, NULL},
++    {"session_stats", (PyCFunction) session_stats,
++                      METH_NOARGS, NULL},
++    {"set_default_verify_paths", (PyCFunction) set_default_verify_paths,
++                                 METH_NOARGS, NULL},
++#ifndef OPENSSL_NO_ECDH
++    {"set_ecdh_curve", (PyCFunction) set_ecdh_curve,
++                       METH_O, NULL},
++#endif
++    {"set_servername_callback", (PyCFunction) set_servername_callback,
++                    METH_VARARGS, PySSL_set_servername_callback_doc},
++    {"cert_store_stats", (PyCFunction) cert_store_stats,
++                    METH_NOARGS, PySSL_get_stats_doc},
++    {"get_ca_certs", (PyCFunction) get_ca_certs,
++                    METH_VARARGS | METH_KEYWORDS, PySSL_get_ca_certs_doc},
++    {NULL, NULL}        /* sentinel */
++};
++
++static PyTypeObject PySSLContext_Type = {
++    PyVarObject_HEAD_INIT(NULL, 0)
++    "_ssl._SSLContext",                        /*tp_name*/
++    sizeof(PySSLContext),                      /*tp_basicsize*/
++    0,                                         /*tp_itemsize*/
++    (destructor)context_dealloc,               /*tp_dealloc*/
++    0,                                         /*tp_print*/
++    0,                                         /*tp_getattr*/
++    0,                                         /*tp_setattr*/
++    0,                                         /*tp_reserved*/
++    0,                                         /*tp_repr*/
++    0,                                         /*tp_as_number*/
++    0,                                         /*tp_as_sequence*/
++    0,                                         /*tp_as_mapping*/
++    0,                                         /*tp_hash*/
++    0,                                         /*tp_call*/
++    0,                                         /*tp_str*/
++    0,                                         /*tp_getattro*/
++    0,                                         /*tp_setattro*/
++    0,                                         /*tp_as_buffer*/
++    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
++    0,                                         /*tp_doc*/
++    (traverseproc) context_traverse,           /*tp_traverse*/
++    (inquiry) context_clear,                   /*tp_clear*/
++    0,                                         /*tp_richcompare*/
++    0,                                         /*tp_weaklistoffset*/
++    0,                                         /*tp_iter*/
++    0,                                         /*tp_iternext*/
++    context_methods,                           /*tp_methods*/
++    0,                                         /*tp_members*/
++    context_getsetlist,                        /*tp_getset*/
++    0,                                         /*tp_base*/
++    0,                                         /*tp_dict*/
++    0,                                         /*tp_descr_get*/
++    0,                                         /*tp_descr_set*/
++    0,                                         /*tp_dictoffset*/
++    0,                                         /*tp_init*/
++    0,                                         /*tp_alloc*/
++    context_new,                               /*tp_new*/
++};
++
++
++
++#ifdef HAVE_OPENSSL_RAND
++
++/* helper routines for seeding the SSL PRNG */
++static PyObject *
++PySSL_RAND_add(PyObject *self, PyObject *args)
++{
++    char *buf;
++    Py_ssize_t len, written;
++    double entropy;
++
++    if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy))
++        return NULL;
++    do {
++        if (len >= INT_MAX) {
++            written = INT_MAX;
++        } else {
++            written = len;
++        }
++        RAND_add(buf, (int)written, entropy);
++        buf += written;
++        len -= written;
++    } while (len);
++    Py_INCREF(Py_None);
++    return Py_None;
++}
++
++PyDoc_STRVAR(PySSL_RAND_add_doc,
++"RAND_add(string, entropy)\n\
++\n\
++Mix string into the OpenSSL PRNG state.  entropy (a float) is a lower\n\
++bound on the entropy contained in string.  See RFC 1750.");
++
++static PyObject *
++PySSL_RAND_status(PyObject *self)
++{
++    return PyLong_FromLong(RAND_status());
+ }
+ 
+ PyDoc_STRVAR(PySSL_RAND_status_doc,
+@@ -1630,21 +3281,413 @@ fails or if it does not provide enough data to seed PRNG.");
+ #endif /* HAVE_OPENSSL_RAND */
+ 
+ 
++PyDoc_STRVAR(PySSL_get_default_verify_paths_doc,
++"get_default_verify_paths() -> tuple\n\
++\n\
++Return search paths and environment vars that are used by SSLContext's\n\
++set_default_verify_paths() to load default CAs. The values are\n\
++'cert_file_env', 'cert_file', 'cert_dir_env', 'cert_dir'.");
++
++static PyObject *
++PySSL_get_default_verify_paths(PyObject *self)
++{
++    PyObject *ofile_env = NULL;
++    PyObject *ofile = NULL;
++    PyObject *odir_env = NULL;
++    PyObject *odir = NULL;
++
++#define convert(info, target) { \
++        const char *tmp = (info); \
++        target = NULL; \
++        if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \
++        else { target = PyBytes_FromString(tmp); } \
++        if (!target) goto error; \
++    } while(0)
++
++    convert(X509_get_default_cert_file_env(), ofile_env);
++    convert(X509_get_default_cert_file(), ofile);
++    convert(X509_get_default_cert_dir_env(), odir_env);
++    convert(X509_get_default_cert_dir(), odir);
++#undef convert
++
++    return Py_BuildValue("NNNN", ofile_env, ofile, odir_env, odir);
++
++  error:
++    Py_XDECREF(ofile_env);
++    Py_XDECREF(ofile);
++    Py_XDECREF(odir_env);
++    Py_XDECREF(odir);
++    return NULL;
++}
++
++static PyObject*
++asn1obj2py(ASN1_OBJECT *obj)
++{
++    int nid;
++    const char *ln, *sn;
++    char buf[100];
++    Py_ssize_t buflen;
++
++    nid = OBJ_obj2nid(obj);
++    if (nid == NID_undef) {
++        PyErr_Format(PyExc_ValueError, "Unknown object");
++        return NULL;
++    }
++    sn = OBJ_nid2sn(nid);
++    ln = OBJ_nid2ln(nid);
++    buflen = OBJ_obj2txt(buf, sizeof(buf), obj, 1);
++    if (buflen < 0) {
++        _setSSLError(NULL, 0, __FILE__, __LINE__);
++        return NULL;
++    }
++    if (buflen) {
++        return Py_BuildValue("isss#", nid, sn, ln, buf, buflen);
++    } else {
++        return Py_BuildValue("issO", nid, sn, ln, Py_None);
++    }
++}
++
++PyDoc_STRVAR(PySSL_txt2obj_doc,
++"txt2obj(txt, name=False) -> (nid, shortname, longname, oid)\n\
++\n\
++Lookup NID, short name, long name and OID of an ASN1_OBJECT. By default\n\
++objects are looked up by OID. With name=True short and long name are also\n\
++matched.");
++
++static PyObject*
++PySSL_txt2obj(PyObject *self, PyObject *args, PyObject *kwds)
++{
++    char *kwlist[] = {"txt", "name", NULL};
++    PyObject *result = NULL;
++    char *txt;
++    PyObject *pyname = Py_None;
++    int name = 0;
++    ASN1_OBJECT *obj;
++
++    if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O:txt2obj",
++                                     kwlist, &txt, &pyname)) {
++        return NULL;
++    }
++    name = PyObject_IsTrue(pyname);
++    if (name < 0)
++        return NULL;
++    obj = OBJ_txt2obj(txt, name ? 0 : 1);
++    if (obj == NULL) {
++        PyErr_Format(PyExc_ValueError, "unknown object '%.100s'", txt);
++        return NULL;
++    }
++    result = asn1obj2py(obj);
++    ASN1_OBJECT_free(obj);
++    return result;
++}
++
++PyDoc_STRVAR(PySSL_nid2obj_doc,
++"nid2obj(nid) -> (nid, shortname, longname, oid)\n\
++\n\
++Lookup NID, short name, long name and OID of an ASN1_OBJECT by NID.");
++
++static PyObject*
++PySSL_nid2obj(PyObject *self, PyObject *args)
++{
++    PyObject *result = NULL;
++    int nid;
++    ASN1_OBJECT *obj;
++
++    if (!PyArg_ParseTuple(args, "i:nid2obj", &nid)) {
++        return NULL;
++    }
++    if (nid < NID_undef) {
++        PyErr_SetString(PyExc_ValueError, "NID must be positive.");
++        return NULL;
++    }
++    obj = OBJ_nid2obj(nid);
++    if (obj == NULL) {
++        PyErr_Format(PyExc_ValueError, "unknown NID %i", nid);
++        return NULL;
++    }
++    result = asn1obj2py(obj);
++    ASN1_OBJECT_free(obj);
++    return result;
++}
++
++#ifdef _MSC_VER
++
++static PyObject*
++certEncodingType(DWORD encodingType)
++{
++    static PyObject *x509_asn = NULL;
++    static PyObject *pkcs_7_asn = NULL;
++
++    if (x509_asn == NULL) {
++        x509_asn = 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 +3715,17 @@ _ssl_thread_id_function (void) {
+ }
+ #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.
++       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.
++       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 +3749,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 +3761,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 +3781,39 @@ PyDoc_STRVAR(module_doc,
+ "Implementation module for SSL socket operations.  See the socket module\n\
+ for documentation.");
+ 
++
++
++
++static void
++parse_openssl_version(unsigned long libver,
++                      unsigned int *major, unsigned int *minor,
++                      unsigned int *fix, unsigned int *patch,
++                      unsigned int *status)
++{
++    *status = libver & 0xF;
++    libver >>= 4;
++    *patch = libver & 0xFF;
++    libver >>= 8;
++    *fix = libver & 0xFF;
++    libver >>= 8;
++    *minor = libver & 0xFF;
++    libver >>= 8;
++    *major = libver & 0xFF;
++}
++
+ PyMODINIT_FUNC
+ init_ssl(void)
+ {
+     PyObject *m, *d, *r;
+     unsigned long libver;
+     unsigned int major, minor, fix, patch, status;
++    struct py_ssl_error_code *errcode;
++    struct py_ssl_library_code *libcode;
+ 
+-    Py_TYPE(&PySSL_Type) = &PyType_Type;
++    if (PyType_Ready(&PySSLContext_Type) < 0)
++        return;
++    if (PyType_Ready(&PySSLSocket_Type) < 0)
++        return;
+ 
+     m = Py_InitModule3("_ssl", PySSL_methods, module_doc);
+     if (m == NULL)
+@@ -1766,15 +3836,53 @@ init_ssl(void)
+     OpenSSL_add_all_algorithms();
+ 
+     /* Add symbols to module dict */
+-    PySSLErrorObject = PyErr_NewException("ssl.SSLError",
+-                                          PySocketModule.error,
+-                                          NULL);
++    PySSLErrorObject = PyErr_NewExceptionWithDoc(
++        "ssl.SSLError", SSLError_doc,
++        PySocketModule.error, NULL);
+     if (PySSLErrorObject == NULL)
+         return;
+-    if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0)
++    ((PyTypeObject *)PySSLErrorObject)->tp_str = (reprfunc)SSLError_str;
++
++    PySSLZeroReturnErrorObject = PyErr_NewExceptionWithDoc(
++        "ssl.SSLZeroReturnError", SSLZeroReturnError_doc,
++        PySSLErrorObject, NULL);
++    PySSLWantReadErrorObject = PyErr_NewExceptionWithDoc(
++        "ssl.SSLWantReadError", SSLWantReadError_doc,
++        PySSLErrorObject, NULL);
++    PySSLWantWriteErrorObject = PyErr_NewExceptionWithDoc(
++        "ssl.SSLWantWriteError", SSLWantWriteError_doc,
++        PySSLErrorObject, NULL);
++    PySSLSyscallErrorObject = PyErr_NewExceptionWithDoc(
++        "ssl.SSLSyscallError", SSLSyscallError_doc,
++        PySSLErrorObject, NULL);
++    PySSLEOFErrorObject = PyErr_NewExceptionWithDoc(
++        "ssl.SSLEOFError", SSLEOFError_doc,
++        PySSLErrorObject, NULL);
++    if (PySSLZeroReturnErrorObject == NULL
++        || PySSLWantReadErrorObject == NULL
++        || PySSLWantWriteErrorObject == NULL
++        || PySSLSyscallErrorObject == NULL
++        || PySSLEOFErrorObject == NULL)
++        return;
++
++    ((PyTypeObject *)PySSLZeroReturnErrorObject)->tp_str = (reprfunc)SSLError_str;
++    ((PyTypeObject *)PySSLWantReadErrorObject)->tp_str = (reprfunc)SSLError_str;
++    ((PyTypeObject *)PySSLWantWriteErrorObject)->tp_str = (reprfunc)SSLError_str;
++    ((PyTypeObject *)PySSLSyscallErrorObject)->tp_str = (reprfunc)SSLError_str;
++    ((PyTypeObject *)PySSLEOFErrorObject)->tp_str = (reprfunc)SSLError_str;
++
++    if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0
++        || PyDict_SetItemString(d, "SSLZeroReturnError", PySSLZeroReturnErrorObject) != 0
++        || PyDict_SetItemString(d, "SSLWantReadError", PySSLWantReadErrorObject) != 0
++        || PyDict_SetItemString(d, "SSLWantWriteError", PySSLWantWriteErrorObject) != 0
++        || PyDict_SetItemString(d, "SSLSyscallError", PySSLSyscallErrorObject) != 0
++        || PyDict_SetItemString(d, "SSLEOFError", PySSLEOFErrorObject) != 0)
++        return;
++    if (PyDict_SetItemString(d, "_SSLContext",
++                             (PyObject *)&PySSLContext_Type) != 0)
+         return;
+-    if (PyDict_SetItemString(d, "SSLType",
+-                             (PyObject *)&PySSL_Type) != 0)
++    if (PyDict_SetItemString(d, "_SSLSocket",
++                             (PyObject *)&PySSLSocket_Type) != 0)
+         return;
+     PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN",
+                             PY_SSL_ERROR_ZERO_RETURN);
+@@ -1802,6 +3910,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 +3982,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 +4096,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 +4104,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
+index 0000000..81a8d7b
+--- /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/00197-unicode_fromformat.patch b/00197-unicode_fromformat.patch
new file mode 100644
index 0000000..95031d5
--- /dev/null
+++ b/00197-unicode_fromformat.patch
@@ -0,0 +1,208 @@
+diff -r 847a0e74c4cc Lib/test/test_unicode.py
+--- a/Lib/test/test_unicode.py	Sun Jul 20 21:26:04 2014 -0700
++++ b/Lib/test/test_unicode.py	Tue Jul 22 00:13:24 2014 +0200
+@@ -1659,6 +1659,122 @@ class UnicodeTest(
+         self.assertEqual("%s" % u, u'__unicode__ overridden')
+         self.assertEqual("{}".format(u), '__unicode__ overridden')
+ 
++    # 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'%li', c_long(-123))
++        check_format(u'-123',
++                     b'%zi', c_ssize_t(-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')
++
+     @test_support.cpython_only
+     def test_encode_decimal(self):
+         from _testcapi import unicode_encodedecimal
+diff -r 847a0e74c4cc Objects/unicodeobject.c
+--- a/Objects/unicodeobject.c	Sun Jul 20 21:26:04 2014 -0700
++++ b/Objects/unicodeobject.c	Tue Jul 22 00:13:24 2014 +0200
+@@ -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;
+@@ -925,12 +930,12 @@ PyUnicode_FromFormatV(const char *format
+             }
+             /* handle the long flag, but only for %ld and %lu.
+                others can be added when necessary. */
+-            if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) {
++            if (*f == 'l' && (f[1] == 'd' || f[1] == 'i' || f[1] == 'u')) {
+                 longflag = 1;
+                 ++f;
+             }
+             /* handle the size_t flag. */
+-            if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
++            if (*f == 'z' && (f[1] == 'd' || f[1] == 'i' || f[1] == 'u')) {
+                 size_tflag = 1;
+                 ++f;
+             }
+@@ -939,8 +944,9 @@ PyUnicode_FromFormatV(const char *format
+             case 'c':
+                 *s++ = va_arg(vargs, int);
+                 break;
++            case 'i':
+             case 'd':
+-                makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'd');
++                makefmt(fmt, longflag, size_tflag, zeropad, width, precision, *f);
+                 if (longflag)
+                     sprintf(realbuffer, fmt, va_arg(vargs, long));
+                 else if (size_tflag)
+@@ -959,11 +965,6 @@ PyUnicode_FromFormatV(const char *format
+                     sprintf(realbuffer, fmt, va_arg(vargs, unsigned int));
+                 appendstring(realbuffer);
+                 break;
+-            case 'i':
+-                makefmt(fmt, 0, 0, zeropad, width, precision, 'i');
+-                sprintf(realbuffer, fmt, va_arg(vargs, int));
+-                appendstring(realbuffer);
+-                break;
+             case 'x':
+                 makefmt(fmt, 0, 0, zeropad, width, precision, 'x');
+                 sprintf(realbuffer, fmt, va_arg(vargs, int));
+@@ -1006,15 +1007,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<usize;)
+-                    *s++ = ucopy[upos++];
++                appendstring(str);
+                 /* We're done with the unicode()/repr() => forget it */
+                 Py_DECREF(*callresult);
+                 /* switch to next unicode()/repr() result */
diff --git a/python.spec b/python.spec
index 2033a36..448f55c 100644
--- a/python.spec
+++ b/python.spec
@@ -106,7 +106,7 @@ Summary: An interpreted, interactive, object-oriented programming language
 Name: %{python}
 # Remember to also rebase python-docs when changing this:
 Version: 2.7.8
-Release: 4%{?dist}
+Release: 5%{?dist}
 License: Python
 Group: Development/Languages
 Requires: %{python}-libs%{?_isa} = %{version}-%{release}
@@ -881,7 +881,18 @@ Patch193: 00193-enable-loading-sqlite-extensions.patch
 # are disabled by default in openssl, according the comment in openssl
 # patch this affects only SSLv23_method, this patch enables SSLv2
 # and SSLv3 when SSLv23_method is used
-Patch195: 00195-enable-sslv23-in-ssl.patch
+# Update:
+# Patch disabled, Openssl reverted disabling sslv3 and now
+# disables only sslv2 all tests pass
+#Patch195: 00195-enable-sslv23-in-ssl.patch
+
+# http://bugs.python.org/issue21308
+# Backport of ssl module from python3
+Patch196: 00196-ssl-backport.patch
+
+# http://bugs.python.org/issue22023
+# Patch seg fault in unicodeobject.c
+Patch197: 00197-unicode_fromformat.patch
 
 # (New patches go here ^^^)
 #
@@ -1239,7 +1250,9 @@ mv Modules/cryptmodule.c Modules/_cryptmodule.c
 # 00192: upstream as of Python 2.7.7
 %patch193 -p1
 # 00194: upstream as of Python 2.7.7
-%patch195 -p1
+#%patch195 -p1
+%patch196 -p1
+%patch197 -p1
 
 
 # This shouldn't be necesarry, but is right now (2.2a3)
@@ -2078,6 +2091,9 @@ rm -fr %{buildroot}
 # ======================================================
 
 %changelog
+* Tue Aug 19 2014 Robert Kuska <rkuska at redhat.com> - 2.7.8-5
+- Backport ssl module from python3
+
 * Sun Aug 17 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 2.7.8-4
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
 


More information about the scm-commits mailing list