diff --git a/Src/IronPython.Modules/_ssl.cs b/Src/IronPython.Modules/_ssl.cs index f3bdf88cc..42918c616 100644 --- a/Src/IronPython.Modules/_ssl.cs +++ b/Src/IronPython.Modules/_ssl.cs @@ -14,6 +14,7 @@ using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Security.Authentication; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -113,6 +114,7 @@ public static void RAND_add(object buf, double entropy) { public class _SSLContext { internal readonly X509Certificate2Collection _cert_store = new X509Certificate2Collection(); internal string _cafile; + internal X509Certificate2 _cert; private int _verify_mode = SSL_VERIFY_NONE; public _SSLContext(CodeContext context, int protocol) { @@ -148,6 +150,10 @@ public int verify_mode { if (_verify_mode != CERT_NONE && _verify_mode != CERT_OPTIONAL && _verify_mode != CERT_REQUIRED) { throw PythonOps.ValueError("invalid value for verify_mode"); } + // TODO: change this in 3.7 + if (check_hostname && value == CERT_NONE) { + throw PythonOps.ValueError("Cannot set verify_mode to CERT_NONE when check_hostname is enabled."); + } _verify_mode = value; } } @@ -156,8 +162,16 @@ public int protocol { get; set; } + private bool _check_hostname; public bool check_hostname { - get; set; + get => _check_hostname; + set { + // TODO: change this in 3.7 + if (value && _verify_mode != CERT_OPTIONAL && _verify_mode != CERT_REQUIRED) { + throw PythonOps.ValueError("check_hostname needs a SSL context with either CERT_OPTIONAL or CERT_REQUIRED"); + } + _check_hostname = value; + } } public void set_default_verify_paths(CodeContext context) { @@ -174,8 +188,19 @@ public void set_ecdh_curve(CodeContext context, [NotNull] Bytes curve) { throw PythonOps.ValueError($"unknown elliptic curve name {PythonOps.Repr(context, curve)}"); } - public void load_cert_chain(string certfile, string keyfile = null, object password = null) { + public void load_cert_chain(CodeContext context, string certfile, string keyfile = null, object password = null) { + if (keyfile is not null) throw new NotImplementedException(nameof(keyfile)); + if (password is not null) throw new NotImplementedException(nameof(password)); +#if NET5_0_OR_GREATER + _cert = X509Certificate2.CreateFromPemFile(certfile, keyfile); +#else + _cert = ReadCertificate(context, certfile, readKey: true); +#endif + } + public PythonList get_ca_certs(CodeContext context, bool binary_form = false) { + if (binary_form) throw new NotImplementedException(nameof(binary_form)); + return new PythonList(_cert_store.Cast().Select(c => CertificateToPython(context, c))); } public void load_verify_locations(CodeContext context, object cafile = null, string capath = null, object cadata = null) { @@ -199,23 +224,38 @@ public void load_verify_locations(CodeContext context, object cafile = null, str } if (capath != null) { + // TODO } - if (cadata != null) { - var cabuf = cadata as IBufferProtocol; - if (cabuf != null) { - int pos = 0; - byte[] contents; - using (IPythonBuffer buf = cabuf.GetBuffer()) { - contents = buf.AsReadOnlySpan().ToArray(); - } - while (pos < contents.Length) { - byte[] curr = new byte[contents.Length - pos]; - Array.Copy(contents, pos, curr, 0, contents.Length - pos); - var cert = new X509Certificate2(curr); + if (cadata is not null) { + if (cadata is string s) { + if (!StringOps.TryEncodeAscii(s, out Bytes ascii)) + throw PythonOps.ValueError("cadata should be an ASCII string or a bytes-like object"); +#if NET5_0_OR_GREATER + _cert_store.ImportFromPem(s); +#else + string line; + var lines = new List(); + using var stream = new MemoryStream(ascii.UnsafeByteArray); + using var sr = new StreamReader(stream); + while ((line = sr.ReadLine()) != null) + lines.Add(line); + _cert_store.Add(ReadCertificate(context, string.Empty, lines.ToArray())); +#endif + } else if (cadata is IBufferProtocol cabuf) { + using IPythonBuffer buf = cabuf.GetBuffer(); + var contents = buf.AsReadOnlySpan(); + while (contents.Length > 0) { +#if NET5_0_OR_GREATER + var cert = new X509Certificate2(contents); +#else + var cert = new X509Certificate2(contents.ToArray()); +#endif _cert_store.Add(cert); - pos += cert.GetRawCertData().Length; + contents = contents.Slice(cert.GetRawCertData().Length); } + } else { + throw PythonOps.ValueError("cadata should be an ASCII string or a bytes-like object"); } } } @@ -230,7 +270,6 @@ public class _SSLSocket { private SslStream _sslStream; private readonly PythonSocket.socket _socket; private readonly X509Certificate2Collection _certCollection; - private readonly X509Certificate _cert; private readonly int _protocol, _certsMode; private readonly bool _validate, _serverSide; private readonly CodeContext _context; @@ -276,10 +315,6 @@ internal _SSLSocket(CodeContext context, _SSLContext sslcontext, PythonSocket.so _certCollection = sslcontext._cert_store; } - if (sslcontext._cafile != null) { - _cert = PythonSsl.ReadCertificate(context, sslcontext._cafile); - } - _socket = sock; EnsureSslStream(false); @@ -357,36 +392,23 @@ internal bool CertValidationCallbackRequired(object sender, X509Certificate cert } private void ValidateCertificate(X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { - chain = new X509Chain(); - X509Certificate2Collection certificates = new X509Certificate2Collection(); - foreach (object cert in _certCollection) { - if (cert is X509Certificate2) { - certificates.Add((X509Certificate2)cert); - } else if (cert is X509Certificate) { - certificates.Add(new X509Certificate2((X509Certificate)cert)); - } - } - chain.ChainPolicy.ExtraStore.AddRange(certificates); - chain.Build(new X509Certificate2(certificate)); - - if (chain.ChainStatus.Length > 0) { - foreach (var elem in chain.ChainStatus) { - if (elem.Status == X509ChainStatusFlags.UntrustedRoot) { - bool isOk = false; - foreach (var cert in _certCollection) { - if (certificate.Issuer == cert.Subject) { - isOk = true; - } - } - - if (isOk) { - continue; + Debug.Assert(chain.ChainStatus.Length > 0); + foreach (var elem in chain.ChainStatus) { + if (elem.Status == X509ChainStatusFlags.UntrustedRoot) { + bool isOk = false; + foreach (var cert in _certCollection) { + if (certificate.Issuer == cert.Subject) { + isOk = true; } } - ValidationError(sslPolicyErrors); - break; + if (isOk) { + continue; + } } + + ValidationError(sslPolicyErrors); + break; } } @@ -411,15 +433,13 @@ public void do_handshake() { try { if (_serverSide) { + var _cert = context._cert; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { + _cert = new X509Certificate2(_cert.Export(X509ContentType.Pkcs12)); + } _sslStream.AuthenticateAsServer(_cert, _certsMode == PythonSsl.CERT_REQUIRED, enabledSslProtocols, false); } else { - - var collection = new X509CertificateCollection(); - - if (_cert != null) { - collection.Add(_cert); - } - _sslStream.AuthenticateAsClient(_serverHostName ?? _socket._hostName, collection, enabledSslProtocols, false); + _sslStream.AuthenticateAsClient(_serverHostName ?? _socket._hostName, context._cert_store, enabledSslProtocols, false); } } catch (AuthenticationException e) { ((IDisposable)_socket._socket).Dispose(); @@ -500,6 +520,8 @@ public PythonTuple cipher() { return null; } + public object compression() => null; // TODO + private string ProtocolToPython() { switch (_sslStream.SslProtocol) { #pragma warning disable CA5397 // Do not use deprecated SslProtocols values @@ -592,13 +614,20 @@ public string server() { [Documentation(@"Writes the bytes-like object b into the SSL object. Returns the number of bytes written.")] - public int write(CodeContext/*!*/ context, Bytes data) { + public int write(CodeContext/*!*/ context, IBufferProtocol data) { EnsureSslStream(true); - byte[] buffer = data.UnsafeByteArray; + using var buffer = data.GetBuffer(); try { - _sslStream.Write(buffer); - return buffer.Length; +#if NETCOREAPP + var bytes = buffer.AsReadOnlySpan(); + _sslStream.Write(bytes); + return bytes.Length; +#else + var bytes = buffer.AsUnsafeArray() ?? buffer.ToArray(); + _sslStream.Write(bytes); + return bytes.Length; +#endif } catch (Exception e) { throw PythonSocket.MakeException(context, e); } @@ -921,6 +950,10 @@ private static X509Certificate2 ReadCertificate(CodeContext context, string file throw PythonExceptions.CreateThrowable(SSLError(context), "Can't open file ", filename); } + return ReadCertificate(context, filename, lines, readKey); + } + + private static X509Certificate2 ReadCertificate(CodeContext context, string filename, string[] lines, bool readKey = false) { X509Certificate2 cert = null; RSACryptoServiceProvider key = null; try { @@ -945,6 +978,16 @@ private static X509Certificate2 ReadCertificate(CodeContext context, string file throw ErrorDecoding(context, filename, e); } } + } else if (lines[i] == "-----BEGIN PRIVATE KEY-----") { + var keyStr = ReadToEnd(lines, ref i, "-----END PRIVATE KEY-----"); + if (readKey) { + try { + var keyBytes = Convert.FromBase64String(keyStr.ToString()); + // TODO + } catch (Exception e) { + throw ErrorDecoding(context, filename, e); + } + } } } } catch (InvalidOperationException e) { @@ -981,7 +1024,6 @@ private static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certifi } #endif - #region Private Key Parsing private const int ClassOffset = 6; @@ -1027,7 +1069,7 @@ private static RSACryptoServiceProvider ParsePkcs1DerEncodedPrivateKey(CodeConte int version = ReadUniversalInt(x, ref offset); if (version != 0) { // unsupported version - throw new InvalidOperationException(String.Format("bad vesion: {0}", version)); + throw new InvalidOperationException(String.Format("bad version: {0}", version)); } // read in parameters and initialize provider @@ -1071,7 +1113,7 @@ private static byte[] ReadUniversalIntAsBytes(byte[] x, ref int offset) { private static void ReadIntType(byte[] x, ref int offset) { int versionType = x[offset++]; if (versionType != UniversalInteger) { - throw new InvalidOperationException(String.Format("expected version, fonud {0}", versionType)); + throw new InvalidOperationException(String.Format("expected version, found {0}", versionType)); } } private static int ReadUniversalInt(byte[] x, ref int offset) { @@ -1134,8 +1176,8 @@ private static Exception ErrorDecoding(CodeContext context, params object[] args public const int CERT_OPTIONAL = 1; public const int CERT_REQUIRED = 2; - public const int PROTOCOL_SSLv2 = 0; - public const int PROTOCOL_SSLv3 = 1; + private const int PROTOCOL_SSLv2 = 0; + private const int PROTOCOL_SSLv3 = 1; public const int PROTOCOL_SSLv23 = 2; public const int PROTOCOL_TLSv1 = 3; public const int PROTOCOL_TLSv1_1 = 4; diff --git a/Src/StdLib/Lib/test/selfsigned_pythontestdotnet.pem b/Src/StdLib/Lib/test/selfsigned_pythontestdotnet.pem index b6d259bcb..2b1760747 100644 --- a/Src/StdLib/Lib/test/selfsigned_pythontestdotnet.pem +++ b/Src/StdLib/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/Src/StdLib/Lib/test/test_httplib.py b/Src/StdLib/Lib/test/test_httplib.py index df9a9e3cb..0d476e627 100644 --- a/Src/StdLib/Lib/test/test_httplib.py +++ b/Src/StdLib/Lib/test/test_httplib.py @@ -956,7 +956,7 @@ def test_networked_good_cert(self): import ssl support.requires('network') with support.transient_internet('self-signed.pythontest.net'): - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) context.verify_mode = ssl.CERT_REQUIRED context.load_verify_locations(CERT_selfsigned_pythontestdotnet) h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context) @@ -971,7 +971,7 @@ def test_networked_bad_cert(self): import ssl support.requires('network') with support.transient_internet('self-signed.pythontest.net'): - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) context.verify_mode = ssl.CERT_REQUIRED context.load_verify_locations(CERT_localhost) h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context) diff --git a/Tests/modules/network_related/test__ssl.py b/Tests/modules/network_related/test__ssl.py index ff15a4287..1d15e2b68 100644 --- a/Tests/modules/network_related/test__ssl.py +++ b/Tests/modules/network_related/test__ssl.py @@ -28,12 +28,12 @@ def test_constants(self): self.assertEqual(_ssl.CERT_NONE, 0) self.assertEqual(_ssl.CERT_OPTIONAL, 1) self.assertEqual(_ssl.CERT_REQUIRED, 2) - if sys.version_info >= (3,5): + if is_cli or sys.version_info >= (3,5): self.assertRaises(AttributeError, lambda: _ssl.PROTOCOL_SSLv2) else: self.assertEqual(_ssl.PROTOCOL_SSLv2, 0) self.assertEqual(_ssl.PROTOCOL_SSLv23, 2) - if sys.version_info >= (3,7): + if is_cli or sys.version_info >= (3,7): self.assertRaises(AttributeError, lambda: _ssl.PROTOCOL_SSLv3) else: self.assertEqual(_ssl.PROTOCOL_SSLv3, 1) diff --git a/Tests/test_httplib_stdlib.py b/Tests/test_httplib_stdlib.py index 487cbf40d..d392ca7ca 100644 --- a/Tests/test_httplib_stdlib.py +++ b/Tests/test_httplib_stdlib.py @@ -59,7 +59,7 @@ def load_tests(loader, standard_tests, pattern): #suite.addTest(test.test_httplib.HTTPSTest('test_local_unknown_cert')) # StackOverflowException suite.addTest(unittest.expectedFailure(test.test_httplib.HTTPSTest('test_networked'))) # AttributeError: 'SSLError' object has no attribute 'reason' suite.addTest(unittest.expectedFailure(test.test_httplib.HTTPSTest('test_networked_bad_cert'))) # AttributeError: 'SSLError' object has no attribute 'reason' - suite.addTest(unittest.expectedFailure(test.test_httplib.HTTPSTest('test_networked_good_cert'))) # ssl.SSLError: [Errno 'errors while validating certificate chain: '] RemoteCertificateChainErrors + suite.addTest(test.test_httplib.HTTPSTest('test_networked_good_cert')) suite.addTest(test.test_httplib.HTTPSTest('test_networked_noverification')) suite.addTest(test.test_httplib.HTTPSTest('test_networked_trusted_by_default_cert')) suite.addTest(test.test_httplib.HeaderTests('test_auto_headers')) diff --git a/Tests/test_ssl_stdlib.py b/Tests/test_ssl_stdlib.py index 3fd588809..9bc80ad57 100644 --- a/Tests/test_ssl_stdlib.py +++ b/Tests/test_ssl_stdlib.py @@ -41,11 +41,11 @@ def load_tests(loader, standard_tests, pattern): suite.addTest(test.test_ssl.BasicSocketTests('test_wrapped_unconnected')) suite.addTest(test.test_ssl.ContextTests('test__create_stdlib_context')) suite.addTest(unittest.expectedFailure(test.test_ssl.ContextTests('test_cert_store_stats'))) # AttributeError: 'SSLContext' object has no attribute 'cert_store_stats' - suite.addTest(unittest.expectedFailure(test.test_ssl.ContextTests('test_check_hostname'))) # AssertionError: ValueError not raised + suite.addTest(test.test_ssl.ContextTests('test_check_hostname')) suite.addTest(unittest.expectedFailure(test.test_ssl.ContextTests('test_ciphers'))) # AssertionError: SSLError not raised suite.addTest(test.test_ssl.ContextTests('test_constructor')) suite.addTest(test.test_ssl.ContextTests('test_create_default_context')) - suite.addTest(unittest.expectedFailure(test.test_ssl.ContextTests('test_get_ca_certs'))) # AttributeError: 'SSLContext' object has no attribute 'get_ca_certs' + suite.addTest(unittest.expectedFailure(test.test_ssl.ContextTests('test_get_ca_certs'))) # AssertionError: Lists differ suite.addTest(unittest.expectedFailure(test.test_ssl.ContextTests('test_load_cert_chain'))) # AssertionError: OSError not raised suite.addTest(test.test_ssl.ContextTests('test_load_default_certs')) if is_posix: @@ -68,12 +68,12 @@ def load_tests(loader, standard_tests, pattern): suite.addTest(test.test_ssl.NetworkedTests('test_algorithms')) suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_ciphers'))) # AssertionError: SSLError not raised suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_connect'))) # AssertionError: {} != None - suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_connect_cadata'))) # ssl.SSLError: [Errno 'errors while validating certificate chain: '] RemoteCertificateChainErrors + suite.addTest(test.test_ssl.NetworkedTests('test_connect_cadata')) suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_connect_capath'))) # ssl.SSLError: [Errno 'errors while validating certificate chain: '] RemoteCertificateChainErrors - suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_connect_ex'))) # ssl.SSLError: [Errno 'errors while validating certificate chain: '] RemoteCertificateChainErrors + suite.addTest(test.test_ssl.NetworkedTests('test_connect_ex')) #suite.addTest(test.test_ssl.NetworkedTests('test_connect_ex_error')) # slow suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_connect_with_context'))) # AssertionError: {} != None - suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_context_setget'))) # AttributeError: '_SSLSocket' object has no attribute 'context' + suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_context_setget'))) # AttributeError: can't assign to read-only property context of type '_SSLSocket' suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_get_ca_certs_capath'))) # AttributeError: 'SSLContext' object has no attribute 'get_ca_certs' suite.addTest(unittest.expectedFailure(test.test_ssl.NetworkedTests('test_get_server_certificate'))) # ssl.SSLError: [Errno 'errors while validating certificate chain: '] RemoteCertificateNameMismatch, RemoteCertificateChainErrors if is_posix: @@ -85,43 +85,43 @@ def load_tests(loader, standard_tests, pattern): suite.addTest(test.test_ssl.NetworkedTests('test_timeout_connect_ex')) suite.addTest(unittest.expectedFailure(test.test_ssl.SSLErrorTests('test_lib_reason'))) # AttributeError: 'SSLContext' object has no attribute 'load_dh_params' suite.addTest(unittest.expectedFailure(test.test_ssl.SSLErrorTests('test_str'))) # AssertionError: '[Errno 1] foo' != 'foo' - #suite.addTest(unittest.expectedFailure(test.test_ssl.SSLErrorTests('test_subclass'))) # blocking - #suite.addTest(test.test_ssl.ThreadedTests('test_asyncore_server')) + suite.addTest(unittest.expectedFailure(test.test_ssl.SSLErrorTests('test_subclass'))) # TypeError: Value cannot be null. + #suite.addTest(test.test_ssl.ThreadedTests('test_asyncore_server')) # blocking #suite.addTest(test.test_ssl.ThreadedTests('test_check_hostname')) #suite.addTest(test.test_ssl.ThreadedTests('test_compression')) - #suite.addTest(test.test_ssl.ThreadedTests('test_compression_disabled')) - #suite.addTest(test.test_ssl.ThreadedTests('test_crl_check')) + suite.addTest(test.test_ssl.ThreadedTests('test_compression_disabled')) + suite.addTest(test.test_ssl.ThreadedTests('test_crl_check')) #suite.addTest(test.test_ssl.ThreadedTests('test_default_ciphers')) #suite.addTest(test.test_ssl.ThreadedTests('test_default_ecdh_curve')) - #suite.addTest(test.test_ssl.ThreadedTests('test_dh_params')) - #suite.addTest(test.test_ssl.ThreadedTests('test_do_handshake_enotconn')) + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_dh_params'))) # AttributeError: 'SSLContext' object has no attribute 'load_dh_params' + suite.addTest(test.test_ssl.ThreadedTests('test_do_handshake_enotconn')) #suite.addTest(test.test_ssl.ThreadedTests('test_echo')) - #suite.addTest(test.test_ssl.ThreadedTests('test_empty_cert')) - #suite.addTest(test.test_ssl.ThreadedTests('test_getpeercert')) - #suite.addTest(test.test_ssl.ThreadedTests('test_getpeercert_enotconn')) - #suite.addTest(test.test_ssl.ThreadedTests('test_handshake_timeout')) - #suite.addTest(test.test_ssl.ThreadedTests('test_malformed_cert')) - #suite.addTest(test.test_ssl.ThreadedTests('test_malformed_key')) - #suite.addTest(test.test_ssl.ThreadedTests('test_nonexisting_cert')) - #suite.addTest(test.test_ssl.ThreadedTests('test_npn_protocols')) + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_empty_cert'))) # NotImplementedError: keyfile + #suite.addTest(test.test_ssl.ThreadedTests('test_getpeercert')) # blocking + suite.addTest(test.test_ssl.ThreadedTests('test_getpeercert_enotconn')) + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_handshake_timeout'))) # TypeError: Value cannot be null. + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_malformed_cert'))) # NotImplementedError: keyfile + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_malformed_key'))) # NotImplementedError: keyfile + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_nonexisting_cert'))) # NotImplementedError: keyfile + suite.addTest(test.test_ssl.ThreadedTests('test_npn_protocols')) #suite.addTest(test.test_ssl.ThreadedTests('test_protocol_sslv2')) #suite.addTest(test.test_ssl.ThreadedTests('test_protocol_sslv23')) #suite.addTest(test.test_ssl.ThreadedTests('test_protocol_sslv3')) #suite.addTest(test.test_ssl.ThreadedTests('test_protocol_tlsv1')) #suite.addTest(test.test_ssl.ThreadedTests('test_protocol_tlsv1_1')) #suite.addTest(test.test_ssl.ThreadedTests('test_protocol_tlsv1_2')) - #suite.addTest(test.test_ssl.ThreadedTests('test_read_write_after_close_raises_valuerror')) - #suite.addTest(test.test_ssl.ThreadedTests('test_recv_send')) - #suite.addTest(test.test_ssl.ThreadedTests('test_rude_shutdown')) + #suite.addTest(test.test_ssl.ThreadedTests('test_read_write_after_close_raises_valuerror')) # blocking + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_recv_send'))) # NotImplementedError: keyfile + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_rude_shutdown'))) # TypeError: Value cannot be null. #suite.addTest(test.test_ssl.ThreadedTests('test_selected_npn_protocol')) #suite.addTest(test.test_ssl.ThreadedTests('test_server_accept')) - #suite.addTest(test.test_ssl.ThreadedTests('test_sni_callback')) - #suite.addTest(test.test_ssl.ThreadedTests('test_sni_callback_alert')) - #suite.addTest(test.test_ssl.ThreadedTests('test_sni_callback_raising')) - #suite.addTest(test.test_ssl.ThreadedTests('test_sni_callback_wrong_return_type')) + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_sni_callback'))) # AttributeError: 'SSLContext' object has no attribute 'set_servername_callback' + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_sni_callback_alert'))) # AttributeError: 'SSLContext' object has no attribute 'set_servername_callback' + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_sni_callback_raising'))) # AttributeError: 'SSLContext' object has no attribute 'set_servername_callback' + suite.addTest(unittest.expectedFailure(test.test_ssl.ThreadedTests('test_sni_callback_wrong_return_type'))) # AttributeError: 'SSLContext' object has no attribute 'set_servername_callback' #suite.addTest(test.test_ssl.ThreadedTests('test_socketserver')) - #suite.addTest(test.test_ssl.ThreadedTests('test_starttls')) - #suite.addTest(test.test_ssl.ThreadedTests('test_tls_unique_channel_binding')) + #suite.addTest(test.test_ssl.ThreadedTests('test_starttls')) # blocking + suite.addTest(test.test_ssl.ThreadedTests('test_tls_unique_channel_binding')) return suite else: