def test__getNextRecord_with_too_big_record(self): mockSock = MockSocket( bytearray(b'\x16' + # type - handshake b'\x03\x03' + # TLSv1.2 b'\xff\xff' + # length b'\x00' * 65536)) sock = TLSRecordLayer(mockSock) # XXX using private method! gen = sock._getNextRecord() with self.assertRaises(TLSLocalAlert) as context: next(gen) self.assertEqual(str(context.exception), "record_overflow")
def test__getNextRecord_with_empty_handshake(self): mock_sock = MockSocket( bytearray(b'\x16' + # handshake b'\x03\x03' + # TLSv1.2 b'\x00\x00' # length )) record_layer = TLSRecordLayer(mock_sock) with self.assertRaises(TLSLocalAlert): for result in record_layer._getNextRecord(): if result in (0, 1): raise Exception("blocking socket") else: break
def test__getNextRecord_with_malformed_record(self): mockSock = MockSocket( bytearray(b'\x01' + # wrong type b'\x03\x03' + # TLSv1.2 b'\x00\x01' + # length b'\x00')) sock = TLSRecordLayer(mockSock) # XXX using private method! gen = sock._getNextRecord() with self.assertRaises(TLSLocalAlert) as context: next(gen) self.assertEqual(str(context.exception), "illegal_parameter")
def test_keyingMaterialExporter_tls1_3_sha256(self): sock = MockSocket(bytearray(0)) conn = TLSConnection(sock) conn._recordLayer.version = (3, 4) conn.session = Session() conn.session.cipherSuite = \ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 conn.session.exporterMasterSecret = \ bytearray(b'0123456789abcdef0123456789abcdef' + b'0123456789abcdef0123456789abcdef') mat = conn.keyingMaterialExporter(bytearray(b'test'), 20) self.assertEqual( mat, bytearray( b'W_h\x10\x83\xc0XD\x0fw\x0e\xfc/\x92\x8f\xb3\xfd\x13\x96\xd9') )
def test_recvMessage(self): defragmenter = Defragmenter() defragmenter.addStaticSize(21, 2) sock = MockSocket(bytearray( b'\x15' + # message type b'\x03\x03' + # TLS version b'\x00\x04' + # payload length b'\xff\xff' + # first message b'\xbb\xbb' # second message )) msgSock = MessageSocket(sock, defragmenter) for res in msgSock.recvMessage(): if res in (0, 1): self.assertTrue(False, "Blocking read") else: break self.assertIsNotNone(res) header, parser = res self.assertEqual(header.type, 21) self.assertEqual(header.version, (3, 3)) self.assertEqual(header.length, 0) self.assertEqual(parser.bytes, bytearray(b'\xff\xff')) res = None for res in msgSock.recvMessage(): if res in (0, 1): self.assertTrue(False, "Blocking read") else: break self.assertIsNotNone(res) header, parser = res self.assertEqual(header.type, 21) self.assertEqual(header.version, (3, 3)) self.assertEqual(header.length, 0) self.assertEqual(parser.bytes, bytearray(b'\xbb\xbb'))
def test_queueMessage_with_conflicting_types(self): sock = MockSocket(bytearray()) msgSock = MessageSocket(sock, None) msgSock.version = (3, 3) msg = Message(ContentType.handshake, bytearray(b'\xaa\xaa\xaa')) for res in msgSock.queueMessage(msg): if res in (0, 1): self.assertTrue(False, "Blocking queue") else: break self.assertEqual(len(sock.sent), 0) msg = Message(ContentType.alert, bytearray(b'\x02\x01')) for res in msgSock.queueMessage(msg): if res in (0, 1): self.assertTrue(False, "Blocking queue") else: break self.assertEqual(len(sock.sent), 1) self.assertEqual(bytearray( b'\x16' + b'\x03\x03' + b'\x00\x03' + b'\xaa'*3), sock.sent[0]) for res in msgSock.flush(): if res in (0, 1): self.assertTrue(False, "Blocking flush") else: break self.assertEqual(len(sock.sent), 2) self.assertEqual(bytearray( b'\x15' + b'\x03\x03' + b'\x00\x02' + b'\x02\x01'), sock.sent[1])
def test_flushBlocking_with_data(self): sock = MockSocket(bytearray(), blockEveryOther=True) sock.blockWrite = True msgSock = MessageSocket(sock, None) msgSock.version = (3, 3) msg = Message(ContentType.handshake, bytearray(b'\xaa\xaa\xaa')) msgSock.queueMessageBlocking(msg) self.assertEqual(len(sock.sent), 0) msgSock.flushBlocking() self.assertEqual(len(sock.sent), 1) self.assertEqual( bytearray(b'\x16' + b'\x03\x03' + b'\x00\x03' + b'\xaa' * 3), sock.sent[0])
def test_flush(self): sock = MockSocket(bytearray()) msgSock = MessageSocket(sock, None) for res in msgSock.flush(): if res in (0, 1): self.assertTrue(False, "Blocking flush") else: break self.assertEqual(len(sock.sent), 0) for res in msgSock.flush(): if res in (0, 1): self.assertTrue(False, "Blocking flush") else: break self.assertEqual(len(sock.sent), 0)
def test_sendMessage(self): sock = MockSocket(bytearray(), blockEveryOther=True) sock.blockWrite = True msgSock = MessageSocket(sock, None) msgSock.version = (3, 3) msg = Message(ContentType.handshake, bytearray(b'\xaa\xaa\xaa')) blocked = False for res in msgSock.queueMessage(msg): if res in (0, 1): blocked = True else: break # no write so no blocking self.assertFalse(blocked) self.assertEqual(len(sock.sent), 0) msg = Message(ContentType.alert, bytearray(b'\x02\x01')) blocked = False for res in msgSock.sendMessage(msg): if res in (0, 1): blocked = True else: break self.assertTrue(blocked) self.assertEqual(len(sock.sent), 2) self.assertEqual(bytearray( b'\x16' + b'\x03\x03' + b'\x00\x03' + b'\xaa'*3), sock.sent[0]) self.assertEqual(bytearray( b'\x15' + b'\x03\x03' + b'\x00\x02' + b'\x02\x01'), sock.sent[1])
def test__getNextRecord_with_trickling_socket(self): mockSock = MockSocket( bytearray(b'\x16' + # type - handshake b'\x03\x03' + # TLSv1.2 b'\x00\x04' + # length b'\x00' * 4), maxRet=1) sock = TLSRecordLayer(mockSock) # XXX using private method! for result in sock._getNextRecord(): if result in (0, 1): self.assertTrue(False, "blocking socket") else: break header, data = result data = data.bytes self.assertEqual(bytearray(4), data)
def test__getMsg_with_fragmented_message(self): mock_sock = MockSocket( bytearray(b'\x16' + # handshake b'\x03\x03' + # TLSv1.2 b'\x00\x06' + # payload length b'\x02' + # Server Hello b'\x00\x00\x36' + # hello length b'\x03\x03' + # TLSv1.2 # fragment end b'\x16' + # type - handshake b'\x03\x03' + # TLSv1.2 b'\x00\x34' + # payload length: b'\x00' * 32 + # random b'\x00' + # session ID length b'\x00\x2f' + # cipher suite selected (AES128-SHA) b'\x00' + # compression null b'\x00\x0e' + # extensions length b'\xff\x01' + # renegotiation_info b'\x00\x01' + # ext length b'\x00' + # renegotiation info ext length - 0 b'\x00\x23' + # session_ticket b'\x00\x00' + # ext length b'\x00\x0f' + # heartbeat extension b'\x00\x01' + # ext length b'\x01')) # peer is allowed to send requests record_layer = TLSRecordLayer(mock_sock) gen = record_layer._getMsg(ContentType.handshake, HandshakeType.server_hello) message = next(gen) if message in (0, 1): raise Exception("blocking") self.assertEqual(ServerHello, type(message)) self.assertEqual((3, 3), message.server_version) self.assertEqual(0x002f, message.cipher_suite)
def test__sendMsg_with_large_message(self): mock_sock = MockSocket(bytearray(0)) record_layer = TLSRecordLayer(mock_sock) client_hello = ClientHello().create( (3, 3), bytearray(32), bytearray(0), [x for x in range(2**15 - 1)]) gen = record_layer._sendMsg(client_hello) for result in gen: if result in (0, 1): self.assertTrue(False, "blocking") else: break # The maximum length that can be sent in single record is 2**14 # record layer adds 5 byte on top of that self.assertEqual(len(mock_sock.sent), 5) for msg in mock_sock.sent: self.assertTrue(len(msg) <= 2**14 + 5)
def test__sendMsg(self): mockSock = MockSocket(bytearray(0)) sock = TLSRecordLayer(mockSock) sock.version = (3, 3) msg = Message(ContentType.handshake, bytearray(10)) # XXX using private method for result in sock._sendMsg(msg, False): if result in (0, 1): self.assertTrue(False, "Blocking socket") else: break self.assertEqual(len(mockSock.sent), 1) self.assertEqual( bytearray(b'\x16' + # handshake message b'\x03\x03' + # version b'\x00\x0a' + # payload length b'\x00' * 10 # payload ), mockSock.sent[0])
def test_queueMessage(self): sock = MockSocket(bytearray()) msgSocket = MessageSocket(sock, None) msg = Message(ContentType.alert, bytearray(b'\xff\xbb')) for res in msgSocket.queueMessage(msg): if res in (0, 1): self.assertTrue(False, "Blocking queue") else: break self.assertEqual(len(sock.sent), 0) msg = Message(ContentType.alert, bytearray(b'\xff\xaa')) for res in msgSocket.queueMessage(msg): if res in (0, 1): self.assertTrue(False, "Blocking queue") else: break self.assertEqual(len(sock.sent), 0) for res in msgSocket.flush(): if res in (0, 1): self.assertTrue(False, "Blocking flush") else: break self.assertEqual(len(sock.sent), 1) self.assertEqual(sock.sent[0], bytearray( b'\x15' + b'\x00\x00' + b'\x00\x04' + b'\xff\xbb' + b'\xff\xaa'))
def test_write_with_BEAST_record_splitting_and_empty_write(self): mock_sock = MockSocket(bytearray(0)) record_layer = TLSRecordLayer(mock_sock) record_layer.version = (3, 1) record_layer.closed = False record_layer._recordLayer.calcPendingStates( CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, bytearray(48), bytearray(32), bytearray(32), None) record_layer._recordLayer.changeWriteState() record_layer.write(bytearray(0)) self.assertEqual(len(mock_sock.sent), 1) msg1 = mock_sock.sent[0] self.assertEqual( bytearray( b'\x17' + # application data b'\x03\x01' + # TLSv1.0 b'\x00\x20' # length 32 bytes = data(0) + MAC(20) + padding(12) ), msg1[:5]) self.assertEqual(len(msg1[5:]), 32)
def test__getNextRecord(self): mockSock = MockSocket( bytearray(b'\x16' + # type - handshake b'\x03\x03' + # TLSv1.2 b'\x00\x04' + # length b'\x00' * 4)) sock = TLSRecordLayer(mockSock) sock.version = (3, 3) # XXX using private method! for result in sock._getNextRecord(): if result in (0, 1): self.assertTrue(False, "blocking socket") else: break header, data = result data = data.bytes self.assertEqual(data, bytearray(4)) self.assertEqual(header.type, ContentType.handshake) self.assertEqual(header.version, (3, 3)) self.assertEqual(header.length, 0)
def test_recvMessageBlocking(self): defragmenter = Defragmenter() defragmenter.addStaticSize(21, 2) sock = MockSocket(bytearray( b'\x15' + # message type b'\x03\x03' + # TLS version b'\x00\x02' + # payload length b'\xff\xff' # message ), blockEveryOther=True, maxRet=1) msgSock = MessageSocket(sock, defragmenter) res = msgSock.recvMessageBlocking() self.assertIsNotNone(res) header, parser = res self.assertEqual(header.type, 21) self.assertEqual(parser.bytes, bytearray(b'\xff\xff'))
def test__getNextRecord_with_slow_socket(self): mockSock = MockSocket( bytearray(b'\x16' + # type - handshake b'\x03\x03' + # TLSv1.2 b'\x00\x04' + # length b'\x00' * 4), maxRet=1, blockEveryOther=True) sock = TLSRecordLayer(mockSock) gotRetry = False # XXX using private method! for result in sock._getNextRecord(): if result in (0, 1): gotRetry = True else: break header, data = result data = data.bytes self.assertTrue(gotRetry) self.assertEqual(bytearray(4), data)
def test__getNextRecord_with_SSL2_record(self): mockSock = MockSocket( bytearray(b'\x80' + # tag b'\x04' + # length b'\x00' * 4)) sock = TLSRecordLayer(mockSock) # XXX using private method! for result in sock._getNextRecord(): if result in (0, 1): self.assertTrue(False, "blocking socket") else: break header, data = result data = data.bytes self.assertTrue(header.ssl2) self.assertEqual(ContentType.handshake, header.type) self.assertEqual(4, header.length) self.assertEqual((2, 0), header.version) self.assertEqual(bytearray(4), data)
def test(self): sock = MockSocket(server_hello_ciphertext) record_layer = RecordLayer(sock) ext = [SNIExtension().create(bytearray(b'server')), TLSExtension(extType=ExtensionType.renegotiation_info) .create(bytearray(b'\x00')), SupportedGroupsExtension().create([GroupName.x25519, GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1, GroupName.ffdhe2048, GroupName.ffdhe3072, GroupName.ffdhe4096, GroupName.ffdhe6144, GroupName.ffdhe8192]), ECPointFormatsExtension().create([ECPointFormat.uncompressed]), TLSExtension(extType=35), ClientKeyShareExtension().create([KeyShareEntry().create(GroupName.x25519, client_key_public, client_key_private)]), SupportedVersionsExtension().create([TLS_1_3_DRAFT, (3, 3), (3, 2)]), SignatureAlgorithmsExtension().create([(HashAlgorithm.sha256, SignatureAlgorithm.ecdsa), (HashAlgorithm.sha384, SignatureAlgorithm.ecdsa), (HashAlgorithm.sha512, SignatureAlgorithm.ecdsa), (HashAlgorithm.sha1, SignatureAlgorithm.ecdsa), SignatureScheme.rsa_pss_sha256, SignatureScheme.rsa_pss_sha384, SignatureScheme.rsa_pss_sha512, SignatureScheme.rsa_pkcs1_sha256, SignatureScheme.rsa_pkcs1_sha384, SignatureScheme.rsa_pkcs1_sha512, SignatureScheme.rsa_pkcs1_sha1, (HashAlgorithm.sha256, SignatureAlgorithm.dsa), (HashAlgorithm.sha384, SignatureAlgorithm.dsa), (HashAlgorithm.sha512, SignatureAlgorithm.dsa), (HashAlgorithm.sha1, SignatureAlgorithm.dsa)]), TLSExtension(extType=45).create(bytearray(b'\x01\x01')), TLSExtension(extType=ExtensionType.client_hello_padding) .create(bytearray(252)) ] client_hello = ClientHello() client_hello.create((3, 3), bytearray(b'\xaf!\x15k\x04\xdbc\x9ef\x15J\x1f\xe5' b'\xad\xfa\xea\xdf\x9eA4\x16\x00\rW\xb8' b'\xe1\x12mM\x11\x9a\x8b'), bytearray(b''), [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0xCCA9, CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 0x0032, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 0x0038, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 0x0013, CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256, CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, CipherSuite.TLS_RSA_WITH_RC4_128_SHA, CipherSuite.TLS_RSA_WITH_RC4_128_MD5], extensions=ext) self.assertEqual(client_hello.write(), client_hello_ciphertext[5:]) for result in record_layer.recvRecord(): # check if non-blocking self.assertNotIn(result, (0, 1)) header, parser = result hs_type = parser.get(1) self.assertEqual(hs_type, HandshakeType.server_hello) server_hello = ServerHello().parse(parser) self.assertEqual(server_hello.server_version, TLS_1_3_DRAFT) self.assertEqual(server_hello.cipher_suite, CipherSuite.TLS_AES_128_GCM_SHA256) server_key_share = server_hello.getExtension(ExtensionType.key_share) server_key_share = server_key_share.server_share self.assertEqual(server_key_share.group, GroupName.x25519) # for TLS_AES_128_GCM_SHA256: prf_name = 'sha256' prf_size = 256 // 8 secret = bytearray(prf_size) psk = bytearray(prf_size) # early secret secret = secureHMAC(secret, psk, prf_name) self.assertEqual(secret, str_to_bytearray( "33ad0a1c607ec03b 09e6cd9893680ce2" "10adf300aa1f2660 e1b22e10f170f92a")) # derive secret for handshake secret = derive_secret(secret, b"derived", None, prf_name) self.assertEqual(secret, str_to_bytearray( "6f2615a108c702c5 678f54fc9dbab697" "16c076189c48250c ebeac3576c3611ba")) # extract secret "handshake" Z = x25519(client_key_private, server_key_share.key_exchange) self.assertEqual(Z, str_to_bytearray( "f677c3cdac26a755 455b130efa9b1a3f" "3cafb153544ca46a ddf670df199d996e")) secret = secureHMAC(secret, Z, prf_name) self.assertEqual(secret, str_to_bytearray( "0cefce00d5d29fd0 9f5de36c86fc8e72" "99b4ad11ba4211c6 7063c2cc539fc4f9")) handshake_hashes = HandshakeHashes() handshake_hashes.update(client_hello_plaintext) handshake_hashes.update(server_hello_payload) # derive "tls13 c hs traffic" c_hs_traffic = derive_secret(secret, bytearray(b'c hs traffic'), handshake_hashes, prf_name) self.assertEqual(c_hs_traffic, str_to_bytearray( "5a63db760b817b1b da96e72832333aec" "6a177deeadb5b407 501ac10c17dac0a4")) s_hs_traffic = derive_secret(secret, bytearray(b's hs traffic'), handshake_hashes, prf_name) self.assertEqual(s_hs_traffic, str_to_bytearray( "3aa72a3c77b791e8 f4de243f9ccce172" "941f8392aeb05429 320f4b572ccfe744")) # derive master secret secret = derive_secret(secret, b"derived", None, prf_name) self.assertEqual(secret, str_to_bytearray( "32cadf38f3089048 5c54bf4f1184eaa5" "569eeef15a43f3c7 6ab33965a47c9ff6")) # extract secret "master secret = secureHMAC(secret, bytearray(prf_size), prf_name) self.assertEqual(secret, str_to_bytearray( "6c6d4b3e7c925460 82d7b7a32f6ce219" "3804f1bb930fed74 5c6b93c71397f424"))
def prepare_mock_socket_with_handshake_failure(self): alertObj = Alert().create(AlertDescription.handshake_failure) alert = alertObj.write() header = RecordHeader3().create((3, 3), ContentType.alert, len(alert)) return MockSocket(header.write() + alert)
def test(self): sock = MockSocket(server_hello_ciphertext) record_layer = RecordLayer(sock) ext = [ SNIExtension().create(bytearray(b'server')), TLSExtension(extType=ExtensionType.renegotiation_info).create( bytearray(b'\x00')), SupportedGroupsExtension().create([ GroupName.x25519, GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1, GroupName.ffdhe2048, GroupName.ffdhe3072, GroupName.ffdhe4096, GroupName.ffdhe6144, GroupName.ffdhe8192 ]), TLSExtension(extType=35), ClientKeyShareExtension().create([ KeyShareEntry().create(GroupName.x25519, client_key_public, client_key_private) ]), SupportedVersionsExtension().create([(3, 4)]), SignatureAlgorithmsExtension().create([ SignatureScheme.ecdsa_secp256r1_sha256, SignatureScheme.ecdsa_secp384r1_sha384, SignatureScheme.ecdsa_secp521r1_sha512, (HashAlgorithm.sha1, SignatureAlgorithm.ecdsa), SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_rsae_sha384, SignatureScheme.rsa_pss_rsae_sha512, SignatureScheme.rsa_pkcs1_sha256, SignatureScheme.rsa_pkcs1_sha384, SignatureScheme.rsa_pkcs1_sha512, SignatureScheme.rsa_pkcs1_sha1, (HashAlgorithm.sha256, SignatureAlgorithm.dsa), (HashAlgorithm.sha384, SignatureAlgorithm.dsa), (HashAlgorithm.sha512, SignatureAlgorithm.dsa), (HashAlgorithm.sha1, SignatureAlgorithm.dsa) ]), TLSExtension(extType=45).create(bytearray(b'\x01\x01')), RecordSizeLimitExtension().create(16385) ] client_hello = ClientHello() client_hello.create((3, 3), bytearray(b'\xcb4\xec\xb1\xe7\x81c' b'\xba\x1c8\xc6\xda\xcb' b'\x19jm\xff\xa2\x1a\x8d' b'\x99\x12\xec\x18\xa2' b'\xefb\x83\x02M\xec\xe7'), bytearray(b''), [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_AES_256_GCM_SHA384 ], extensions=ext) self.assertEqual(client_hello.write(), client_hello_ciphertext[5:]) for result in record_layer.recvRecord(): # check if non-blocking self.assertNotIn(result, (0, 1)) break header, parser = result hs_type = parser.get(1) self.assertEqual(hs_type, HandshakeType.server_hello) server_hello = ServerHello().parse(parser) self.assertEqual(server_hello.server_version, (3, 3)) self.assertEqual(server_hello.cipher_suite, CipherSuite.TLS_AES_128_GCM_SHA256) server_key_share = server_hello.getExtension(ExtensionType.key_share) server_key_share = server_key_share.server_share self.assertEqual(server_key_share.group, GroupName.x25519) # for TLS_AES_128_GCM_SHA256: prf_name = 'sha256' prf_size = 256 // 8 secret = bytearray(prf_size) psk = bytearray(prf_size) # early secret secret = secureHMAC(secret, psk, prf_name) self.assertEqual( secret, clean(""" 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a """)) # derive secret for handshake secret = derive_secret(secret, b"derived", None, prf_name) self.assertEqual( secret, clean(""" 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba """)) # extract secret "handshake" Z = x25519(client_key_private, server_key_share.key_exchange) self.assertEqual( Z, clean(""" 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d """)) secret = secureHMAC(secret, Z, prf_name) self.assertEqual( secret, clean(""" 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac """)) handshake_hashes = HandshakeHashes() handshake_hashes.update(client_hello_plaintext) handshake_hashes.update(server_hello_payload) # derive "tls13 c hs traffic" c_hs_traffic = derive_secret(secret, bytearray(b'c hs traffic'), handshake_hashes, prf_name) self.assertEqual( c_hs_traffic, clean(""" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 """)) s_hs_traffic = derive_secret(secret, bytearray(b's hs traffic'), handshake_hashes, prf_name) self.assertEqual( s_hs_traffic, clean(""" b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38 """)) # derive master secret secret = derive_secret(secret, b"derived", None, prf_name) self.assertEqual( secret, clean(""" 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4 """)) # extract secret "master" secret = secureHMAC(secret, bytearray(prf_size), prf_name) self.assertEqual( secret, clean(""" 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 """)) # derive write keys for handshake data server_hs_write_trafic_key = HKDF_expand_label(s_hs_traffic, b"key", b"", 16, prf_name) self.assertEqual( server_hs_write_trafic_key, clean(""" 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc """)) server_hs_write_trafic_iv = HKDF_expand_label(s_hs_traffic, b"iv", b"", 12, prf_name) self.assertEqual( server_hs_write_trafic_iv, clean(""" 5d 31 3e b2 67 12 76 ee 13 00 0b 30 """)) # derive key for Finished message server_finished_key = HKDF_expand_label(s_hs_traffic, b"finished", b"", prf_size, prf_name) self.assertEqual( server_finished_key, clean(""" 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85 c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8 """)) # Update the handshake transcript handshake_hashes.update(server_encrypted_extensions) handshake_hashes.update(server_certificate_message) handshake_hashes.update(server_certificateverify_message) hs_transcript = handshake_hashes.digest(prf_name) server_finished = secureHMAC(server_finished_key, hs_transcript, prf_name) self.assertEqual( server_finished, clean(""" 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18 """)) server_finished_message = Finished((3, 4)).create(server_finished) server_finished_payload = server_finished_message.write() # update handshake transcript to include Finished payload handshake_hashes.update(server_finished_payload) # derive keys for client application traffic c_ap_traffic = derive_secret(secret, b"c ap traffic", handshake_hashes, prf_name) self.assertEqual( c_ap_traffic, clean(""" 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5 """)) # derive keys for server application traffic s_ap_traffic = derive_secret(secret, b"s ap traffic", handshake_hashes, prf_name) self.assertEqual( s_ap_traffic, clean(""" a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 """)) # derive exporter master secret exp_master = derive_secret(secret, b"exp master", handshake_hashes, prf_name) self.assertEqual( exp_master, clean(""" fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50 """)) # derive write traffic keys for app data server_write_traffic_key = HKDF_expand_label(s_ap_traffic, b"key", b"", 16, prf_name) self.assertEqual( server_write_traffic_key, clean(""" 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56 """)) server_write_traffic_iv = HKDF_expand_label(s_ap_traffic, b"iv", b"", 12, prf_name) self.assertEqual( server_write_traffic_iv, clean(""" cf 78 2b 88 dd 83 54 9a ad f1 e9 84 """)) # derive read traffic keys for app data server_read_hs_key = HKDF_expand_label(c_hs_traffic, b"key", b"", 16, prf_name) self.assertEqual( server_read_hs_key, clean(""" db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01 """)) server_read_hs_iv = HKDF_expand_label(c_hs_traffic, b"iv", b"", 12, prf_name) self.assertEqual( server_read_hs_iv, clean(""" 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f """))