Author: Richard Plangger <planri...@gmail.com>
Branch: py3.5-ssl
Changeset: r88427:742c85b008ab
Date: 2016-11-17 10:05 +0100
http://bitbucket.org/pypy/pypy/changeset/742c85b008ab/

Log:    copy over certificates of cpython stdlib (ssl + ssl_tests) target
        3.5.2

diff --git a/lib-python/3/test/capath/0e4015b9.0 
b/lib-python/3/test/capath/0e4015b9.0
new file mode 100644
--- /dev/null
+++ b/lib-python/3/test/capath/0e4015b9.0
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
+bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
+A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
+b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
+aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
+Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
+Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
+EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
+bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
+AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
+TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
+C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
+-----END CERTIFICATE-----
diff --git a/lib-python/3/test/capath/ce7b8643.0 
b/lib-python/3/test/capath/ce7b8643.0
new file mode 100644
--- /dev/null
+++ b/lib-python/3/test/capath/ce7b8643.0
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
+bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
+A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
+b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
+aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
+Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
+Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
+EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
+bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
+AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
+TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
+C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
+-----END CERTIFICATE-----
diff --git a/lib-python/3/test/selfsigned_pythontestdotnet.pem 
b/lib-python/3/test/selfsigned_pythontestdotnet.pem
--- a/lib-python/3/test/selfsigned_pythontestdotnet.pem
+++ b/lib-python/3/test/selfsigned_pythontestdotnet.pem
@@ -1,5 +1,5 @@
 -----BEGIN CERTIFICATE-----
-MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
+MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
 BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
 IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
 bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
@@ -8,9 +8,9 @@
 aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
 Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
 Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
-EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl
-bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM
-eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV
-HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97
-vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9
+EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
+bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
+AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
+TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
+C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
 -----END CERTIFICATE-----
diff --git a/lib-python/3/test/test_ssl.py b/lib-python/3/test/test_ssl.py
--- a/lib-python/3/test/test_ssl.py
+++ b/lib-python/3/test/test_ssl.py
@@ -23,9 +23,6 @@
 
 PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
 HOST = support.HOST
-IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL')
-IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0)
-
 
 def data_file(*name):
     return os.path.join(os.path.dirname(__file__), *name)
@@ -57,8 +54,6 @@
 SIGNED_CERTFILE = data_file("keycert3.pem")
 SIGNED_CERTFILE2 = data_file("keycert4.pem")
 SIGNING_CA = data_file("pycacert.pem")
-# cert with all kinds of subject alt names
-ALLSANFILE = data_file("allsans.pem")
 
 REMOTE_HOST = "self-signed.pythontest.net"
 REMOTE_ROOT_CERT = data_file("selfsigned_pythontestdotnet.pem")
@@ -148,8 +143,8 @@
     def test_str_for_enums(self):
         # Make sure that the PROTOCOL_* constants have enum-like string
         # reprs.
-        proto = ssl.PROTOCOL_TLS
-        self.assertEqual(str(proto), '_SSLMethod.PROTOCOL_TLS')
+        proto = ssl.PROTOCOL_SSLv23
+        self.assertEqual(str(proto), '_SSLMethod.PROTOCOL_SSLv23')
         ctx = ssl.SSLContext(proto)
         self.assertIs(ctx.protocol, proto)
 
@@ -281,27 +276,6 @@
 
         self.assertEqual(p['subjectAltName'], san)
 
-    def test_parse_all_sans(self):
-        p = ssl._ssl._test_decode_cert(ALLSANFILE)
-        self.assertEqual(p['subjectAltName'],
-            (
-                ('DNS', 'allsans'),
-                ('othername', '<unsupported>'),
-                ('othername', '<unsupported>'),
-                ('email', 'u...@example.org'),
-                ('DNS', 'www.example.org'),
-                ('DirName',
-                    ((('countryName', 'XY'),),
-                    (('localityName', 'Castle Anthrax'),),
-                    (('organizationName', 'Python Software Foundation'),),
-                    (('commonName', 'dirname example'),))),
-                ('URI', 'https://www.python.org/'),
-                ('IP Address', '127.0.0.1'),
-                ('IP Address', '0:0:0:0:0:0:0:1\n'),
-                ('Registered ID', '1.2.3.4.5')
-            )
-        )
-
     def test_DER_to_PEM(self):
         with open(CAFILE_CACERT, 'r') as f:
             pem = f.read()
@@ -338,8 +312,8 @@
         self.assertGreaterEqual(status, 0)
         self.assertLessEqual(status, 15)
         # Version string as returned by {Open,Libre}SSL, the format might 
change
-        if IS_LIBRESSL:
-            self.assertTrue(s.startswith("LibreSSL {:d}".format(major)),
+        if "LibreSSL" in s:
+            self.assertTrue(s.startswith("LibreSSL {:d}.{:d}".format(major, 
minor)),
                             (s, t, hex(n)))
         else:
             self.assertTrue(s.startswith("OpenSSL 
{:d}.{:d}.{:d}".format(major, minor, fix)),
@@ -816,8 +790,7 @@
     def test_constructor(self):
         for protocol in PROTOCOLS:
             ssl.SSLContext(protocol)
-        ctx = ssl.SSLContext()
-        self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLS)
+        self.assertRaises(TypeError, ssl.SSLContext)
         self.assertRaises(ValueError, ssl.SSLContext, -1)
         self.assertRaises(ValueError, ssl.SSLContext, 42)
 
@@ -838,15 +811,15 @@
     def test_options(self):
         ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
         # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
-        default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
-        if not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0):
-            default |= ssl.OP_NO_COMPRESSION
-        self.assertEqual(default, ctx.options)
+        self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3,
+                         ctx.options)
         ctx.options |= ssl.OP_NO_TLSv1
-        self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
+        self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | 
ssl.OP_NO_TLSv1,
+                         ctx.options)
         if can_clear_options():
-            ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
-            self.assertEqual(default, ctx.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
             # Ubuntu has OP_NO_SSLv3 forced on by default
             self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
@@ -1182,7 +1155,6 @@
         self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
 
     @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
-    @unittest.skipIf(IS_LIBRESSL, "LibreSSL doesn't support env vars")
     def test_load_default_certs_env(self):
         ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
         with support.EnvironmentVarGuard() as env:
@@ -1778,13 +1750,13 @@
             sslobj = ctx.wrap_bio(incoming, outgoing, False, REMOTE_HOST)
             self.assertIs(sslobj._sslobj.owner, sslobj)
             self.assertIsNone(sslobj.cipher())
-            self.assertIsNotNone(sslobj.shared_ciphers())
+            self.assertIsNone(sslobj.shared_ciphers())
             self.assertRaises(ValueError, sslobj.getpeercert)
             if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
                 self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
             self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
             self.assertTrue(sslobj.cipher())
-            self.assertIsNotNone(sslobj.shared_ciphers())
+            self.assertIsNone(sslobj.shared_ciphers())
             self.assertTrue(sslobj.getpeercert())
             if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
                 self.assertTrue(sslobj.get_channel_binding('tls-unique'))
@@ -1898,14 +1870,7 @@
                 else:
                     self.sock.close()
 
-            # PyPy change
             def run(self):
-                try:
-                    self._run()
-                finally:
-                    self.close()
-
-            def _run(self):
                 self.running = True
                 if not self.server.starttls_server:
                     if not self.wrap_conn():
@@ -2668,7 +2633,7 @@
                     s.close()
 
         def test_socketserver(self):
-            """Using socketserver to create and manage SSL connections."""
+            """Using a SocketServer to create and manage SSL connections."""
             server = make_https_server(self, certfile=CERTFILE)
             # try to connect
             if support.verbose:
@@ -2695,6 +2660,8 @@
 
         def test_asyncore_server(self):
             """Check the example asyncore integration."""
+            indata = "TEST MESSAGE of mixed case\n"
+
             if support.verbose:
                 sys.stdout.write("\n")
 
@@ -2826,13 +2793,20 @@
                         # consume data
                         s.read()
 
+                data = b"data"
+
                 # read(-1, buffer) is supported, even though read(-1) is not
-                data = b"data"
                 s.send(data)
                 buffer = bytearray(len(data))
                 self.assertEqual(s.read(-1, buffer), len(data))
                 self.assertEqual(buffer, data)
 
+                # recv/read(0) should return no data
+                s.send(data)
+                self.assertEqual(s.recv(0), b"")
+                self.assertEqual(s.read(0), b"")
+                self.assertEqual(s.read(), data)
+
                 # Make sure sendmsg et al are disallowed to avoid
                 # inadvertent disclosure of data and/or corruption
                 # of the encrypted data stream
@@ -2848,26 +2822,6 @@
 
                 s.close()
 
-        def test_recv_zero(self):
-            server = ThreadedEchoServer(CERTFILE)
-            server.__enter__()
-            self.addCleanup(server.__exit__, None, None)
-            s = socket.create_connection((HOST, server.port))
-            self.addCleanup(s.close)
-            s = ssl.wrap_socket(s, suppress_ragged_eofs=False)
-            self.addCleanup(s.close)
-
-            # recv/read(0) should return no data
-            s.send(b"data")
-            self.assertEqual(s.recv(0), b"")
-            self.assertEqual(s.read(0), b"")
-            self.assertEqual(s.read(), b"data")
-
-            # Should not block if the other end sends no data
-            s.setblocking(False)
-            self.assertEqual(s.recv(0), b"")
-            self.assertEqual(s.recv_into(bytearray()), 0)
-
         def test_nonblocking_send(self):
             server = ThreadedEchoServer(CERTFILE,
                                         certreqs=ssl.CERT_NONE,
@@ -2889,10 +2843,8 @@
                 # will be full and the call will block
                 buf = bytearray(8192)
                 def fill_buffer():
-                    i = 0
                     while True:
                         s.send(buf)
-                        i += 1
                 self.assertRaises((ssl.SSLWantWriteError,
                                    ssl.SSLWantReadError), fill_buffer)
 
@@ -3028,7 +2980,7 @@
                 with context.wrap_socket(socket.socket()) as s:
                     self.assertIs(s.version(), None)
                     s.connect((HOST, server.port))
-                    self.assertEqual(s.version(), 'TLSv1')
+                    self.assertEqual(s.version(), "TLSv1")
                 self.assertIs(s.version(), None)
 
         @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled 
OpenSSL")
@@ -3170,36 +3122,24 @@
                 (['http/3.0', 'http/4.0'], None)
             ]
             for client_protocols, expected in protocol_tests:
-                server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
+                server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
                 server_context.load_cert_chain(CERTFILE)
                 server_context.set_alpn_protocols(server_protocols)
-                client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
+                client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
                 client_context.load_cert_chain(CERTFILE)
                 client_context.set_alpn_protocols(client_protocols)
-
-                try:
-                    stats = server_params_test(client_context,
-                                               server_context,
-                                               chatty=True,
-                                               connectionchatty=True)
-                except ssl.SSLError as e:
-                    stats = e
-
-                if expected is None and IS_OPENSSL_1_1:
-                    # OpenSSL 1.1.0 raises handshake error
-                    self.assertIsInstance(stats, ssl.SSLError)
-                else:
-                    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_alpn_protocol']
-                    self.assertEqual(client_result, expected,
-                                     msg % (client_result, "client"))
-                    server_result = stats['server_alpn_protocols'][-1] \
-                        if len(stats['server_alpn_protocols']) else 'nothing'
-                    self.assertEqual(server_result, expected,
-                                     msg % (server_result, "server"))
+                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_alpn_protocol']
+                self.assertEqual(client_result, expected, msg % 
(client_result, "client"))
+                server_result = stats['server_alpn_protocols'][-1] \
+                    if len(stats['server_alpn_protocols']) else 'nothing'
+                self.assertEqual(server_result, expected, msg % 
(server_result, "server"))
 
         def test_selected_npn_protocol(self):
             # selected_npn_protocol() is None unless NPN is used
@@ -3347,23 +3287,13 @@
             client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
             client_context.verify_mode = ssl.CERT_REQUIRED
             client_context.load_verify_locations(SIGNING_CA)
-            if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2):
-                client_context.set_ciphers("AES128:AES256")
-                server_context.set_ciphers("AES256")
-                alg1 = "AES256"
-                alg2 = "AES-256"
-            else:
-                client_context.set_ciphers("AES:3DES")
-                server_context.set_ciphers("3DES")
-                alg1 = "3DES"
-                alg2 = "DES-CBC3"
-
+            client_context.set_ciphers("RC4")
+            server_context.set_ciphers("AES:RC4")
             stats = server_params_test(client_context, server_context)
             ciphers = stats['server_shared_ciphers'][0]
             self.assertGreater(len(ciphers), 0)
             for name, tls_version, bits in ciphers:
-                if not alg1 in name.split("-") and alg2 not in name:
-                    self.fail(name)
+                self.assertIn("RC4", name.split("-"))
 
         def test_read_write_after_close_raises_valuerror(self):
             context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
diff --git a/lib_pypy/openssl/_cffi_src/openssl/err.py 
b/lib_pypy/openssl/_cffi_src/openssl/err.py
--- a/lib_pypy/openssl/_cffi_src/openssl/err.py
+++ b/lib_pypy/openssl/_cffi_src/openssl/err.py
@@ -196,9 +196,34 @@
 static const int SSL_TLSEXT_ERR_ALERT_FATAL;
 static const int SSL_TLSEXT_ERR_NOACK;
 
+static const int SSL_AD_CLOSE_NOTIFY;
+static const int SSL_AD_UNEXPECTED_MESSAGE;
+static const int SSL_AD_BAD_RECORD_MAC;
+static const int SSL_AD_RECORD_OVERFLOW;
+static const int SSL_AD_DECOMPRESSION_FAILURE;
+static const int SSL_AD_HANDSHAKE_FAILURE;
+static const int SSL_AD_BAD_CERTIFICATE;
+static const int SSL_AD_UNSUPPORTED_CERTIFICATE;
+static const int SSL_AD_CERTIFICATE_REVOKED;
+static const int SSL_AD_CERTIFICATE_EXPIRED;
+static const int SSL_AD_CERTIFICATE_UNKNOWN;
+static const int SSL_AD_ILLEGAL_PARAMETER;
+static const int SSL_AD_UNKNOWN_CA;
+static const int SSL_AD_ACCESS_DENIED;
+static const int SSL_AD_DECODE_ERROR;
+static const int SSL_AD_DECRYPT_ERROR;
+static const int SSL_AD_PROTOCOL_VERSION;
+static const int SSL_AD_INSUFFICIENT_SECURITY;
 static const int SSL_AD_INTERNAL_ERROR;
-static const int SSL_AD_ACCESS_DENIED;
-static const int SSL_AD_HANDSHAKE_FAILURE;
+static const int SSL_AD_USER_CANCELLED;
+static const int SSL_AD_NO_RENEGOTIATION;
+
+static const int SSL_AD_UNSUPPORTED_EXTENSION;
+static const int SSL_AD_CERTIFICATE_UNOBTAINABLE;
+static const int SSL_AD_UNRECOGNIZED_NAME;
+static const int SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+static const int SSL_AD_BAD_CERTIFICATE_HASH_VALUE;
+static const int SSL_AD_UNKNOWN_PSK_IDENTITY;
 """
 
 FUNCTIONS = """
@@ -255,4 +280,24 @@
 static const long Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR = 0;
 static const long RSA_R_PKCS_DECODING_ERROR = 0;
 #endif
+
+#ifndef SSL_AD_UNSUPPORTED_EXTENSION
+    static const int SSL_AD_UNSUPPORTED_EXTENSION = -1;
+#endif
+#ifndef SSL_AD_CERTIFICATE_UNOBTAINABLE
+    static const int SSL_AD_CERTIFICATE_UNOBTAINABLE = -1;
+#endif
+#ifndef SSL_AD_UNRECOGNIZED_NAME
+    static const int SSL_AD_UNRECOGNIZED_NAME = -1;
+#endif
+#ifndef SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE
+    static const int SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE = -1;
+#endif
+#ifndef SSL_AD_BAD_CERTIFICATE_HASH_VALUE
+    static const int SSL_AD_BAD_CERTIFICATE_HASH_VALUE = -1;
+#endif
+#ifndef SSL_AD_UNKNOWN_PSK_IDENTITY
+    static const int SSL_AD_UNKNOWN_PSK_IDENTITY = -1;
+#endif
+
 """
diff --git a/lib_pypy/openssl/_cffi_src/openssl/ssl.py 
b/lib_pypy/openssl/_cffi_src/openssl/ssl.py
--- a/lib_pypy/openssl/_cffi_src/openssl/ssl.py
+++ b/lib_pypy/openssl/_cffi_src/openssl/ssl.py
@@ -695,9 +695,9 @@
 static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS = 1;
 
 #ifdef OPENSSL_NO_TLSEXT
+static const long Cryptography_NO_TLSEXT = 1;
+#else
 static const long Cryptography_NO_TLSEXT = 0;
-#else
-static const long Cryptography_NO_TLSEXT = 1;
 #endif
 
 #ifdef OPENSSL_NPN_NEGOTIATED
diff --git a/lib_pypy/openssl/_stdssl/__init__.py 
b/lib_pypy/openssl/_stdssl/__init__.py
--- a/lib_pypy/openssl/_stdssl/__init__.py
+++ b/lib_pypy/openssl/_stdssl/__init__.py
@@ -8,7 +8,7 @@
 from openssl._stdssl.certificate import (_test_decode_cert,
     _decode_certificate, _certificate_to_der)
 from openssl._stdssl.utility import (_str_with_len, _bytes_with_len,
-    _str_to_ffi_buffer, _str_from_buf)
+    _str_to_ffi_buffer, _str_from_buf, _cstr_decode_fs)
 from openssl._stdssl.error import (ssl_error, pyssl_error,
         SSLError, SSLZeroReturnError, SSLWantReadError,
         SSLWantWriteError, SSLSyscallError,
@@ -17,8 +17,9 @@
         SSL_ERROR_SSL, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
         SSL_ERROR_WANT_X509_LOOKUP, SSL_ERROR_SYSCALL,
         SSL_ERROR_ZERO_RETURN, SSL_ERROR_WANT_CONNECT,
-        SSL_ERROR_EOF, SSL_ERROR_NO_SOCKET, SSL_ERROR_INVALID_ERROR_CODE)
-
+        SSL_ERROR_EOF, SSL_ERROR_NO_SOCKET, SSL_ERROR_INVALID_ERROR_CODE,
+        pyerr_write_unraisable)
+from openssl._stdssl import error
 
 OPENSSL_VERSION = ffi.string(lib.OPENSSL_VERSION_TEXT).decode('utf-8')
 OPENSSL_VERSION_NUMBER = lib.OPENSSL_VERSION_NUMBER
@@ -85,6 +86,12 @@
 else:
     CHANNEL_BINDING_TYPES = []
 
+for name in error.SSL_AD_NAMES:
+    lib_attr = 'SSL_AD_' + name
+    attr = 'ALERT_DESCRIPTION_' + name
+    if hasattr(lib, lib_attr):
+        globals()[attr] = getattr(lib, lib_attr)
+
 # init open ssl
 lib.SSL_load_error_strings()
 lib.SSL_library_init()
@@ -103,6 +110,7 @@
     callable = None
     password = None
     operationerror = None
+    handle = None
 PWINFO_STORAGE = {}
 
 def _Cryptography_pem_password_cb(buf, size, rwflag, userdata):
@@ -258,8 +266,8 @@
         self._owner = None
         self.server_hostname = None
         self.socket = None
-        self.alpn_protocols = ffi.NULL
-        self.npn_protocols = ffi.NULL
+        #self.alpn_protocols = ffi.NULL
+        #self.npn_protocols = ffi.NULL
 
     @property
     def owner(self):
@@ -710,7 +718,7 @@
 class _SSLContext(object):
     __slots__ = ('ctx', '_check_hostname', 'servername_callback',
                  'alpn_protocols', 'npn_protocols', 'set_hostname',
-                 '_set_hostname_handle')
+                 '_set_hostname_handle', '_npn_protocols_handle')
 
     def __new__(cls, protocol):
         self = object.__new__(cls)
@@ -861,8 +869,6 @@
         pw_info = PasswordInfo()
         index = -1
         if password is not None:
-            index = _thread.get_ident()
-            PWINFO_STORAGE[index] = pw_info
 
             if callable(password):
                 pw_info.callable = password
@@ -872,9 +878,11 @@
                 else:
                     raise TypeError("password should be a string or callable")
 
-            handle = ffi.new_handle(pw_info) # XXX MUST NOT be garbage 
collected
+            pw_info.handle = ffi.new_handle(pw_info)
+            index = _thread.get_ident()
+            PWINFO_STORAGE[index] = pw_info
             lib.SSL_CTX_set_default_passwd_cb(self.ctx, 
Cryptography_pem_password_cb)
-            lib.SSL_CTX_set_default_passwd_cb_userdata(self.ctx, handle)
+            lib.SSL_CTX_set_default_passwd_cb_userdata(self.ctx, 
pw_info.handle)
 
         try:
             ffi.errno = 0
@@ -908,7 +916,7 @@
 
             ret = lib.SSL_CTX_check_private_key(self.ctx)
             if ret != 1:
-                raise _ssl_seterror(None, -1)
+                raise ssl_error(None)
         finally:
             if index >= 0:
                 del PWINFO_STORAGE[index]
@@ -1033,6 +1041,7 @@
         return {'x509': x509, 'x509_ca': x509_ca, 'crl': crl}
 
 
+#    REVIEW, how to do that properly
 #    def _finalize_(self):
 #        ctx = self.ctx
 #        if ctx:
@@ -1125,8 +1134,8 @@
             return
         if not callable(callback):
             raise TypeError("not a callable object")
-        self.set_hostname = callback
-        self._set_hostname_handle = ffi.new_handle(self)
+        scb = ServernameCallback(callback, self)
+        self._set_hostname_handle = ffi.new_handle(scb)
         lib.Cryptography_SSL_CTX_set_tlsext_servername_callback(self.ctx, 
_servername_callback)
         lib.Cryptography_SSL_CTX_set_tlsext_servername_arg(self.ctx, 
self._set_hostname_handle)
 
@@ -1146,6 +1155,7 @@
         if HAS_NPN:
             self.npn_protocols = ffi.from_buffer(protos)
             handle = ffi.new_handle(self)
+            self._npn_protocols_handle = handle # track a reference to the 
handle
             lib.SSL_CTX_set_next_protos_advertised_cb(self.ctx, 
advertise_npn_callback, handle)
             lib.SSL_CTX_set_next_proto_select_cb(self.ctx, 
select_npn_callback, handle)
         else:
@@ -1156,20 +1166,21 @@
 if HAS_SNI and not lib.Cryptography_NO_TLSEXT:
     @ffi.callback("int(SSL*,int*,void*)")
     def _servername_callback(s, al, arg):
-        ssl_ctx = ffi.from_handle(arg)
+        scb = ffi.from_handle(arg)
+        ssl_ctx = scb.ctx
         servername = lib.SSL_get_servername(s, lib.TLSEXT_NAMETYPE_host_name)
-    #ifdef WITH_THREAD
-        # TODO PyGILState_STATE gstate = PyGILState_Ensure();
-    #endif
+        set_hostname = scb.callback
+        #ifdef WITH_THREAD
+            # TODO PyGILState_STATE gstate = PyGILState_Ensure();
+        #endif
 
-        if ssl_ctx.set_hostname is None:
+        if set_hostname is None:
             #/* remove race condition in this the call back while if removing 
the
             # * callback is in progress */
-    #ifdef WITH_THREAD
-            # TODO PyGILState_Release(gstate);
-    #endif
+            #ifdef WITH_THREAD
+                    # TODO PyGILState_Release(gstate);
+            #endif
             return lib.SSL_TLSEXT_ERR_OK
-        #}
 
         ssl = ffi.from_handle(lib.SSL_get_app_data(s))
         assert isinstance(ssl, _SSLSocket)
@@ -1192,10 +1203,9 @@
 
         if servername == ffi.NULL:
             try:
-                result = ssl_ctx.set_hostname(ssl_socket, None, ssl_ctx)
-            except:
-                # TODO
-                #        PyErr_WriteUnraisable(ssl_ctx->set_hostname);
+                result = set_hostname(ssl_socket, None, ssl_ctx)
+            except Exception as e:
+                pyerr_write_unraisable(e, set_hostname)
                 al[0] = lib.SSL_AD_HANDSHAKE_FAILURE
                 return lib.SSL_TLSEXT_ERR_ALERT_FATAL
         else:
@@ -1203,31 +1213,44 @@
 
             try:
                 servername_idna = servername.decode("idna")
-            except UnicodeDecodeError:
-                raise # TODO?
-    #            PyErr_WriteUnraisable(servername_o);
+            except UnicodeDecodeError as e:
+                pyerr_write_unraisable(e, servername)
 
             try:
-                result = ssl_ctx.set_hostname(ssl_socket, servername_idna, 
ssl_ctx)
-            except:
-                # TODO
-                #        PyErr_WriteUnraisable(ssl_ctx->set_hostname);
+                result = set_hostname(ssl_socket, servername_idna, ssl_ctx)
+            except Exception as e:
+                pyerr_write_unraisable(e, set_hostname)
                 al[0] = lib.SSL_AD_HANDSHAKE_FAILURE
                 return lib.SSL_TLSEXT_ERR_ALERT_FATAL
 
         if result is not None:
+            # this is just a poor man's emulation:
+            # in CPython this works a bit different, it calls all the way
+            # down from PyLong_AsLong to _PyLong_FromNbInt which raises
+            # a TypeError if there is no nb_int slot filled.
             try:
-                al[0] = int(result)
-            except:
-    #                PyErr_WriteUnraisable(result);
-               al[0] = lib.SSL_AD_INTERNAL_ERROR
-               return lib.SSL_TLSEXT_ERR_ALERT_FATAL
+                if isinstance(result, int):
+                    al[0] = result
+                else:
+                    if result is not None:
+                        if hasattr(result,'__int__'):
+                            al[0] = result.__int__()
+                            return lib.SSL_TLSEXT_ERR_ALERT_FATAL
+                    # needed because sys.exec_info is used in 
pyerr_write_unraisable
+                    raise TypeError("an integer is required (got type %s)" % 
result)
+            except TypeError as e:
+                pyerr_write_unraisable(e, result)
+                al[0] = lib.SSL_AD_INTERNAL_ERROR
+            return lib.SSL_TLSEXT_ERR_ALERT_FATAL
         else:
             # TODO gil state release?
             return lib.SSL_TLSEXT_ERR_OK
 
 class ServernameCallback(object):
-    ctx = None
+    def __init__(self, callback, ctx):
+        self.callback = callback
+        self.ctx = ctx
+
 SERVERNAME_CALLBACKS = weakref.WeakValueDictionary()
 TEST = None
 
@@ -1287,13 +1310,13 @@
         """Whether the memory BIO is at EOF."""
         return lib.BIO_ctrl_pending(self.bio) == 0 and self.eof_written
 
-    def write(self, _bytes):
+    def write(self, strlike):
         INT_MAX = 2**31-1
-        if isinstance(_bytes, memoryview):
-            # REVIEW pypy does not support from_buffer of a memoryview
-            # copies the data!
-            _bytes = bytes(_bytes)
-        buf = ffi.from_buffer(_bytes)
+        if isinstance(strlike, memoryview):
+            # FIXME pypy must support get_raw_address for
+            # StringBuffer to remove this case!
+            strlike = strlike.tobytes()
+        buf = ffi.from_buffer(strlike)
         if len(buf) > INT_MAX:
             raise OverflowError("string longer than %d bytes", INT_MAX)
 
@@ -1346,7 +1369,7 @@
         ok = lib.RAND_bytes(buf, count)
         if ok == 1:
             return ffi.string(buf)
-    raise ssl_error("", errcode=lib.ERR_get_error())
+    raise ssl_error(None, errcode=lib.ERR_get_error())
 
 def RAND_pseudo_bytes(count):
     return _RAND_bytes(count, True)
@@ -1358,19 +1381,6 @@
     buf = _str_to_ffi_buffer(view)
     lib.RAND_add(buf, len(buf), entropy)
 
-
-def _cstr_decode_fs(buf):
-#define CONVERT(info, target) { \
-#        const char *tmp = (info); \
-#        target = NULL; \
-#        if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \
-#        else if ((target = PyUnicode_DecodeFSDefault(tmp)) == NULL) { \
-#            target = PyBytes_FromString(tmp); } \
-#        if (!target) goto error; \
-#    }
-    # REVIEW
-    return ffi.string(buf).decode(sys.getfilesystemencoding())
-
 def get_default_verify_paths():
 
     ofile_env = _cstr_decode_fs(lib.X509_get_default_cert_file_env())
@@ -1385,7 +1395,6 @@
     odir = _cstr_decode_fs(lib.X509_get_default_cert_dir())
     if odir is None:
         return odir
-
     return (ofile_env, ofile, odir_env, odir);
 
 @ffi.callback("int(SSL*,unsigned char **,unsigned char *,const unsigned char 
*,unsigned int,void *)")
@@ -1395,28 +1404,28 @@
                                  ffi.cast("unsigned 
char*",ctx.alpn_protocols), len(ctx.alpn_protocols),
                                  client_protocols, client_protocols_len)
 
-@ffi.callback("int(SSL*,unsigned char **,unsigned char *,const unsigned char 
*,unsigned int,void *)")
-def select_npn_callback(ssl, out, outlen, server_protocols, 
server_protocols_len, args):
-    ctx = ffi.from_handle(args)
-    return do_protocol_selection(0, out, outlen, server_protocols, 
server_protocols_len,
-                                 ffi.cast("unsigned char*",ctx.npn_protocols), 
len(ctx.npn_protocols))
+if lib.Cryptography_HAS_NPN_NEGOTIATED:
+    @ffi.callback("int(SSL*,unsigned char **,unsigned char *,const unsigned 
char *,unsigned int,void *)")
+    def select_npn_callback(ssl, out, outlen, server_protocols, 
server_protocols_len, args):
+        ctx = ffi.from_handle(args)
+        return do_protocol_selection(0, out, outlen, server_protocols, 
server_protocols_len,
+                                     ffi.cast("unsigned 
char*",ctx.npn_protocols), len(ctx.npn_protocols))
 
 
-@ffi.callback("int(SSL*,const unsigned char**, unsigned int*, void*)")
-def advertise_npn_callback(ssl, data, length, args):
-    ctx = ffi.from_handle(args)
+    @ffi.callback("int(SSL*,const unsigned char**, unsigned int*, void*)")
+    def advertise_npn_callback(ssl, data, length, args):
+        ctx = ffi.from_handle(args)
 
-    if not ctx.npn_protocols:
-        data[0] = ffi.new("unsigned char*", b"")
-        length[0] = 0
-    else:
-        data[0] = ffi.cast("unsigned char*",ctx.npn_protocols)
-        length[0] = len(ctx.npn_protocols)
+        if not ctx.npn_protocols:
+            data[0] = ffi.new("unsigned char*", b"")
+            length[0] = 0
+        else:
+            data[0] = ffi.cast("unsigned char*",ctx.npn_protocols)
+            length[0] = len(ctx.npn_protocols)
 
-    return lib.SSL_TLSEXT_ERR_OK
+        return lib.SSL_TLSEXT_ERR_OK
 
 
-if lib.Cryptography_HAS_NPN_NEGOTIATED:
     def do_protocol_selection(alpn, out, outlen, server_protocols, 
server_protocols_len,
                                                  client_protocols, 
client_protocols_len):
         if client_protocols == ffi.NULL:
diff --git a/lib_pypy/openssl/_stdssl/error.py 
b/lib_pypy/openssl/_stdssl/error.py
--- a/lib_pypy/openssl/_stdssl/error.py
+++ b/lib_pypy/openssl/_stdssl/error.py
@@ -1,3 +1,5 @@
+import sys
+import traceback
 from _openssl import ffi
 from _openssl import lib
 
@@ -46,7 +48,7 @@
     if errstr is None:
         errcode = lib.ERR_peek_last_error()
     try:
-        return fill_sslerror(SSLError, errcode, errstr)
+        return fill_sslerror(SSLError, errcode, errstr, errcode)
     finally:
         lib.ERR_clear_error()
 
@@ -136,6 +138,7 @@
         lib_str = LIB_CODES_TO_NAMES.get(err_lib, None)
         if errstr is None:
             errstr = _str_from_buf(lib.ERR_reason_error_string(errcode))
+    msg = errstr
     if not errstr:
         msg = "unknown error"
     if reason_str and lib_str:
@@ -148,3 +151,49 @@
     err_value.library = lib_str if lib_str else None
     return err_value
 
+def pyerr_write_unraisable(exc, obj):
+    f = sys.stderr
+
+    if obj:
+        f.write("Exception ignored in: ")
+        f.write(repr(obj))
+        f.write("\n")
+
+    t, v, tb = sys.exc_info()
+    traceback.print_tb(tb, file=f)
+
+    assert isinstance(v, Exception)
+    f.write(t.__module__ + "." + t.__name__)
+    f.write(": ")
+    f.write(str(v))
+    f.write("\n")
+
+SSL_AD_NAMES = [
+    "ACCESS_DENIED",
+    "BAD_CERTIFICATE",
+    "BAD_CERTIFICATE_HASH_VALUE",
+    "BAD_CERTIFICATE_STATUS_RESPONSE",
+    "BAD_RECORD_MAC",
+    "CERTIFICATE_EXPIRED",
+    "CERTIFICATE_REVOKED",
+    "CERTIFICATE_UNKNOWN",
+    "CERTIFICATE_UNOBTAINABLE",
+    "CLOSE_NOTIFY",
+    "DECODE_ERROR",
+    "DECOMPRESSION_FAILURE",
+    "DECRYPT_ERROR",
+    "HANDSHAKE_FAILURE",
+    "ILLEGAL_PARAMETER",
+    "INSUFFICIENT_SECURITY",
+    "INTERNAL_ERROR",
+    "NO_RENEGOTIATION",
+    "PROTOCOL_VERSION",
+    "RECORD_OVERFLOW",
+    "UNEXPECTED_MESSAGE",
+    "UNKNOWN_CA",
+    "UNKNOWN_PSK_IDENTITY",
+    "UNRECOGNIZED_NAME",
+    "UNSUPPORTED_CERTIFICATE",
+    "UNSUPPORTED_EXTENSION",
+    "USER_CANCELLED",
+]
diff --git a/lib_pypy/openssl/_stdssl/utility.py 
b/lib_pypy/openssl/_stdssl/utility.py
--- a/lib_pypy/openssl/_stdssl/utility.py
+++ b/lib_pypy/openssl/_stdssl/utility.py
@@ -1,3 +1,4 @@
+import sys
 from _openssl import ffi
 from _openssl import lib
 
@@ -36,3 +37,15 @@
 def _str_from_buf(buf):
     return ffi.string(buf).decode('utf-8')
 
+def _cstr_decode_fs(buf):
+#define CONVERT(info, target) { \
+#        const char *tmp = (info); \
+#        target = NULL; \
+#        if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \
+#        else if ((target = PyUnicode_DecodeFSDefault(tmp)) == NULL) { \
+#            target = PyBytes_FromString(tmp); } \
+#        if (!target) goto error; \
+#    }
+    # REVIEW
+    return ffi.string(buf).decode(sys.getfilesystemencoding())
+
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to