[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [bridgedb/develop] Fix for issue #27984
commit 6bbc11b2f0683d55390dfcc2c4409f51d866fe2e
Author: agix <columbeff@xxxxxxxxx>
Date: Thu Apr 29 15:15:56 2021 +0200
Fix for issue #27984
Changed the hostname check by using verify_certificate_hostname from the service identity package for complete hostname verification.
Added wildcard certificates for testing and two additional test cases (test_verifyHostname_matching_wildcard & test_verifyHostname_matching_wildcard_multidns)
---
bridgedb/crypto.py | 26 +++++++---
bridgedb/test/test_crypto.py | 118 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 138 insertions(+), 6 deletions(-)
diff --git a/bridgedb/crypto.py b/bridgedb/crypto.py
index 9bdf729..b2db8b2 100644
--- a/bridgedb/crypto.py
+++ b/bridgedb/crypto.py
@@ -54,6 +54,10 @@ from Crypto.PublicKey import RSA
from twisted.internet import ssl
from twisted.python.procutils import which
+from service_identity.cryptography import verify_certificate_hostname
+from cryptography.x509 import load_pem_x509_certificate
+from service_identity import VerificationError, CertificateError, SubjectAltNameWarning
+
#: The hash digest to use for HMACs.
DIGESTMOD = hashlib.sha1
@@ -340,16 +344,26 @@ class SSLVerifyingContextFactory(ssl.CertificateOptions):
"""
commonName = x509.get_subject().commonName
logging.debug("Received cert at level %d: '%s'" % (depth, commonName))
+ x509 = x509.to_cryptography()
# We only want to verify that the hostname matches for the level 0
# certificate:
if okay and (depth == 0):
- cn = commonName.replace('*', '.*')
- hostnamesMatch = re.search(cn, self.hostname)
- if not hostnamesMatch:
+ try:
+ verify_certificate_hostname(x509, self.hostname)
+ logging.debug("Valid certificate subject CN for '%s': '%s'"
+ % (self.hostname, commonName))
+ return True
+ except VerificationError:
logging.warn("Invalid certificate subject CN for '%s': '%s'"
% (self.hostname, commonName))
return False
- logging.debug("Valid certificate subject CN for '%s': '%s'"
- % (self.hostname, commonName))
- return True
+ except CertificateError:
+ logging.warn("Certificate contains invalid or unexpected data")
+ return False
+ except SubjectAltNameWarning:
+ logging.warn("Certificate contains no SAN, fallback to common name")
+ cn = commonName.replace('*', '.*')
+ hostnamesMatch = re.search(cn, self.hostname)
+ hostnamesMatch = True if hostnamesMatch else False
+ return hostnamesMatch
\ No newline at end of file
diff --git a/bridgedb/test/test_crypto.py b/bridgedb/test/test_crypto.py
index f57d4f3..b1af96d 100644
--- a/bridgedb/test/test_crypto.py
+++ b/bridgedb/test/test_crypto.py
@@ -191,6 +191,90 @@ class SSLVerifyingContextFactoryTests(unittest.TestCase,
"rR97EIYKFz7C6LMy/PIe8xFTIyKMtM59IcpUDIwCLlM9JtNdwN4VpyKy\n"
"-----END CERTIFICATE-----\n")
+ _wildcardcertificate = (
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIExjCCA66gAwIBAgIRAKy0RV8bAucyAgAAAABnMzYwDQYJKoZIhvcNAQELBQAw\n"
+ "QjELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFUdvb2dsZSBUcnVzdCBTZXJ2aWNlczET\n"
+ "MBEGA1UEAxMKR1RTIENBIDFPMTAeFw0yMDA1MDUwODMyMjlaFw0yMDA3MjgwODMy\n"
+ "MjlaMGUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH\n"
+ "Ew1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgTExDMRQwEgYDVQQDDAsq\n"
+ "Lmdvb2dsZS5hdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDuwtcBm/Zy4gj3P\n"
+ "aaBHMOHIypfqB7KBhbzJSux7ZQpuWhM4R4anNzOzjjrCyi4R+u2mkjeB/Bw6xzt8\n"
+ "ObtSEmWjggJdMIICWTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUH\n"
+ "AwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUOCAX+hzjxyujW0S+sRabV0fAspkw\n"
+ "HwYDVR0jBBgwFoAUmNH4bhDrz5vsYJ8YkBug630J/SswZAYIKwYBBQUHAQEEWDBW\n"
+ "MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHMxbzEwKwYIKwYB\n"
+ "BQUHMAKGH2h0dHA6Ly9wa2kuZ29vZy9nc3IyL0dUUzFPMS5jcnQwIQYDVR0RBBow\n"
+ "GIILKi5nb29nbGUuYXSCCWdvb2dsZS5hdDAhBgNVHSAEGjAYMAgGBmeBDAECAjAM\n"
+ "BgorBgEEAdZ5AgUDMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9jcmwucGtpLmdv\n"
+ "b2cvR1RTMU8xLmNybDCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3ALIeBcyLos2K\n"
+ "IE6HZvkruYolIGdr2vpw57JJUy3vi5BeAAABceQt+OQAAAQDAEgwRgIhANY9slOG\n"
+ "xYI8TgPHZ4QdaJAOkOUf+0OMQb47glFk/MAJAiEAlmNt5gNHqEKOhZAU5FB/PF9v\n"
+ "P6sD8oLupRxHiEMTtLIAdgBep3P531bA57U2SH3QSeAyepGaDIShEhKEGHWWgXFF\n"
+ "WAAAAXHkLfiiAAAEAwBHMEUCIQDcvmEUZcDHDCvX2cikDl8xTfGcWvKETvQL02qt\n"
+ "L/hVlQIgfvzN2SEzT2+VwuzgGbmC8CljAjVwxKMRc+BzlB0yFh4wDQYJKoZIhvcN\n"
+ "AQELBQADggEBAHsyJM0yEViV/Vo09mwmP3LAyNhK4hGl3+ueZRr7PE3zkbXA3Sb3\n"
+ "JAbdpaQJIGUb5PeiTCB5e/Zem8N6qh4WZOi09LVoVUvkOcCUTSFayRzkyTZK1gT5\n"
+ "9d/RWL4BfptK++pdkHWT24SnXw/OfeZBd537LWwhGo4X60RRmPIfvxenUcXlUull\n"
+ "ZKYMh5B/GkcHAUf6m79lsR5K82ryplDwHr7IpfPSlJyLZn7Y4n3G9HdFeqUVEw4y\n"
+ "J7GslEdOd8C5IaO0xLiw+A7kkUJ16LOYKncmaMnIdhL7ibpQltd8x9VHwM7tEw3g\n"
+ "52qHhy4vviLHs2SClrxmkINyRvqd9c/GHcI=\n"
+ "-----END CERTIFICATE-----\n")
+
+ _wildcardmultidnscertificate = (
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIJTzCCCDegAwIBAgIQGoaLDa+bxzQIAAAAAD69lzANBgkqhkiG9w0BAQsFADBC\n"
+ "MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMRMw\n"
+ "EQYDVQQDEwpHVFMgQ0EgMU8xMB4XDTIwMDUwNTA4MjIzNVoXDTIwMDcyODA4MjIz\n"
+ "NVowZjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcT\n"
+ "DU1vdW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBMTEMxFTATBgNVBAMMDCou\n"
+ "Z29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMExBCpkvy8VuVVJ\n"
+ "gyrY19Q/NvVPzb+yNS371xwzVriYLDhyEyGXNf45D/qj7qIe9EqkpOylAUvF5+4x\n"
+ "NYr5INujggbmMIIG4jAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUH\n"
+ "AwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUn9s6xwZqJNPn2S7GBvgewUShDNcw\n"
+ "HwYDVR0jBBgwFoAUmNH4bhDrz5vsYJ8YkBug630J/SswZAYIKwYBBQUHAQEEWDBW\n"
+ "MCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHMxbzEwKwYIKwYB\n"
+ "BQUHMAKGH2h0dHA6Ly9wa2kuZ29vZy9nc3IyL0dUUzFPMS5jcnQwggSoBgNVHREE\n"
+ "ggSfMIIEm4IMKi5nb29nbGUuY29tgg0qLmFuZHJvaWQuY29tghYqLmFwcGVuZ2lu\n"
+ "ZS5nb29nbGUuY29tggkqLmJkbi5kZXaCEiouY2xvdWQuZ29vZ2xlLmNvbYIYKi5j\n"
+ "cm93ZHNvdXJjZS5nb29nbGUuY29tggYqLmcuY2+CDiouZ2NwLmd2dDIuY29tghEq\n"
+ "LmdjcGNkbi5ndnQxLmNvbYIKKi5nZ3BodC5jboIOKi5na2VjbmFwcHMuY26CFiou\n"
+ "Z29vZ2xlLWFuYWx5dGljcy5jb22CCyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIO\n"
+ "Ki5nb29nbGUuY28uaW6CDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IP\n"
+ "Ki5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5i\n"
+ "coIPKi5nb29nbGUuY29tLmNvgg8qLmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNv\n"
+ "bS50coIPKi5nb29nbGUuY29tLnZuggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOC\n"
+ "CyouZ29vZ2xlLmZyggsqLmdvb2dsZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xl\n"
+ "Lm5sggsqLmdvb2dsZS5wbIILKi5nb29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNv\n"
+ "bYIPKi5nb29nbGVhcGlzLmNughEqLmdvb2dsZWNuYXBwcy5jboIUKi5nb29nbGVj\n"
+ "b21tZXJjZS5jb22CESouZ29vZ2xldmlkZW8uY29tggwqLmdzdGF0aWMuY26CDSou\n"
+ "Z3N0YXRpYy5jb22CEiouZ3N0YXRpY2NuYXBwcy5jboIKKi5ndnQxLmNvbYIKKi5n\n"
+ "dnQyLmNvbYIUKi5tZXRyaWMuZ3N0YXRpYy5jb22CDCoudXJjaGluLmNvbYIQKi51\n"
+ "cmwuZ29vZ2xlLmNvbYITKi53ZWFyLmdrZWNuYXBwcy5jboIWKi55b3V0dWJlLW5v\n"
+ "Y29va2llLmNvbYINKi55b3V0dWJlLmNvbYIWKi55b3V0dWJlZWR1Y2F0aW9uLmNv\n"
+ "bYIRKi55b3V0dWJla2lkcy5jb22CByoueXQuYmWCCyoueXRpbWcuY29tghphbmRy\n"
+ "b2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CG2RldmVsb3Blci5h\n"
+ "bmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRyb2lkLmdvb2dsZS5jboIE\n"
+ "Zy5jb4IIZ2dwaHQuY26CDGdrZWNuYXBwcy5jboIGZ29vLmdsghRnb29nbGUtYW5h\n"
+ "bHl0aWNzLmNvbYIKZ29vZ2xlLmNvbYIPZ29vZ2xlY25hcHBzLmNughJnb29nbGVj\n"
+ "b21tZXJjZS5jb22CGHNvdXJjZS5hbmRyb2lkLmdvb2dsZS5jboIKdXJjaGluLmNv\n"
+ "bYIKd3d3Lmdvby5nbIIIeW91dHUuYmWCC3lvdXR1YmUuY29tghR5b3V0dWJlZWR1\n"
+ "Y2F0aW9uLmNvbYIPeW91dHViZWtpZHMuY29tggV5dC5iZTAhBgNVHSAEGjAYMAgG\n"
+ "BmeBDAECAjAMBgorBgEEAdZ5AgUDMC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9j\n"
+ "cmwucGtpLmdvb2cvR1RTMU8xLmNybDCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3\n"
+ "ALIeBcyLos2KIE6HZvkruYolIGdr2vpw57JJUy3vi5BeAAABceQk7HEAAAQDAEgw\n"
+ "RgIhAMeaPA4eH4PQ6P80cE7pV9+cA+JzHsfEHXybUpJYTUUqAiEAtt6UgO7o9Bo5\n"
+ "T83b8KngOaFoAMEitVL5ckcpZHNtOaQAdgBep3P531bA57U2SH3QSeAyepGaDISh\n"
+ "EhKEGHWWgXFFWAAAAXHkJOyPAAAEAwBHMEUCIQDLXewTtt5w1Pykw4iJLVEBNWsU\n"
+ "8LazX+MIkUmuOpwJQwIgIXySwReiZv9FbIJ/73ytICnrPGNkD43+PVMge9cJ0gQw\n"
+ "DQYJKoZIhvcNAQELBQADggEBAM/x3sGLTHpoan0gd9XdVCG6HsQynQEzLL25kTvN\n"
+ "q14pRburIrsdFWhtEETqNJo7IG19PozR6IdJkQqEBYjw6D9rRniikWeski5MhcFD\n"
+ "fU3ycQ2I2ISlAd3HelYNbVDJ8zJWerEGk7dyi2O/UmRreXHhi+dry8IgTiSssYNA\n"
+ "fht9x4GVvFTT6gap4E1Qy5UFMBGMqXmhXNoH9bYX1oY6N+8xr5tkTSQfV0T1kXKJ\n"
+ "WUhnDkwMUnvwuMUEP7elcvp7OgOslSQ5zwjnR3zSDozO072YR+L9SGMICCZz1ha1\n"
+ "DMCTA95gzVKezFCaUidRU9UyHOFzltfYDt7HRlp7MwWoPLM=\n"
+ "-----END CERTIFICATE-----\n")
+
def setUp(self):
"""Create a fake reactor for these tests."""
self.reactor = self.createReactor()
@@ -248,6 +332,40 @@ class SSLVerifyingContextFactoryTests(unittest.TestCase,
result = contextFactory.verifyHostname(conn, x509, 0, 0, True)
self.assertTrue(result)
+ def test_verifyHostname_matching_wildcard(self):
+ """Check that ``verifyHostname()`` returns ``True`` when the
+ ``SSLVerifyingContextFactory.hostname`` matches the one found in the
+ level 0 certificate subject SAN. The certificate includes a wildcard
+ for the common name & SAN.
+ """
+ hostname = 'www.google.at'
+ url = 'https://' + hostname + '/recaptcha'
+ contextFactory = crypto.SSLVerifyingContextFactory(url)
+ self.assertEqual(contextFactory.hostname, hostname)
+
+ x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
+ self._wildcardcertificate)
+ conn = DummyEndpoint()
+ result = contextFactory.verifyHostname(conn, x509, 0, 0, True)
+ self.assertTrue(result)
+
+ def test_verifyHostname_matching_wildcard_multidns(self):
+ """Check that ``verifyHostname()`` returns ``True`` when the
+ ``SSLVerifyingContextFactory.hostname`` matches the one found in the
+ level 0 certificate subject CN. This specific google.com certificate
+ inlcudes numerous SAN's.
+ """
+ hostname = 'www.google.com'
+ url = 'https://' + hostname + '/recaptcha'
+ contextFactory = crypto.SSLVerifyingContextFactory(url)
+ self.assertEqual(contextFactory.hostname, hostname)
+
+ x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
+ self._wildcardmultidnscertificate)
+ conn = DummyEndpoint()
+ result = contextFactory.verifyHostname(conn, x509, 0, 0, True)
+ self.assertTrue(result)
+
def test_getContext(self):
"""The context factory's ``getContext()`` method should produce an
``OpenSSL.SSL.Context`` object.
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits