GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

Commit 188aca3a authored by Cecylia Bocovich's avatar Cecylia Bocovich
Browse files

Merge branch 'issue#27984' into 'develop'

Fix for issue #27984

See merge request tpo/anti-censorship/bridgedb!14
parents f4f1fbb5 6bbc11b2
......@@ -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
......@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment