Skip to content

Commit 06e1a65

Browse files
committed
iostream_test: Test check_hostname functionality.
In #3337, the removal of ssl.match_hostname revealed that we did not have any test coverage of hostname checking in tornado.iostream. Since we were forced to remove the manual check that we had in place for old versions of Python, we need a test to make sure that we didn't inadvertently break hostname checking.
1 parent a6dfd70 commit 06e1a65

File tree

4 files changed

+120
-45
lines changed

4 files changed

+120
-45
lines changed

tornado/test/iostream_test.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,81 @@ def handle_stream(self, stream, address):
11491149
yield handshake_future
11501150

11511151

1152+
class TestIOStreamCheckHostname(AsyncTestCase):
1153+
# This test ensures that hostname checks are working correctly after
1154+
# #3337 revealed that we have no test coverage in this area, and we
1155+
# removed a manual hostname check that was needed only for very old
1156+
# versions of python.
1157+
def setUp(self):
1158+
super().setUp()
1159+
self.listener, self.port = bind_unused_port()
1160+
1161+
def accept_callback(connection, address):
1162+
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
1163+
ssl_ctx.load_cert_chain(
1164+
os.path.join(os.path.dirname(__file__), "test.crt"),
1165+
os.path.join(os.path.dirname(__file__), "test.key"),
1166+
)
1167+
connection = ssl_ctx.wrap_socket(
1168+
connection,
1169+
server_side=True,
1170+
do_handshake_on_connect=False,
1171+
)
1172+
SSLIOStream(connection)
1173+
1174+
netutil.add_accept_handler(self.listener, accept_callback)
1175+
1176+
# Our self-signed cert is its own CA. We have to pass the CA check before
1177+
# the hostname check will be performed.
1178+
self.client_ssl_ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
1179+
self.client_ssl_ctx.load_verify_locations(
1180+
os.path.join(os.path.dirname(__file__), "test.crt")
1181+
)
1182+
1183+
def tearDown(self):
1184+
self.io_loop.remove_handler(self.listener.fileno())
1185+
self.listener.close()
1186+
super().tearDown()
1187+
1188+
@gen_test
1189+
async def test_match(self):
1190+
stream = SSLIOStream(socket.socket(), ssl_options=self.client_ssl_ctx)
1191+
await stream.connect(
1192+
("127.0.0.1", self.port),
1193+
server_hostname="foo.example.com",
1194+
)
1195+
stream.close()
1196+
1197+
@gen_test
1198+
async def test_no_match(self):
1199+
stream = SSLIOStream(socket.socket(), ssl_options=self.client_ssl_ctx)
1200+
with ExpectLog(gen_log, ".*alert bad certificate", level=logging.WARNING):
1201+
with self.assertRaises(ssl.SSLCertVerificationError):
1202+
with ExpectLog(
1203+
gen_log,
1204+
".*(certificate verify failed: Hostname mismatch)",
1205+
level=logging.WARNING,
1206+
):
1207+
await stream.connect(
1208+
("127.0.0.1", self.port),
1209+
server_hostname="bar.example.com",
1210+
)
1211+
# The server logs a warning while cleaning up the failed connection.
1212+
# Unfortunately there's no good hook to wait for this logging.
1213+
await asyncio.sleep(0.1)
1214+
1215+
@gen_test
1216+
async def test_check_disabled(self):
1217+
# check_hostname can be set to false and the connection will succeed even though it doesn't
1218+
# have the right hostname.
1219+
self.client_ssl_ctx.check_hostname = False
1220+
stream = SSLIOStream(socket.socket(), ssl_options=self.client_ssl_ctx)
1221+
await stream.connect(
1222+
("127.0.0.1", self.port),
1223+
server_hostname="bar.example.com",
1224+
)
1225+
1226+
11521227
@skipIfNonUnix
11531228
class TestPipeIOStream(TestReadWriteMixin, AsyncTestCase):
11541229
@gen.coroutine

tornado/test/test.crt

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
-----BEGIN CERTIFICATE-----
2-
MIIDWzCCAkOgAwIBAgIUV4spou0CenmvKqa7Hml/MC+JKiAwDQYJKoZIhvcNAQEL
3-
BQAwPTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExGTAXBgNVBAoM
4-
EFRvcm5hZG8gV2ViIFRlc3QwHhcNMTgwOTI5MTM1NjQ1WhcNMjgwOTI2MTM1NjQ1
5-
WjA9MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEZMBcGA1UECgwQ
6-
VG9ybmFkbyBXZWIgVGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
7-
AKT0LdyI8tW5uwP3ahE8BFSz+j3SsKBDv/0cKvqxVVE6sLEST2s3HjArZvIIG5sb
8-
iBkWDrqnZ6UKDvB4jlobLGAkepxDbrxHWxK53n0C28XXGLqJQ01TlTZ5rpjttMeg
9-
5SKNjHbxpOvpUwwQS4br4WjZKKyTGiXpFkFUty+tYVU35/U2yyvreWHmzpHx/25t
10-
H7O2RBARVwJYKOGPtlH62lQjpIWfVfklY4Ip8Hjl3B6rBxPyBULmVQw0qgoZn648
11-
oa4oLjs0wnYBz01gVjNMDHej52SsB/ieH7W1TxFMzqOlcvHh41uFbQJPgcXsruSS
12-
9Z4twzSWkUp2vk/C//4Sz38CAwEAAaNTMFEwHQYDVR0OBBYEFLf8fQ5+u8sDWAd3
13-
r5ZjZ5MmDWJeMB8GA1UdIwQYMBaAFLf8fQ5+u8sDWAd3r5ZjZ5MmDWJeMA8GA1Ud
14-
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADkkm3pIb9IeqVNmQ2uhQOgw
15-
UwyToTYUHNTb/Nm5lzBTBqC8gbXAS24RQ30AB/7G115Uxeo+YMKfITxm/CgR+vhF
16-
F59/YrzwXj+G8bdbuVl/UbB6f9RSp+Zo93rUZAtPWr77gxLUrcwSRzzDwxFjC2nC
17-
6eigbkvt1OQY775RwnFAt7HKPclE0Out+cGJIboJuO1f3r57ZdyFH0GzbZEff/7K
18-
atGXohijWJjYvU4mk0KFHORZrcBpsv9cfkFbmgVmiRwxRJ1tLauHM3Ne+VfqYE5M
19-
4rTStSyz3ASqVKJ2iFMQueNR/tUOuDlfRt+0nhJMuYSSkW+KTgnwyOGU9cv+mxA=
2+
MIIC1TCCAb2gAwIBAgIJAOV36k+idrqDMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV
3+
BAMMD2Zvby5leGFtcGxlLmNvbTAeFw0yMzExMTIwMTQ3MzhaFw0zMzExMDkwMTQ3
4+
MzhaMBoxGDAWBgNVBAMMD2Zvby5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB
5+
BQADggEPADCCAQoCggEBAKjfAL8hQ1G5yoR29D0NwqhL3EE9RShYLvzKvSNhOceR
6+
e390XJLAi8PN8Xv8LkmoMITaLdRDtBwXcdw+kfHjcfXZ0cORJkxJFdk/38SsiBKV
7+
ZzMO+1PVULfnQa92tHtahNsTGI5367WEALn9UNJLmP+jpX+3zohatUTbhlnRSruH
8+
O/Mo5mLs1XJhQpdvp8BQNksJhiTQ7FsbcjGq6gZ75SnbfUR0PyohY0LTsrql00Tz
9+
hCAEvm2TNiQ5s+PT5fFOg6Jh2ZGj1lYLQY3dDeqt9sdabvj7LANqfygbt2cf9yYn
10+
a25UTRcAN7CNdWwTEfvnOVMITzCE8F2FmKDvJR+TX30CAwEAAaMeMBwwGgYDVR0R
11+
BBMwEYIPZm9vLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBjKz4gM4Bz
12+
JO7Ny1fwbBtraHCGYnDG8gBID3+/sQlMMFeuquJK+oc+1DOpr9wFlmgih67OszdM
13+
X2Xl/HjtHPKwNqaDHXu5bQPFT5fXzAZ8HHEOXSV9IpHaNyS7TC7bYmD/ClCZeqXU
14+
h7MBe5yPXfCCIqWyjZMZDQfT1v6J+WX3+lO9josMJCfNR5DzvJiPmSTUxrLD5SkT
15+
+7iKxhM6eI83D+I188sGc2IMinkFp8jSRTlaH8WYiOd5QQ2r8GSYNM9M3z1sK7zv
16+
0Bw3hWEQgpFbEaSH0OB72KYkMUZBqK9UoeSZWBrMXHFBNaY23tEKInEwlBGBELGc
17+
acSinK6OBC0z
2018
-----END CERTIFICATE-----

tornado/test/test.key

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
-----BEGIN PRIVATE KEY-----
2-
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCk9C3ciPLVubsD
3-
92oRPARUs/o90rCgQ7/9HCr6sVVROrCxEk9rNx4wK2byCBubG4gZFg66p2elCg7w
4-
eI5aGyxgJHqcQ268R1sSud59AtvF1xi6iUNNU5U2ea6Y7bTHoOUijYx28aTr6VMM
5-
EEuG6+Fo2Siskxol6RZBVLcvrWFVN+f1Nssr63lh5s6R8f9ubR+ztkQQEVcCWCjh
6-
j7ZR+tpUI6SFn1X5JWOCKfB45dweqwcT8gVC5lUMNKoKGZ+uPKGuKC47NMJ2Ac9N
7-
YFYzTAx3o+dkrAf4nh+1tU8RTM6jpXLx4eNbhW0CT4HF7K7kkvWeLcM0lpFKdr5P
8-
wv/+Es9/AgMBAAECggEABi6AaXtYXloPgB6NgwfUwbfc8OQsalUfpMShd7OdluW0
9-
KW6eO05de0ClIvzay/1EJGyHMMeFQtIVrT1XWFkcWJ4FWkXMqJGkABenFtg8lDVz
10-
X8o1E3jGZrw4ptKBq9mDvL/BO9PiclTUH+ecbPn6AIvi0lTQ7grGIryiAM9mjmLy
11-
jpCwoutF2LD4RPNg8vqWe/Z1rQw5lp8FOHhRwPooHHeoq1bSrp8dqvVAwAam7Mmf
12-
uFgI8jrNycPgr2cwEEtbq2TQ625MhVnCpwT+kErmAStfbXXuqv1X1ZZgiNxf+61C
13-
OL0bhPRVIHmmjiK/5qHRuN4Q5u9/Yp2SJ4W5xadSQQKBgQDR7dnOlYYQiaoPJeD/
14-
7jcLVJbWwbr7bE19O/QpYAtkA/FtGlKr+hQxPhK6OYp+in8eHf+ga/NSAjCWRBoh
15-
MNAVCJtiirHo2tFsLFOmlJpGL9n3sX8UnkJN90oHfWrzJ8BZnXaSw2eOuyw8LLj+
16-
Q+ISl6Go8/xfsuy3EDv4AP1wCwKBgQDJJ4vEV3Kr+bc6N/xeu+G0oHvRAWwuQpcx
17-
9D+XpnqbJbFDnWKNE7oGsDCs8Qjr0CdFUN1pm1ppITDZ5N1cWuDg/47ZAXqEK6D1
18-
z13S7O0oQPlnsPL7mHs2Vl73muAaBPAojFvceHHfccr7Z94BXqKsiyfaWz6kclT/
19-
Nl4JTdsC3QKBgQCeYgozL2J/da2lUhnIXcyPstk+29kbueFYu/QBh2HwqnzqqLJ4
20-
5+t2H3P3plQUFp/DdDSZrvhcBiTsKiNgqThEtkKtfSCvIvBf4a2W/4TJsW6MzxCm
21-
2KQDuK/UqM4Y+APKWN/N6Lln2VWNbNyBkWuuRVKFatccyJyJnSjxeqW7cwKBgGyN
22-
idCYPIrwROAHLItXKvOWE5t0ABRq3TsZC2RkdA/b5HCPs4pclexcEriRjvXrK/Yt
23-
MH94Ve8b+UftSUQ4ytjBMS6MrLg87y0YDhLwxv8NKUq65DXAUOW+8JsAmmWQOqY3
24-
MK+m1BT4TMklgVoN3w3sPsKIsSJ/jLz5cv/kYweFAoGAG4iWU1378tI2Ts/Fngsv
25-
7eoWhoda77Y9D0Yoy20aN9VdMHzIYCBOubtRPEuwgaReNwbUBWap01J63yY/fF3K
26-
8PTz6covjoOJqxQJOvM7nM0CsJawG9ccw3YXyd9KgRIdSt6ooEhb7N8W2EXYoKl3
27-
g1i2t41Q/SC3HUGC5mJjpO8=
2+
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo3wC/IUNRucqE
3+
dvQ9DcKoS9xBPUUoWC78yr0jYTnHkXt/dFySwIvDzfF7/C5JqDCE2i3UQ7QcF3Hc
4+
PpHx43H12dHDkSZMSRXZP9/ErIgSlWczDvtT1VC350GvdrR7WoTbExiOd+u1hAC5
5+
/VDSS5j/o6V/t86IWrVE24ZZ0Uq7hzvzKOZi7NVyYUKXb6fAUDZLCYYk0OxbG3Ix
6+
quoGe+Up231EdD8qIWNC07K6pdNE84QgBL5tkzYkObPj0+XxToOiYdmRo9ZWC0GN
7+
3Q3qrfbHWm74+ywDan8oG7dnH/cmJ2tuVE0XADewjXVsExH75zlTCE8whPBdhZig
8+
7yUfk199AgMBAAECggEBAIGFmXL/Nj0GvVfgTPBPD5A5rxOyxMpu6IsnjO4H8mMp
9+
KInXW/GLESf7W053W6FPCPe8yA3YZ9pr+P6uVw4qHwwsJwFS4Qb9v25D2YNluXBX
10+
ezHkOcxQ/novO2gzKba69M961Ajh3b35Iv2EV2sUZKMehx9wgU6AFCxeG6vkJOez
11+
UCX0WG467cdo4alfe/oQZLioU3t+GGCb23m13B9xaN2tqONNh2E2yp73MVJ1Q74R
12+
HVBkQxciHd3iJee5/4AGUJl9TLv8wAT1cf3OhcGlvOlcfSYtuNUY32TPWit1Or1y
13+
i9fPkjo8SBw52TN5RRmjIlpNMxeK+G4+XtO1Y47TlZkCgYEA3Y+NK8mz9kTnorkf
14+
R7CSOAaiste8c3CJbbbaTk7oTxK4MISL1RX+sFK65cnV54Wo75hCZxsjV2oEQ+4r
15+
UOGw1JxcV16V6iP/AaQS41xsxZca/xnC//YojBN6kP+OV+/ByF4HNs5eDN6uHg0y
16+
OOfBWi6oc449CFFMxVnrQ0SymaMCgYEAwx7M9xQ1eth902Wq2VNszFIgdgptGYhj
17+
XbWsAFYKII+aUXC92sVL5sO33vNyhBbyMN1aSRXYe8B5EnwsP31o5csrHQw6i/Dp
18+
jUx1AUBYkNPgL9ctqlTQf1nb0LenGlCUBD6jrSrJVHeOF4y+HIZHXNZ++otH7+eu
19+
b3dbHgV/9F8CgYBTopO0utAvH3WdDGqNYk7fzUlvX1ao8Qs/mi2wL8MrzjIvRmmO
20+
h137607X3Sfc3KyXvQ8b4relkMSJbAd34aohp+CHrpHCr9HcKbZjkwkQUWkEcRIW
21+
EzLdJaE3yPBPq5an7y6j9qS0EP8DIxIZPwrS4xf9fuz1DdOAD+BqJS2SJwKBgQCt
22+
zZzTpduxbnA+Qrx503cBVVJ28viVmsiwK2hn8DwbHu9eBegHnGDs0H/Th9UE1g+r
23+
+TA4E85/BUaTcapUb5hlwKDJwh/QkaroYyeCEtgRQbnbw3d41w3Vsqw78atWpFoE
24+
oetYD9nAdLJMReD+NZoRlzsKX9CXYS8fORkf19RPTwKBgQCQdvDMicrtnJ4U2MOA
25+
y+59K7V77VRfHLecjAMGblBGmrtoQSBvQiFznXm0DUOSy3eZRITwe01/t+RUDhx9
26+
MVLlyNzwRCVHzPe7kUI10GM4W5ZKAf8f/t0KjBrQBeYtRUOEI3QVzsVzc1hY8Fv8
27+
YHOhmI8Tdd2biF+lqXKC6vGlvQ==
2828
-----END PRIVATE KEY-----

tornado/testing.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,9 @@ def get_ssl_options(self) -> Dict[str, Any]:
517517
def default_ssl_options() -> Dict[str, Any]:
518518
# Testing keys were generated with:
519519
# openssl req -new -keyout tornado/test/test.key \
520-
# -out tornado/test/test.crt -nodes -days 3650 -x509
520+
# -out tornado/test/test.crt \
521+
# -nodes -days 3650 -x509 \
522+
# -subj "/CN=foo.example.com" -addext "subjectAltName = DNS:foo.example.com"
521523
module_dir = os.path.dirname(__file__)
522524
return dict(
523525
certfile=os.path.join(module_dir, "test", "test.crt"),

0 commit comments

Comments
 (0)