[Jython-checkins] jython: test_ssl failures from weak certificate. Fixes #2774.
jeff.allen
jython-checkins at python.org
Sun Jun 16 14:01:28 EDT 2019
https://hg.python.org/jython/rev/3d37bb31d66d
changeset: 8250:3d37bb31d66d
user: Adam Burke <adamburkemail at gmail.com>
date: Sun Jun 16 17:53:43 2019 +0100
summary:
test_ssl failures from weak certificate. Fixes #2774.
The minimal fix is simply the update to selfsigned_pythontestdotnet.pem
from Python core. See Python bug 36816.
This change also merges from the latest 2.7 version of test_ssl, and
separates most Jython variation into test_ssl_jy.py. This is to ease future
maintenance and/or patches back into CPython. No new tests are skipped.
Method test_algorithms() is deleted as per 2.7 and Python bug 25764,
although it actually ran cleanly locally.
files:
Lib/ssl.py | 4 +-
Lib/test/capath/efa5f9c3.0 | 34 +
Lib/test/regrtest.py | 1 +
Lib/test/selfsigned_pythontestdotnet.pem | 46 +-
Lib/test/test_ssl.py | 717 ++++++---
Lib/test/test_ssl_jy.py | 231 +++
NEWS | 1 +
lib-python/2.7/test/selfsigned_pythontestdotnet.pem | 34 +
8 files changed, 806 insertions(+), 262 deletions(-)
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -97,6 +97,8 @@
VERIFY_DEFAULT, VERIFY_CRL_CHECK_LEAF, VERIFY_CRL_CHECK_CHAIN, VERIFY_X509_STRICT = 0, 4, 12, 32
+HAS_TLSv1_3 = False
+
CHANNEL_BINDING_TYPES = []
# https://docs.python.org/2/library/ssl.html#ssl.HAS_ALPN etc...
@@ -691,7 +693,7 @@
self._sock._handle_channel_future(self._handshake_future, "SSL handshake")
def dup(self):
- raise NotImplemented("Can't dup() %s instances" %
+ raise NotImplementedError("Can't dup() %s instances" %
self.__class__.__name__)
@raises_java_exception
diff --git a/Lib/test/capath/efa5f9c3.0 b/Lib/test/capath/efa5f9c3.0
new file mode 100644
--- /dev/null
+++ b/Lib/test/capath/efa5f9c3.0
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF9zCCA9+gAwIBAgIUH98b4Fw/DyugC9cV7VK7ZODzHsIwDQYJKoZIhvcNAQEL
+BQAwgYoxCzAJBgNVBAYTAlhZMRcwFQYDVQQIDA5DYXN0bGUgQW50aHJheDEYMBYG
+A1UEBwwPQXJndW1lbnQgQ2xpbmljMSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0aG9udGVzdC5uZXQw
+HhcNMTkwNTA4MDEwMjQzWhcNMjcwNzI0MDEwMjQzWjCBijELMAkGA1UEBhMCWFkx
+FzAVBgNVBAgMDkNhc3RsZSBBbnRocmF4MRgwFgYDVQQHDA9Bcmd1bWVudCBDbGlu
+aWMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQD
+DBpzZWxmLXNpZ25lZC5weXRob250ZXN0Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMKdJlyCThkahwoBb7pl5q64Pe9Fn5jrIvzsveHTc97TpjV2
+RLfICnXKrltPk/ohkVl6K5SUZQZwMVzFubkyxE0nZPHYHlpiKWQxbsYVkYv01rix
+IFdLvaxxbGYke2jwQao31s4o61AdlsfK1SdpHQUynBBMssqI3SB4XPmcA7e+wEEx
+jxjVish4ixA1vuIZOx8yibu+CFCf/geEjoBMF3QPdzULzlrCSw8k/45iZCSoNbvK
+DoL4TVV07PHOxpheDh8ZQmepGvU6pVqhb9m4lgmV0OGWHgozd5Ur9CbTVDmxIEz3
+TSoRtNJK7qtyZdGNqwjksQxgZTjM/d/Lm/BJG99AiOmYOjsl9gbQMZgvQmMAtUsI
+aMJnQuZ6R+KEpW/TR5qSKLWZSG45z/op+tzI2m+cE6HwTRVAWbcuJxcAA55MZjqU
+OOOu3BBYMjS5nf2sQ9uoXsVBFH7i0mQqoW1SLzr9opI8KsWwFxQmO2vBxWYaN+lH
+OmwBZBwyODIsmI1YGXmTp09NxRYz3Qe5GCgFzYowpMrcxUC24iduIdMwwhRM7rKg
+7GtIWMSrFfuI1XCLRmSlhDbhNN6fVg2f8Bo9PdH9ihiIyxSrc+FOUasUYCCJvlSZ
+8hFUlLvcmrZlWuazohm0lsXuMK1JflmQr/DA/uXxP9xzFfRy+RU3jDyxJbRHAgMB
+AAGjUzBRMB0GA1UdDgQWBBSQJyxiPMRK01i+0BsV9zUwDiBaHzAfBgNVHSMEGDAW
+gBSQJyxiPMRK01i+0BsV9zUwDiBaHzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4ICAQCR+7a7N/m+WLkxPPIA/CB4MOr2Uf8ixTv435Nyv6rXOun0+lTP
+ExSZ0uYQ+L0WylItI3cQHULldDueD+s8TGzxf5woaLKf6tqyr0NYhKs+UeNEzDnN
+9PHQIhX0SZw3XyXGUgPNBfRCg2ZDdtMMdOU4XlQN/IN/9hbYTrueyY7eXq9hmtI9
+1srftAMqr9SR1JP7aHI6DVgrEsZVMTDnfT8WmLSGLlY1HmGfdEn1Ip5sbo9uSkiH
+AEPgPfjYIvR5LqTOMn4KsrlZyBbFIDh9Sl99M1kZzgH6zUGVLCDg1y6Cms69fx/e
+W1HoIeVkY4b4TY7Bk7JsqyNhIuqu7ARaxkdaZWhYaA2YyknwANdFfNpfH+elCLIk
+BUt5S3f4i7DaUePTvKukCZiCq4Oyln7RcOn5If73wCeLB/ZM9Ei1HforyLWP1CN8
+XLfpHaoeoPSWIveI0XHUl65LsPN2UbMbul/F23hwl+h8+BLmyAS680Yhn4zEN6Ku
+B7Po90HoFa1Du3bmx4jsN73UkT/dwMTi6K072FbipnC1904oGlWmLwvAHvrtxxmL
+Pl3pvEaZIu8wa/PNF6Y7J7VIewikIJq6Ta6FrWeFfzMWOj2qA1ZZi6fUaDSNYvuV
+J5quYKCc/O+I/yDDf8wyBbZ/gvUXzUHTMYGG+bFrn1p7XDbYYeEJ6R/xEg==
+-----END CERTIFICATE-----
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -1322,6 +1322,7 @@
test_peepholer
test_pyclbr
test_pyexpat
+ test_ssl # overridden by test_ssl_jy
test_stringprep # UnicodeDecodeError
test_threadsignals
test_transformer
diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem
--- a/Lib/test/selfsigned_pythontestdotnet.pem
+++ b/Lib/test/selfsigned_pythontestdotnet.pem
@@ -1,16 +1,34 @@
-----BEGIN CERTIFICATE-----
-MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
-bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
-A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
-b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
-aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
-Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
-Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
-EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
-bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
-AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
-TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
-C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
+MIIF9zCCA9+gAwIBAgIUH98b4Fw/DyugC9cV7VK7ZODzHsIwDQYJKoZIhvcNAQEL
+BQAwgYoxCzAJBgNVBAYTAlhZMRcwFQYDVQQIDA5DYXN0bGUgQW50aHJheDEYMBYG
+A1UEBwwPQXJndW1lbnQgQ2xpbmljMSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0aG9udGVzdC5uZXQw
+HhcNMTkwNTA4MDEwMjQzWhcNMjcwNzI0MDEwMjQzWjCBijELMAkGA1UEBhMCWFkx
+FzAVBgNVBAgMDkNhc3RsZSBBbnRocmF4MRgwFgYDVQQHDA9Bcmd1bWVudCBDbGlu
+aWMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQD
+DBpzZWxmLXNpZ25lZC5weXRob250ZXN0Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMKdJlyCThkahwoBb7pl5q64Pe9Fn5jrIvzsveHTc97TpjV2
+RLfICnXKrltPk/ohkVl6K5SUZQZwMVzFubkyxE0nZPHYHlpiKWQxbsYVkYv01rix
+IFdLvaxxbGYke2jwQao31s4o61AdlsfK1SdpHQUynBBMssqI3SB4XPmcA7e+wEEx
+jxjVish4ixA1vuIZOx8yibu+CFCf/geEjoBMF3QPdzULzlrCSw8k/45iZCSoNbvK
+DoL4TVV07PHOxpheDh8ZQmepGvU6pVqhb9m4lgmV0OGWHgozd5Ur9CbTVDmxIEz3
+TSoRtNJK7qtyZdGNqwjksQxgZTjM/d/Lm/BJG99AiOmYOjsl9gbQMZgvQmMAtUsI
+aMJnQuZ6R+KEpW/TR5qSKLWZSG45z/op+tzI2m+cE6HwTRVAWbcuJxcAA55MZjqU
+OOOu3BBYMjS5nf2sQ9uoXsVBFH7i0mQqoW1SLzr9opI8KsWwFxQmO2vBxWYaN+lH
+OmwBZBwyODIsmI1YGXmTp09NxRYz3Qe5GCgFzYowpMrcxUC24iduIdMwwhRM7rKg
+7GtIWMSrFfuI1XCLRmSlhDbhNN6fVg2f8Bo9PdH9ihiIyxSrc+FOUasUYCCJvlSZ
+8hFUlLvcmrZlWuazohm0lsXuMK1JflmQr/DA/uXxP9xzFfRy+RU3jDyxJbRHAgMB
+AAGjUzBRMB0GA1UdDgQWBBSQJyxiPMRK01i+0BsV9zUwDiBaHzAfBgNVHSMEGDAW
+gBSQJyxiPMRK01i+0BsV9zUwDiBaHzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4ICAQCR+7a7N/m+WLkxPPIA/CB4MOr2Uf8ixTv435Nyv6rXOun0+lTP
+ExSZ0uYQ+L0WylItI3cQHULldDueD+s8TGzxf5woaLKf6tqyr0NYhKs+UeNEzDnN
+9PHQIhX0SZw3XyXGUgPNBfRCg2ZDdtMMdOU4XlQN/IN/9hbYTrueyY7eXq9hmtI9
+1srftAMqr9SR1JP7aHI6DVgrEsZVMTDnfT8WmLSGLlY1HmGfdEn1Ip5sbo9uSkiH
+AEPgPfjYIvR5LqTOMn4KsrlZyBbFIDh9Sl99M1kZzgH6zUGVLCDg1y6Cms69fx/e
+W1HoIeVkY4b4TY7Bk7JsqyNhIuqu7ARaxkdaZWhYaA2YyknwANdFfNpfH+elCLIk
+BUt5S3f4i7DaUePTvKukCZiCq4Oyln7RcOn5If73wCeLB/ZM9Ei1HforyLWP1CN8
+XLfpHaoeoPSWIveI0XHUl65LsPN2UbMbul/F23hwl+h8+BLmyAS680Yhn4zEN6Ku
+B7Po90HoFa1Du3bmx4jsN73UkT/dwMTi6K072FbipnC1904oGlWmLwvAHvrtxxmL
+Pl3pvEaZIu8wa/PNF6Y7J7VIewikIJq6Ta6FrWeFfzMWOj2qA1ZZi6fUaDSNYvuV
+J5quYKCc/O+I/yDDf8wyBbZ/gvUXzUHTMYGG+bFrn1p7XDbYYeEJ6R/xEg==
-----END CERTIFICATE-----
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -4,6 +4,7 @@
import sys
import unittest
from test import test_support as support
+from test.script_helper import assert_python_ok
import asyncore
import socket
import select
@@ -13,11 +14,12 @@
import os
import errno
import pprint
-import tempfile
+import shutil
import urllib2
import traceback
import weakref
import platform
+import re
import functools
from contextlib import closing
@@ -25,6 +27,9 @@
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):
file = os.path.join(os.path.dirname(__file__), *name)
@@ -62,20 +67,30 @@
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")
EMPTYCERT = data_file("nullcert.pem")
BADCERT = data_file("badcert.pem")
-WRONGCERT = data_file("XXXnonexisting.pem")
+NONEXISTINGCERT = data_file("XXXnonexisting.pem")
BADKEY = data_file("badkey.pem")
NOKIACERT = data_file("nokia.pem")
NULLBYTECERT = data_file("nullbytecert.pem")
-
-DHFILE = data_file("dh1024.pem")
+TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem")
+
+DHFILE = data_file("ffdh3072.pem")
BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding())
+# Not defined in all versions of OpenSSL
+OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
+OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
+OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
+OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
+OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
+
def handle_error(prefix):
exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
@@ -151,6 +166,36 @@
else:
return func
+def skip_if_openssl_cnf_minprotocol_gt_tls1(func):
+ """Skip a test if the OpenSSL config MinProtocol is > TLSv1.
+ OS distros with an /etc/ssl/openssl.cnf and MinProtocol set often do so to
+ require TLSv1.2 or higher (Debian Buster). Some of our tests for older
+ protocol versions will fail under such a config.
+ Alternative workaround: Run this test in a process with
+ OPENSSL_CONF=/dev/null in the environment.
+ """
+ @functools.wraps(func)
+ def f(*args, **kwargs):
+ openssl_cnf = os.environ.get("OPENSSL_CONF", "/etc/ssl/openssl.cnf")
+ try:
+ with open(openssl_cnf, "r") as config:
+ for line in config:
+ match = re.match(r"MinProtocol\s*=\s*(TLSv\d+\S*)", line)
+ if match:
+ tls_ver = match.group(1)
+ if tls_ver > "TLSv1":
+ raise unittest.SkipTest(
+ "%s has MinProtocol = %s which is > TLSv1." %
+ (openssl_cnf, tls_ver))
+ except (EnvironmentError, UnicodeDecodeError) as err:
+ # no config file found, etc.
+ if support.verbose:
+ sys.stdout.write("\n Could not scan %s for MinProtocol: %s\n"
+ % (openssl_cnf, err))
+ return func(*args, **kwargs)
+ return f
+
+
needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test")
@@ -168,7 +213,13 @@
ssl.OP_NO_COMPRESSION
self.assertIn(ssl.HAS_SNI, {True, False})
self.assertIn(ssl.HAS_ECDH, {True, False})
-
+ ssl.OP_NO_SSLv2
+ ssl.OP_NO_SSLv3
+ ssl.OP_NO_TLSv1
+ # ssl.OP_NO_TLSv1_3 Not yet supported in Jython ssl.py
+ if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1):
+ ssl.OP_NO_TLSv1_1
+ ssl.OP_NO_TLSv1_2
def test_random(self):
v = ssl.RAND_status()
@@ -181,7 +232,6 @@
self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1)
ssl.RAND_add("this is a random string", 75.0)
- @unittest.skipIf(support.is_jython, "Jython does not have _ssl, therefore this test needs to be rewritten")
def test_parse_cert(self):
# note that this uses an 'unofficial' function in _ssl.c,
# provided solely for this test, to exercise the certificate
@@ -196,9 +246,9 @@
(('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['notAfter'], asn1time('Aug 26 14:23:15 2028 GMT'))
+ self.assertEqual(p['notBefore'], asn1time('Aug 29 14:23:15 2018 GMT'))
+ self.assertEqual(p['serialNumber'], '98A7CF88C74A32ED')
self.assertEqual(p['subject'],
((('countryName', 'XY'),),
(('localityName', 'Castle Anthrax'),),
@@ -222,7 +272,27 @@
self.assertEqual(p['crlDistributionPoints'],
('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',))
- @unittest.skipIf(support.is_jython, "Jython does not have _ssl, therefore this test needs to be rewritten")
+ def test_parse_cert_CVE_2019_5010(self):
+ p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP)
+ if support.verbose:
+ sys.stdout.write("\n" + pprint.pformat(p) + "\n")
+ self.assertEqual(
+ p,
+ {
+ 'issuer': (
+ (('countryName', 'UK'),), (('commonName', 'cody-ca'),)),
+ 'notAfter': 'Jun 14 18:00:58 2028 GMT',
+ 'notBefore': 'Jun 18 18:00:58 2018 GMT',
+ 'serialNumber': '02',
+ 'subject': ((('countryName', 'UK'),),
+ (('commonName',
+ 'codenomicon-vm-2.test.lal.cisco.com'),)),
+ 'subjectAltName': (
+ ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),),
+ 'version': 3
+ }
+ )
+
def test_parse_cert_CVE_2013_4238(self):
p = ssl._ssl._test_decode_cert(NULLBYTECERT)
if support.verbose:
@@ -252,6 +322,27 @@
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', 'user at 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()
@@ -288,9 +379,9 @@
self.assertGreaterEqual(status, 0)
self.assertLessEqual(status, 15)
# Version string as returned by {Open,Libre}SSL, the format might change
- if "LibreSSL" in s:
- self.assertTrue(s.startswith("LibreSSL {:d}.{:d}".format(major, minor)),
- (s, t))
+ if IS_LIBRESSL:
+ self.assertTrue(s.startswith("LibreSSL {:d}".format(major)),
+ (s, t, hex(n)))
else:
self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
(s, t))
@@ -316,6 +407,7 @@
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))
+ self.assertRaises(NotImplementedError, ss.dup)
def test_timeout(self):
# Issue #8524: when creating an SSL socket, the timeout of the
@@ -348,16 +440,41 @@
s.connect, (HOST, 8080))
with self.assertRaises(IOError) as cm:
with closing(socket.socket()) as sock:
- ssl.wrap_socket(sock, certfile=WRONGCERT)
+ ssl.wrap_socket(sock, certfile=NONEXISTINGCERT)
+ 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=NONEXISTINGCERT)
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)
+ ssl.wrap_socket(sock,
+ certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT)
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 bad_cert_test(self, certfile):
+ """Check that trying to use the given client certificate fails"""
+ certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
+ certfile)
+ sock = socket.socket()
+ self.addCleanup(sock.close)
+ with self.assertRaises(ssl.SSLError):
+ ssl.wrap_socket(sock,
+ certfile=certfile,
+ ssl_version=ssl.PROTOCOL_TLSv1)
+
+ def test_empty_cert(self):
+ """Wrapping with an empty cert file"""
+ self.bad_cert_test("nullcert.pem")
+
+ def test_malformed_cert(self):
+ """Wrapping with a badly formatted certificate (syntax error)"""
+ self.bad_cert_test("badcert.pem")
+
+ def test_malformed_key(self):
+ """Wrapping with a badly formatted key (syntax error)"""
+ self.bad_cert_test("badkey.pem")
def test_match_hostname(self):
def ok(cert, hostname):
@@ -583,32 +700,31 @@
self.assertIsInstance(val, ssl._ASN1Object)
self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth')
- # TODO Jython better asn1 support, though not sure there's much use for it
- # 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')
+ 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')
@@ -720,7 +836,6 @@
ctx = ssl.SSLContext(proto)
self.assertEqual(ctx.protocol, proto)
- @unittest.skipIf(support.is_jython, "Currently not supported")
def test_ciphers(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.set_ciphers("ALL")
@@ -732,17 +847,20 @@
def test_options(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
# OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
- self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3,
- ctx.options)
+ default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
+ # SSLContext also enables these by default
+ default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
+ OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
+ OP_ENABLE_MIDDLEBOX_COMPAT)
+ self.assertEqual(default, ctx.options)
ctx.options |= ssl.OP_NO_TLSv1
- self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1,
- ctx.options)
+ self.assertEqual(default | ssl.OP_NO_TLSv1, 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 = (ctx.options & ~ssl.OP_NO_TLSv1)
+ self.assertEqual(default, ctx.options)
ctx.options = 0
- self.assertEqual(0, ctx.options)
+ # Ubuntu has OP_NO_SSLv3 forced on by default
+ self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
else:
with self.assertRaises(ValueError):
ctx.options = 0
@@ -797,7 +915,7 @@
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)
+ ctx.load_cert_chain(NONEXISTINGCERT)
self.assertEqual(cm.exception.errno, errno.ENOENT)
with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"):
ctx.load_cert_chain(BADCERT)
@@ -883,7 +1001,7 @@
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)
+ ctx.load_verify_locations(NONEXISTINGCERT)
self.assertEqual(cm.exception.errno, errno.ENOENT)
with self.assertRaises(IOError):
ctx.load_verify_locations(u'')
@@ -953,8 +1071,14 @@
ctx.load_verify_locations(cadata=b"broken")
- @unittest.skipIf(support.is_jython, "Not yet supported on Jython")
def test_load_dh_params(self):
+ filename = u'dhpäräm.pem'
+ fs_encoding = sys.getfilesystemencoding()
+ try:
+ filename.encode(fs_encoding)
+ except UnicodeEncodeError:
+ self.skipTest("filename %r cannot be encoded to the filesystem encoding %r" % (filename, fs_encoding))
+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.load_dh_params(DHFILE)
if os.name != 'nt':
@@ -962,10 +1086,14 @@
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)
+ ctx.load_dh_params(NONEXISTINGCERT)
self.assertEqual(cm.exception.errno, errno.ENOENT)
with self.assertRaises(ssl.SSLError) as cm:
ctx.load_dh_params(CERTFILE)
+ with support.temp_dir() as d:
+ fname = os.path.join(d, filename)
+ shutil.copy(DHFILE, fname)
+ ctx.load_dh_params(fname)
@skip_if_broken_ubuntu_ssl
def test_session_stats(self):
@@ -1033,16 +1161,13 @@
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
self.assertEqual(ctx.cert_store_stats(),
{'x509_ca': 0, 'crl': 0, 'x509': 0})
-
- # Jython x509 will grow by 1 while openssl remains 0
- # TODO investgate deeper
ctx.load_cert_chain(CERTFILE)
self.assertEqual(ctx.cert_store_stats(),
- {'x509_ca': 0, 'crl': 0, 'x509': 1})
+ {'x509_ca': 0, 'crl': 0, 'x509': 0})
ctx.load_verify_locations(CERTFILE)
self.assertEqual(ctx.cert_store_stats(),
- {'x509_ca': 0, 'crl': 0, 'x509': 2})
- ctx.load_verify_locations(REMOTE_ROOT_CERT)
+ {'x509_ca': 0, 'crl': 0, 'x509': 1})
+ ctx.load_verify_locations(CAFILE_CACERT)
self.assertEqual(ctx.cert_store_stats(),
{'x509_ca': 1, 'crl': 0, 'x509': 2})
@@ -1072,11 +1197,12 @@
#
# see this sample code on how we might be able to decode:
# https://svn.apache.org/repos/asf/cxf/tags/cxf-2.4.4/distribution/src/main/release/samples/sts_issue_operation/src/main/java/demo/sts/provider/cert/CRLVerifier.java
+ # Subject and issuer ordering also differs vs CPython 2.7 latest
with open(CAFILE_CACERT) as f:
pem = f.read()
- der = ssl.PEM_cert_to_DER_cert(pem)
- self.assertEqual(ctx.get_ca_certs(True), [der])
+ 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)
@@ -1094,13 +1220,14 @@
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:
env["SSL_CERT_DIR"] = CAPATH
env["SSL_CERT_FILE"] = CERTFILE
ctx.load_default_certs()
- self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 4, "x509_ca": 0})
+ self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0})
@unittest.skipUnless(sys.platform == "win32", "Windows specific")
def test_load_default_certs_env_windows(self):
@@ -1116,16 +1243,29 @@
stats["x509"] += 1
self.assertEqual(ctx.cert_store_stats(), stats)
+ def _assert_context_options(self, ctx):
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
+ if OP_NO_COMPRESSION != 0:
+ self.assertEqual(ctx.options & OP_NO_COMPRESSION,
+ OP_NO_COMPRESSION)
+ if OP_SINGLE_DH_USE != 0:
+ self.assertEqual(ctx.options & OP_SINGLE_DH_USE,
+ OP_SINGLE_DH_USE)
+ if OP_SINGLE_ECDH_USE != 0:
+ self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE,
+ OP_SINGLE_ECDH_USE)
+ if OP_CIPHER_SERVER_PREFERENCE != 0:
+ self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE,
+ OP_CIPHER_SERVER_PREFERENCE)
+
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),
- # )
+ self._assert_context_options(ctx)
+
with open(SIGNING_CA) as f:
cadata = f.read().decode("ascii")
@@ -1133,40 +1273,24 @@
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),
- # )
+ self._assert_context_options(ctx)
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),
- # )
+ self._assert_context_options(ctx)
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)
+ self._assert_context_options(ctx)
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)
+ self._assert_context_options(ctx)
ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1,
cert_reqs=ssl.CERT_REQUIRED,
@@ -1174,12 +1298,63 @@
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)
+ self._assert_context_options(ctx)
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)
+ self._assert_context_options(ctx)
+
+ def test__https_verify_certificates(self):
+ # Unit test to check the contect factory mapping
+ # The factories themselves are tested above
+ # This test will fail by design if run under PYTHONHTTPSVERIFY=0
+ # (as will various test_httplib tests)
+
+ # Uses a fresh SSL module to avoid affecting the real one
+ local_ssl = support.import_fresh_module("ssl")
+ # Certificate verification is enabled by default
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl.create_default_context)
+ # Turn default verification off
+ local_ssl._https_verify_certificates(enable=False)
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl._create_unverified_context)
+ # And back on
+ local_ssl._https_verify_certificates(enable=True)
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl.create_default_context)
+ # The default behaviour is to enable
+ local_ssl._https_verify_certificates(enable=False)
+ local_ssl._https_verify_certificates()
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl.create_default_context)
+
+ def test__https_verify_envvar(self):
+ # Unit test to check the PYTHONHTTPSVERIFY handling
+ # Need to use a subprocess so it can still be run under -E
+ https_is_verified = """import ssl, sys; \
+ status = "Error: _create_default_https_context does not verify certs" \
+ if ssl._create_default_https_context is \
+ ssl._create_unverified_context \
+ else None; \
+ sys.exit(status)"""
+ https_is_not_verified = """import ssl, sys; \
+ status = "Error: _create_default_https_context verifies certs" \
+ if ssl._create_default_https_context is \
+ ssl.create_default_context \
+ else None; \
+ sys.exit(status)"""
+ extra_env = {}
+ # Omitting it leaves verification on
+ assert_python_ok("-c", https_is_verified, **extra_env)
+ # Setting it to zero turns verification off
+ extra_env[ssl._https_verify_envvar] = "0"
+ assert_python_ok("-c", https_is_not_verified, **extra_env)
+ # Any other value should also leave it on
+ for setting in ("", "1", "enabled", "foo"):
+ extra_env[ssl._https_verify_envvar] = setting
+ assert_python_ok("-c", https_is_verified, **extra_env)
def test_check_hostname(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
@@ -1209,14 +1384,13 @@
def test_str(self):
# The str() of a SSLError doesn't include the errno
e = ssl.SSLError(1, "foo")
- self.assertIn("foo", str(e))
+ self.assertEqual(str(e), "foo")
self.assertEqual(e.errno, 1)
# Same for a subclass
e = ssl.SSLZeroReturnError(1, "foo")
- self.assertIn("foo", str(e))
+ self.assertEqual(str(e), "foo")
self.assertEqual(e.errno, 1)
- @unittest.skipIf(support.is_jython, "TODO")
def test_lib_reason(self):
# Test the library and reason attributes
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
@@ -1227,7 +1401,6 @@
s = str(cm.exception)
self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s)
- @unittest.skipIf(support.is_jython, "TODO")
def test_subclass(self):
# Check that the appropriate SSLError subclass is raised
# (this only tests one of them)
@@ -1283,7 +1456,7 @@
cert_reqs=ssl.CERT_REQUIRED,
ca_certs=REMOTE_ROOT_CERT)
try:
- self.assertEqual(errno.EISCONN, s.connect_ex((REMOTE_HOST, 443)))
+ self.assertEqual(0, s.connect_ex((REMOTE_HOST, 443)))
self.assertTrue(s.getpeercert())
finally:
s.close()
@@ -1300,8 +1473,7 @@
s.setblocking(False)
rc = s.connect_ex((REMOTE_HOST, 443))
# EWOULDBLOCK under Windows, EINPROGRESS elsewhere
- # Jython added EALREADY, as in Jython connect may have already happened
- self.assertIn(rc, (0, errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK))
+ self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
# Wait for connect to finish
select.select([], [s], [], 5.0)
# Non-blocking handshake
@@ -1314,7 +1486,7 @@
except ssl.SSLWantWriteError:
select.select([], [s], [], 5.0)
# SSL established
- #self.assertTrue(s.getpeercert())
+ self.assertTrue(s.getpeercert())
finally:
s.close()
@@ -1329,9 +1501,9 @@
try:
s.settimeout(0.0000001)
rc = s.connect_ex((REMOTE_HOST, 443))
- if rc == errno.EISCONN:
+ if rc == 0:
self.skipTest("REMOTE_HOST responded too quickly")
- self.assertIn(rc, (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK))
+ self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
finally:
s.close()
@@ -1434,7 +1606,6 @@
cert = s.getpeercert()
self.assertTrue(cert)
- @unittest.skipIf(support.is_jython, "Can't use a socket as a file under Jython")
@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
@@ -1493,7 +1664,6 @@
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:
@@ -1505,7 +1675,6 @@
if support.IPV6_ENABLED:
_test_get_server_certificate('ipv6.google.com', 443)
- @unittest.skipIf(support.is_jython, "Currently not supported")
def test_ciphers(self):
remote = (REMOTE_HOST, 443)
with support.transient_internet(remote[0]):
@@ -1522,35 +1691,6 @@
cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
s.connect(remote)
- def test_algorithms(self):
- # Issue #8484: all algorithms should be available when verifying a
- # certificate.
- # 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)
- # sha256.tbs-internet.com needs SNI to use the correct certificate
- if not ssl.HAS_SNI or support.is_jython: # sha256.tbs-internet.com is no longer alive
- 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 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 support.verbose:
- sys.stdout.write("\nCipher with %r is %r\n" %
- (remote, s.cipher()))
- sys.stdout.write("Certificate is:\n%s\n" %
- pprint.pformat(s.getpeercert()))
- finally:
- s.close()
-
- @unittest.skipIf(support.is_jython, "On jython preloaded TODO")
def test_get_ca_certs_capath(self):
# capath certs are loaded on request
with support.transient_internet(REMOTE_HOST):
@@ -1565,7 +1705,7 @@
self.assertTrue(cert)
finally:
s.close()
- self.assertEqual(len(ctx.get_ca_certs()), 3)
+ self.assertEqual(len(ctx.get_ca_certs()), 1)
@needs_sni
def test_context_setget(self):
@@ -1586,9 +1726,7 @@
import threading
except ImportError:
_have_threads = False
-
-_have_threads = False
-if _have_threads: # Jython skip threading tests for now, really don't work :(
+else:
_have_threads = True
from test.ssl_servers import make_https_server
@@ -1617,23 +1755,43 @@
self.sock, server_side=True)
self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
- except socket.error as e:
- # We treat ConnectionResetError as though it were an
- # SSLError - OpenSSL on Ubuntu abruptly closes the
- # connection when asked to use an unsupported protocol.
- #
- # XXX Various errors can have happened here, for example
- # a mismatching protocol version, an invalid certificate,
- # or a low-level bug. This should be made more discriminating.
- if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET:
- raise
- self.server.conn_errors.append(e)
- if self.server.chatty:
- handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
- self.running = False
- self.server.stop()
- self.close()
- return False
+ except (ssl.SSLError, socket.error, OSError) as e:
+ if e.errno in (errno.ECONNRESET, errno.EPIPE, errno.ESHUTDOWN):
+ # Mimick Python 3:
+ #
+ # except (ConnectionResetError, BrokenPipeError):
+ #
+ # We treat ConnectionResetError as though it were an
+ # SSLError - OpenSSL on Ubuntu abruptly closes the
+ # connection when asked to use an unsupported protocol.
+ #
+ # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
+ # tries to send session tickets after handshake.
+ # https://github.com/openssl/openssl/issues/6342
+ self.server.conn_errors.append(str(e))
+ if self.server.chatty:
+ handle_error(
+ "\n server: bad connection attempt from "
+ + repr(self.addr) + ":\n")
+ self.running = False
+ self.close()
+ return False
+ else:
+ # OSError may occur with wrong protocols, e.g. both
+ # sides use PROTOCOL_TLS_SERVER.
+ #
+ # XXX Various errors can have happened here, for example
+ # a mismatching protocol version, an invalid certificate,
+ # or a low-level bug. This should be made more discriminating.
+ if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET:
+ raise
+ self.server.conn_errors.append(e)
+ if self.server.chatty:
+ handle_error("\n server: bad connection attempt from " + 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()
@@ -1732,7 +1890,7 @@
else:
self.context = ssl.SSLContext(ssl_version
if ssl_version is not None
- else ssl.PROTOCOL_TLSv1)
+ else ssl.PROTOCOL_TLS)
self.context.verify_mode = (certreqs if certreqs is not None
else ssl.CERT_NONE)
if cacerts:
@@ -1892,6 +2050,8 @@
self.join()
if support.verbose:
sys.stdout.write(" cleanup: successfully joined.\n")
+ # make sure that ConnectionHandler is removed from socket_map
+ asyncore.close_all(ignore_all=True)
def start(self, flag=None):
self.flag = flag
@@ -1911,36 +2071,6 @@
self.active = False
self.server.close()
- def bad_cert_test(certfile):
- """
- Launch a server with CERT_REQUIRED, and check that trying to
- connect to it with the given client certificate fails.
- """
- server = ThreadedEchoServer(CERTFILE,
- certreqs=ssl.CERT_REQUIRED,
- cacerts=CERTFILE, chatty=False,
- connectionchatty=False)
- with server:
- try:
- 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(client_context, server_context, indata=b"FOO\n",
chatty=True, connectionchatty=False, sni_name=None):
"""
@@ -2179,22 +2309,38 @@
"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,
- "nullcert.pem"))
- def test_malformed_cert(self):
- """Connecting with a badly formatted certificate (syntax error)"""
- bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
- "badcert.pem"))
- def test_nonexisting_cert(self):
- """Connecting with a non-existing cert file"""
- bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
- "wrongcert.pem"))
- def test_malformed_key(self):
- """Connecting with a badly formatted key (syntax error)"""
- bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
- "badkey.pem"))
+ def test_wrong_cert(self):
+ """Connecting when the server rejects the client's certificate
+
+ Launch a server with CERT_REQUIRED, and check that trying to
+ connect to it with a wrong client certificate fails.
+ """
+ certfile = os.path.join(os.path.dirname(__file__) or os.curdir,
+ "keycert.pem")
+ server = ThreadedEchoServer(SIGNED_CERTFILE,
+ certreqs=ssl.CERT_REQUIRED,
+ cacerts=SIGNING_CA, chatty=False,
+ connectionchatty=False)
+ with server, \
+ closing(socket.socket()) as sock, \
+ closing(ssl.wrap_socket(sock,
+ certfile=certfile,
+ ssl_version=ssl.PROTOCOL_TLSv1)) as s:
+ try:
+ # Expect either an SSL error about the server rejecting
+ # the connection, or a low-level connection reset (which
+ # sometimes happens on Windows)
+ s.connect((HOST, server.port))
+ except ssl.SSLError as e:
+ if support.verbose:
+ sys.stdout.write("\nSSLError is %r\n" % e)
+ except socket.error as e:
+ if e.errno != errno.ECONNRESET:
+ raise
+ if support.verbose:
+ sys.stdout.write("\nsocket.error is %r\n" % e)
+ else:
+ self.fail("Use of invalid cert should have failed!")
def test_rude_shutdown(self):
"""A brutal shutdown of an SSL server should raise an OSError
@@ -2261,6 +2407,7 @@
client_options=ssl.OP_NO_TLSv1)
@skip_if_broken_ubuntu_ssl
+ @skip_if_openssl_cnf_minprotocol_gt_tls1
def test_protocol_sslv23(self):
"""Connecting to an SSLv23 server with various client options"""
if support.verbose:
@@ -2338,6 +2485,7 @@
@skip_if_broken_ubuntu_ssl
@unittest.skipUnless(hasattr(ssl, "PROTOCOL_TLSv1_1"),
"TLS version 1.1 not supported.")
+ @skip_if_openssl_cnf_minprotocol_gt_tls1
def test_protocol_tlsv1_1(self):
"""Connecting to a TLSv1.1 server with various client options.
Testing against older TLS versions."""
@@ -2466,8 +2614,6 @@
def test_asyncore_server(self):
"""Check the example asyncore integration."""
- indata = "TEST MESSAGE of mixed case\n"
-
if support.verbose:
sys.stdout.write("\n")
@@ -2599,9 +2745,41 @@
# consume data
s.read()
+ # 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)
+
+ self.assertRaises(NotImplementedError, s.dup)
s.write(b"over\n")
+
+ self.assertRaises(ValueError, s.recv, -1)
+ self.assertRaises(ValueError, s.read, -1)
+
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_handshake_timeout(self):
# Issue #5103: SSL handshake must respect the socket timeout
server = socket.socket(socket.AF_INET)
@@ -2671,7 +2849,7 @@
# Block on the accept and wait on the connection to close.
evt.set()
remote[0], peer[0] = server.accept()
- remote[0].recv(1)
+ remote[0].send(remote[0].recv(4))
t = threading.Thread(target=serve)
t.start()
@@ -2679,6 +2857,8 @@
evt.wait()
client = context.wrap_socket(socket.socket())
client.connect((host, port))
+ client.send(b'data')
+ client.recv()
client_addr = client.getsockname()
client.close()
t.join()
@@ -2702,19 +2882,24 @@
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:
- with closing(context.wrap_socket(socket.socket())) as s:
- with self.assertRaises(ssl.SSLError):
- s.connect((HOST, server.port))
+ def test_no_shared_ciphers(self):
+ server_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ server_context.load_cert_chain(SIGNED_CERTFILE)
+ client_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ client_context.verify_mode = ssl.CERT_REQUIRED
+ client_context.check_hostname = True
+
+ # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test
+ client_context.options |= ssl.OP_NO_TLSv1_3
+ # Force different suites on client and master
+ client_context.set_ciphers("AES128")
+ server_context.set_ciphers("AES256")
+ with ThreadedEchoServer(context=server_context) as server:
+ s = client_context.wrap_socket(
+ socket.socket(),
+ server_hostname="localhost")
+ with self.assertRaises(ssl.SSLError):
+ s.connect((HOST, server.port))
self.assertIn("no shared cipher", str(server.conn_errors[0]))
def test_version_basic(self):
@@ -2729,15 +2914,37 @@
with closing(context.wrap_socket(socket.socket())) as s:
self.assertIs(s.version(), None)
s.connect((HOST, server.port))
- self.assertEqual(s.version(), "TLSv1")
+ self.assertEqual(s.version(), 'TLSv1')
self.assertIs(s.version(), None)
+ @unittest.skipUnless(ssl.HAS_TLSv1_3,
+ "test requires TLSv1.3 enabled OpenSSL")
+ def test_tls1_3(self):
+ context = ssl.SSLContext(ssl.PROTOCOL_TLS)
+ context.load_cert_chain(CERTFILE)
+ # disable all but TLS 1.3
+ context.options |= (
+ ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2
+ )
+ with ThreadedEchoServer(context=context) as server:
+ s = context.wrap_socket(socket.socket())
+ with closing(s):
+ s.connect((HOST, server.port))
+ self.assertIn(s.cipher()[0], [
+ 'TLS_AES_256_GCM_SHA384',
+ 'TLS_CHACHA20_POLY1305_SHA256',
+ 'TLS_AES_128_GCM_SHA256',
+ ])
+
@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)
+ # TLSv1.3 defaults to PFS key agreement and no longer has KEA in
+ # cipher name.
+ context.options |= ssl.OP_NO_TLSv1_3
# 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
@@ -2871,24 +3078,37 @@
(['http/3.0', 'http/4.0'], None)
]
for client_protocols, expected in protocol_tests:
- server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
server_context.load_cert_chain(CERTFILE)
server_context.set_alpn_protocols(server_protocols)
- client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
client_context.load_cert_chain(CERTFILE)
client_context.set_alpn_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_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"))
+
+ 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
+ and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)):
+ # OpenSSL 1.1.0 to 1.1.0e 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"))
def test_selected_npn_protocol(self):
# selected_npn_protocol() is None unless NPN is used
@@ -3046,8 +3266,9 @@
self.assertRaises(ValueError, s.write, b'hello')
-def test_main(verbose=False):
- if support.verbose:
+
+def test_main(verbose=False,tests=[]):
+ if verbose or support.verbose:
plats = {
'Linux': platform.linux_distribution,
'Mac': platform.mac_ver,
@@ -3078,20 +3299,22 @@
if not os.path.exists(filename):
raise support.TestFailed("Can't read certificate file %r" % filename)
- tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests]
-
- if support.is_resource_enabled('network'):
- tests.append(NetworkedTests)
-
- if _have_threads:
- thread_info = support.threading_setup()
- if thread_info:
- tests.append(ThreadedTests)
+ used_threads = False
+ if not tests:
+ tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests]
+ if support.is_resource_enabled('network'):
+ tests.append(NetworkedTests)
+
+ if _have_threads:
+ used_threads = True
+ thread_info = support.threading_setup()
+ if thread_info:
+ tests.append(ThreadedTests)
try:
support.run_unittest(*tests)
finally:
- if _have_threads:
+ if used_threads:
support.threading_cleanup(*thread_info)
if __name__ == "__main__":
diff --git a/Lib/test/test_ssl_jy.py b/Lib/test/test_ssl_jy.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_ssl_jy.py
@@ -0,0 +1,231 @@
+# Jython variations on the test_ssl tests are concentrated here, where possible
+# Due to the structure of the module, some functions still have to be modified
+# directly in the original, but this reduces the diff and ongoing merge effort
+
+import errno
+import select
+import socket
+import ssl
+import sys
+import unittest
+import test.test_ssl
+from test.test_ssl import BasicTests
+from test.test_ssl import can_clear_options, support, skip_if_broken_ubuntu_ssl
+from test.test_ssl import CAPATH, CERTFILE, CAFILE_CACERT
+from test.test_ssl import REMOTE_HOST, REMOTE_ROOT_CERT
+
+
+
+class BasicSocketTests(test.test_ssl.BasicSocketTests):
+ @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten")
+ def test_parse_cert(self):
+ None
+
+ @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten")
+ def test_parse_cert_CVE_2013_4238(self):
+ None
+
+ @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten")
+ def test_parse_cert_CVE_2019_5010(self):
+ None
+
+ @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten")
+ def test_parse_all_sans(self):
+ None
+
+ def test_asn1object(self):
+ # Abbreviated version of parent test up to unsupported part
+ # TODO Jython better asn1 support, though not sure there's much use for
+ # it
+ 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')
+
+
+class ContextTests(test.test_ssl.ContextTests):
+ @unittest.skip("Currently not supported")
+ def test_ciphers(self):
+ None
+
+ @skip_if_broken_ubuntu_ssl
+ def test_options(self):
+ # new default options in later 2.7 versions not yet supported
+ # See CPython b8eaec697a2b5d9d2def2950a0aa50e8ffcf1059
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
+ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3,
+ ctx.options)
+ ctx.options |= ssl.OP_NO_TLSv1
+ 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_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
+
+ @unittest.skip("Not yet supported on Jython")
+ def test_load_dh_params(self):
+ 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})
+ # Jython x509 will grow by 1 while openssl remains 0
+ # TODO investgate deeper
+ ctx.load_cert_chain(CERTFILE)
+ self.assertEqual(ctx.cert_store_stats(),
+ {'x509_ca': 0, 'crl': 0, 'x509': 1})
+ ctx.load_verify_locations(CERTFILE)
+ self.assertEqual(ctx.cert_store_stats(),
+ {'x509_ca': 0, 'crl': 0, 'x509': 2})
+ ctx.load_verify_locations(CAFILE_CACERT)
+ self.assertEqual(ctx.cert_store_stats(),
+ {'x509_ca': 1, 'crl': 0, 'x509': 2})
+
+ @unittest.skipIf(sys.platform == "win32", "not-Windows specific")
+ def test_load_default_certs_env(self):
+ # Store behaviour differs from CPython so different stats
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ with support.EnvironmentVarGuard() as env:
+ env["SSL_CERT_DIR"] = CAPATH
+ env["SSL_CERT_FILE"] = CERTFILE
+ ctx.load_default_certs()
+ self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 5, "x509_ca": 0})
+
+ def _assert_context_options(self, ctx):
+ self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
+ # Jython doesn't support OP_NO_COMPRESSION, OP_SINGLE_DH_USE
+ # OP_SINGLE_ECDH_USE, OP_CIPHER_SERVER_PREFERENCE
+
+ @unittest.skip("Jython not using ssl.__https_verify_certificates ")
+ def test__https_verify_certificates(self):
+ None
+
+ @unittest.skip("Jython not using ssl._https_verify_envvar ")
+ def test__https_verify_envvar(self):
+ None
+
+
+class SSLErrorTests(test.test_ssl.SSLErrorTests):
+ def test_str(self):
+ # Different error strings for Jython
+ # The str() of a SSLError doesn't include the errno
+ e = ssl.SSLError(1, "foo")
+ self.assertIn("foo", str(e))
+ self.assertEqual(e.errno, 1)
+ # Same for a subclass
+ e = ssl.SSLZeroReturnError(1, "foo")
+ self.assertIn("foo", str(e))
+ self.assertEqual(e.errno, 1)
+
+ @unittest.skip("Jython TODO")
+ def test_lib_reason(self):
+ None
+
+ @unittest.skip("Jython TODO")
+ def test_subclass(self):
+ None
+
+
+class NetworkedTests(test.test_ssl.NetworkedTests):
+ def test_connect_ex(self):
+ # Issue #11326: check connect_ex() implementation
+ with support.transient_internet(REMOTE_HOST):
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=REMOTE_ROOT_CERT)
+ try:
+ # Jython, errno.EISCONN expected per earlier 2.x versions, not 0
+ self.assertEqual(errno.EISCONN, s.connect_ex((REMOTE_HOST, 443)))
+ self.assertTrue(s.getpeercert())
+ finally:
+ s.close()
+
+ def test_non_blocking_connect_ex(self):
+ # Issue #11326: non-blocking connect_ex() should allow handshake
+ # to proceed after the socket gets ready.
+ # Jython behaviour varies
+ with support.transient_internet(REMOTE_HOST):
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=REMOTE_ROOT_CERT,
+ do_handshake_on_connect=False)
+ try:
+ s.setblocking(False)
+ rc = s.connect_ex((REMOTE_HOST, 443))
+ # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
+ # Jython added EALREADY, as in Jython connect may have already happened
+ self.assertIn(rc, (0, errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK))
+ # Wait for connect to finish
+ select.select([], [s], [], 5.0)
+ # Non-blocking handshake
+ while True:
+ try:
+ s.do_handshake()
+ break
+ except ssl.SSLWantReadError:
+ select.select([s], [], [], 5.0)
+ except ssl.SSLWantWriteError:
+ select.select([], [s], [], 5.0)
+ # SSL established - not in Jython
+ #self.assertTrue(s.getpeercert())
+ finally:
+ s.close()
+
+ 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).
+ # Jython follows earlier 2.x behaviour of errno.EISCONN
+ # it also allows errno.TIMEDOUT
+ with support.transient_internet(REMOTE_HOST):
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=REMOTE_ROOT_CERT,
+ do_handshake_on_connect=False)
+ try:
+ s.settimeout(0.0000001)
+ rc = s.connect_ex((REMOTE_HOST, 443))
+ if rc == errno.EISCONN:
+ self.skipTest("REMOTE_HOST responded too quickly")
+ self.assertIn(rc, (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK))
+ finally:
+ s.close()
+
+ @unittest.skip("Can't use a socket as a file under Jython")
+ def test_makefile_close(self):
+ None
+
+ @unittest.skip("Currently not supported")
+ def test_ciphers(self):
+ None
+
+ @unittest.skip("On jython preloaded TODO")
+ def test_get_ca_certs_capath(self):
+ None
+
+
+def test_main(verbose=False):
+ tests=[ContextTests, BasicTests, BasicSocketTests, SSLErrorTests]
+ if support.is_resource_enabled('network'):
+ tests.append(NetworkedTests)
+ # Jython skip threading tests for now, really don't work :(
+ test.test_ssl.test_main(verbose, tests)
+
+
+if __name__ == "__main__":
+ test_main()
+
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@
Development tip
Bugs fixed
+ - [ 2774 ] test_ssl failures from weak certificate
- [ 2768 ] Allow bytearray + and += to accept buffer protocol objects
- [ 2742 ] JARs for bouncycastle out of date (upgrade to 1.16)
- [ 2762 ] Upgrade Apache commons-compress to 1.18
diff --git a/lib-python/2.7/test/selfsigned_pythontestdotnet.pem b/lib-python/2.7/test/selfsigned_pythontestdotnet.pem
new file mode 100644
--- /dev/null
+++ b/lib-python/2.7/test/selfsigned_pythontestdotnet.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF9zCCA9+gAwIBAgIUH98b4Fw/DyugC9cV7VK7ZODzHsIwDQYJKoZIhvcNAQEL
+BQAwgYoxCzAJBgNVBAYTAlhZMRcwFQYDVQQIDA5DYXN0bGUgQW50aHJheDEYMBYG
+A1UEBwwPQXJndW1lbnQgQ2xpbmljMSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0aG9udGVzdC5uZXQw
+HhcNMTkwNTA4MDEwMjQzWhcNMjcwNzI0MDEwMjQzWjCBijELMAkGA1UEBhMCWFkx
+FzAVBgNVBAgMDkNhc3RsZSBBbnRocmF4MRgwFgYDVQQHDA9Bcmd1bWVudCBDbGlu
+aWMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQD
+DBpzZWxmLXNpZ25lZC5weXRob250ZXN0Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMKdJlyCThkahwoBb7pl5q64Pe9Fn5jrIvzsveHTc97TpjV2
+RLfICnXKrltPk/ohkVl6K5SUZQZwMVzFubkyxE0nZPHYHlpiKWQxbsYVkYv01rix
+IFdLvaxxbGYke2jwQao31s4o61AdlsfK1SdpHQUynBBMssqI3SB4XPmcA7e+wEEx
+jxjVish4ixA1vuIZOx8yibu+CFCf/geEjoBMF3QPdzULzlrCSw8k/45iZCSoNbvK
+DoL4TVV07PHOxpheDh8ZQmepGvU6pVqhb9m4lgmV0OGWHgozd5Ur9CbTVDmxIEz3
+TSoRtNJK7qtyZdGNqwjksQxgZTjM/d/Lm/BJG99AiOmYOjsl9gbQMZgvQmMAtUsI
+aMJnQuZ6R+KEpW/TR5qSKLWZSG45z/op+tzI2m+cE6HwTRVAWbcuJxcAA55MZjqU
+OOOu3BBYMjS5nf2sQ9uoXsVBFH7i0mQqoW1SLzr9opI8KsWwFxQmO2vBxWYaN+lH
+OmwBZBwyODIsmI1YGXmTp09NxRYz3Qe5GCgFzYowpMrcxUC24iduIdMwwhRM7rKg
+7GtIWMSrFfuI1XCLRmSlhDbhNN6fVg2f8Bo9PdH9ihiIyxSrc+FOUasUYCCJvlSZ
+8hFUlLvcmrZlWuazohm0lsXuMK1JflmQr/DA/uXxP9xzFfRy+RU3jDyxJbRHAgMB
+AAGjUzBRMB0GA1UdDgQWBBSQJyxiPMRK01i+0BsV9zUwDiBaHzAfBgNVHSMEGDAW
+gBSQJyxiPMRK01i+0BsV9zUwDiBaHzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4ICAQCR+7a7N/m+WLkxPPIA/CB4MOr2Uf8ixTv435Nyv6rXOun0+lTP
+ExSZ0uYQ+L0WylItI3cQHULldDueD+s8TGzxf5woaLKf6tqyr0NYhKs+UeNEzDnN
+9PHQIhX0SZw3XyXGUgPNBfRCg2ZDdtMMdOU4XlQN/IN/9hbYTrueyY7eXq9hmtI9
+1srftAMqr9SR1JP7aHI6DVgrEsZVMTDnfT8WmLSGLlY1HmGfdEn1Ip5sbo9uSkiH
+AEPgPfjYIvR5LqTOMn4KsrlZyBbFIDh9Sl99M1kZzgH6zUGVLCDg1y6Cms69fx/e
+W1HoIeVkY4b4TY7Bk7JsqyNhIuqu7ARaxkdaZWhYaA2YyknwANdFfNpfH+elCLIk
+BUt5S3f4i7DaUePTvKukCZiCq4Oyln7RcOn5If73wCeLB/ZM9Ei1HforyLWP1CN8
+XLfpHaoeoPSWIveI0XHUl65LsPN2UbMbul/F23hwl+h8+BLmyAS680Yhn4zEN6Ku
+B7Po90HoFa1Du3bmx4jsN73UkT/dwMTi6K072FbipnC1904oGlWmLwvAHvrtxxmL
+Pl3pvEaZIu8wa/PNF6Y7J7VIewikIJq6Ta6FrWeFfzMWOj2qA1ZZi6fUaDSNYvuV
+J5quYKCc/O+I/yDDf8wyBbZ/gvUXzUHTMYGG+bFrn1p7XDbYYeEJ6R/xEg==
+-----END CERTIFICATE-----
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list