[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