def test_HMAC_expand_2(self): # RFC 5869 Appendix A.2 Test Vector 2 self.assertEqual( HKDF_expand( numberToByteArray( int( '0x06a6b88c5853361a06104c9ceb35b45cef7600149' '04671014a193f40c15fc244', 16), 32), numberToByteArray( int( '0xb0b1b2b3b4b5b6b7' 'b8b9babbbcbdbebfc0' 'c1c2c3c4c5c6c7c8c9' 'cacbcccdcecfd0d1d2' 'd3d4d5d6d7d8d9dadb' 'dcdddedfe0e1e2e3e4' 'e5e6e7e8e9eaebeced' 'eeeff0f1f2f3f4f5f6' 'f7f8f9fafbfcfdf' 'eff', 16), 80), 82, 'sha256'), numberToByteArray( int( '0xb11e398dc80327a1c8e7f78c596a' '49344f012eda2d4efad8a050cc4c19' 'afa97c59045a99cac7827271cb41c6' '5e590e09da3275600c2f09b8367793' 'a9aca3db71cc30c58179ec3e87c14c' '01d5c1f3434f1d87', 16), 82))
def test_HMAC_expand_5(self): # RFC 5869 Appendix A.5 Test Vector 5 self.assertEqual( HKDF_expand( numberToByteArray( int('0x8adae09a2a307059' '478d309b26c4115a22' '4cfaf6', 16), 20), numberToByteArray( int( '0xb0b1b2b3b4b5b6b7' 'b8b9babbbcbdbebfc0' 'c1c2c3c4c5c6c7c8c9' 'cacbcccdcecfd0d1d2' 'd3d4d5d6d7d8d9dadb' 'dcdddedfe0e1e2e3e4' 'e5e6e7e8e9eaebeced' 'eeeff0f1f2f3f4f5f6' 'f7f8f9fafbfcfdfe' 'ff', 16), 80), 82, 'sha1'), numberToByteArray( int( '0x0bd770a74d1160f7c9f12cd5912a' '06ebff6adcae899d92191fe4305673' 'ba2ffe8fa3f1a4e5ad79f3f334b3b2' '02b2173c486ea37ce3d397ed034c7f' '9dfeb15c5e927336d0441f4c4300e2' 'cff0d0900b52d3b4', 16), 82))
def test_HMAC_expand_6(self): # RFC 5869 Appendix A.6 Test Vector 6 self.assertEqual(HKDF_expand(numberToByteArray(int('0xda8c8a73c7fa7728' '8ec6f5e7c297786aa0' 'd32d01', 16), 20), bytearray(), 42, 'sha1'), numberToByteArray(int('0x0ac1af7002b3d761d1e55298da9d' '0506b9ae52057220a306e07b6b87e8' 'df21d0ea00033de03984d34918', 16), 42))
def test_HMAC_expand_7(self): # RFC 5869 Appendix A.7 Test Vector 7 self.assertEqual(HKDF_expand(numberToByteArray(int('0x2adccada18779e7c' '2077ad2eb19d3f3e73' '1385dd', 16), 20), bytearray(), 42, 'sha1'), numberToByteArray(int('0x2c91117204d745f3500d636a62f6' '4f0ab3bae548aa53d423b0d1f27ebb' 'a6f5e5673a081d70cce7acfc48', 16), 42))
def test_HMAC_expand_4(self): # RFC 5869 Appendix A.4 Test Vector 4 self.assertEqual(HKDF_expand(numberToByteArray(int('0x9b6c18c432a7bf8f' '0e71c8eb88f4b30baa' '2ba243', 16), 20), numberToByteArray(int('0xf0f1f2f3f4f5f6f7' 'f8f9', 16), 10), 42, 'sha1'), numberToByteArray(int('0x085a01ea1b10f36933068b56efa5' 'ad81a4f14b822f5b091568a9cdd4f1' '55fda2c22e422478d305f3f896', 16), 42))
def test_HMAC_expand_3(self): # RFC 5869 Appendix A.3 Test Vector 3 self.assertEqual(HKDF_expand(numberToByteArray(int('0x19ef24a32c717b16' '7f33a91d6f648bdf96' '596776afdb6377ac43' '4c1c293ccb04', 16), 32), bytearray(), 42, 'sha256'), numberToByteArray(int('0x8da4e775a563c18f715f802a063c' '5a31b8a11f5c5ee1879ec3454e5f3c' '738d2d9d201395faa4b61a96c8', 16), 42))
def test_HMAC_expand_1(self): # RFC 5869 Appendix A.1 Test Vector 1 self.assertEqual(HKDF_expand(numberToByteArray(int('0x077709362c2e32df' '0ddc3f0dc47bba6390' 'b6c73bb50f9c3122ec' '844ad7c2b3e5', 16), 32), numberToByteArray(0xf0f1f2f3f4f5f6f7f8f9, 10), 42, 'sha256'), numberToByteArray(int('0x3cb25f25faacd57a90434f64d036' '2f2a2d2d0a90cf1a5a4c5db02d56ec' 'c4c5bf34007208d5b887185865', 16), 42))
def test_HMAC_expand_6(self): # RFC 5869 Appendix A.6 Test Vector 6 self.assertEqual( HKDF_expand( numberToByteArray( int('0xda8c8a73c7fa7728' '8ec6f5e7c297786aa0' 'd32d01', 16), 20), bytearray(), 42, 'sha1'), numberToByteArray( int( '0x0ac1af7002b3d761d1e55298da9d' '0506b9ae52057220a306e07b6b87e8' 'df21d0ea00033de03984d34918', 16), 42))
def test_HMAC_expand_7(self): # RFC 5869 Appendix A.7 Test Vector 7 self.assertEqual( HKDF_expand( numberToByteArray( int('0x2adccada18779e7c' '2077ad2eb19d3f3e73' '1385dd', 16), 20), bytearray(), 42, 'sha1'), numberToByteArray( int( '0x2c91117204d745f3500d636a62f6' '4f0ab3bae548aa53d423b0d1f27ebb' 'a6f5e5673a081d70cce7acfc48', 16), 42))
def _cbcmac_calc(self, nonce, aad, msg): L = 15 - len(nonce) mac_data = bytearray() # Flags constructed as in section 2.2 in the rfc flags = 64 * (len(aad) > 0) flags += 8 * ((self.tagLength - 2) // 2) flags += 1 * (L - 1) # Construct B_0 b_0 = bytearray([flags]) + nonce + numberToByteArray(len(msg), L) aad_len_encoded = bytearray() if len(aad) > 0: if len(aad) < (2**16 - 2**8): oct_size = 2 elif len(aad) < (2**32): oct_size = 4 aad_len_encoded = b'\xFF\xFE' else: oct_size = 8 aad_len_encoded = b'\xFF\xFF' aad_len_encoded += numberToByteArray(len(aad), oct_size) # Construct the bytearray that goes into the MAC mac_data += b_0 mac_data += aad_len_encoded mac_data += aad # We need to pad with zeroes before and after msg blocks are added self._pad_with_zeroes(mac_data, 16) if msg != b'': mac_data += msg self._pad_with_zeroes(mac_data, 16) # The mac data is now constructed and # we need to run in through AES-CBC with 0 IV self._cbc.IV = bytearray(b'\x00' * 16) cbcmac = self._cbc.encrypt(mac_data) # If the tagLength has default value 16, we return # the whole last block. Otherwise we return only # the first tagLength bytes from the last block if self.tagLength == 16: t = cbcmac[-16:] else: t = cbcmac[-16:-(16 - self.tagLength)] return t
def test_HMAC_expand_4(self): # RFC 5869 Appendix A.4 Test Vector 4 self.assertEqual( HKDF_expand( numberToByteArray( int('0x9b6c18c432a7bf8f' '0e71c8eb88f4b30baa' '2ba243', 16), 20), numberToByteArray(int('0xf0f1f2f3f4f5f6f7' 'f8f9', 16), 10), 42, 'sha1'), numberToByteArray( int( '0x085a01ea1b10f36933068b56efa5' 'ad81a4f14b822f5b091568a9cdd4f1' '55fda2c22e422478d305f3f896', 16), 42))
def test_HMAC_expand_3(self): # RFC 5869 Appendix A.3 Test Vector 3 self.assertEqual( HKDF_expand( numberToByteArray( int( '0x19ef24a32c717b16' '7f33a91d6f648bdf96' '596776afdb6377ac43' '4c1c293ccb04', 16), 32), bytearray(), 42, 'sha256'), numberToByteArray( int( '0x8da4e775a563c18f715f802a063c' '5a31b8a11f5c5ee1879ec3454e5f3c' '738d2d9d201395faa4b61a96c8', 16), 42))
def test_ECDHE_key_exchange(self): srv_key_ex = self.keyExchange.makeServerKeyExchange('sha1') KeyExchange.verifyServerKeyExchange(srv_key_ex, self.srv_pub_key, self.client_hello.random, self.server_hello.random, [(HashAlgorithm.sha1, SignatureAlgorithm.rsa)]) curveName = GroupName.toStr(srv_key_ex.named_curve) curve = getCurveByName(curveName) generator = curve.generator cln_Xc = ecdsa.util.randrange(generator.order()) cln_Ys = decodeX962Point(srv_key_ex.ecdh_Ys, curve) cln_Yc = encodeX962Point(generator * cln_Xc) cln_key_ex = ClientKeyExchange(self.cipher_suite, (3, 3)) cln_key_ex.createECDH(cln_Yc) cln_S = cln_Ys * cln_Xc cln_premaster = numberToByteArray(cln_S.x(), getPointByteSize(cln_S)) srv_premaster = self.keyExchange.processClientKeyExchange(cln_key_ex) self.assertEqual(cln_premaster, srv_premaster)
def seal(self, nonce, msg, aad): if len(nonce) != 12: raise ValueError("Bad nonce length") L = 15 - len(nonce) # We construct the key stream blocks. # S_0 is not used for encrypting the message, it is only used # to compute the authentication value. # S_1..S_n are used to encrypt the message. flags = L - 1 s_0 = bytearray([flags]) + nonce + numberToByteArray(0, L) mac = self._cbcmac_calc(nonce, aad, msg) self._ctr.counter = s_0 if self.tagLength == 16: auth_value = self._ctr.encrypt(mac) else: assert self.tagLength == 8 self._pad_with_zeroes(mac, 16) auth_value = self._ctr.encrypt(mac)[:8] enc_msg = self._ctr.encrypt(msg) ciphertext = enc_msg + auth_value return ciphertext
def open(self, nonce, ciphertext, aad): if len(nonce) != 12: raise ValueError("Bad nonce length") if self.tagLength == 16 and len(ciphertext) < 16: return None if self.tagLength == 8 and len(ciphertext) < 8: return None L = 15 - len(nonce) flags = L - 1 # Same construction as in seal function s_0 = bytearray([flags]) + nonce + numberToByteArray(0, L) auth_value = ciphertext[-self.tagLength:] # We decrypt the auth value self._ctr.counter = s_0 received_mac = self._ctr.decrypt(auth_value) msg = self._ctr.decrypt(ciphertext) msg = msg[:-self.tagLength] computed_mac = self._cbcmac_calc(nonce, aad, msg) # Compare the mac vlaue is the same as the one we computed if received_mac != computed_mac: return None return msg
def test_SRP_key_exchange_without_signature(self): self.cipher_suite = CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA self.keyExchange.cipherSuite = self.cipher_suite self.server_hello.cipher_suite = self.cipher_suite srv_key_ex = self.keyExchange.makeServerKeyExchange() a = bytesToNumber(getRandomBytes(32)) A = powMod(srv_key_ex.srp_g, a, srv_key_ex.srp_N) x = makeX(srv_key_ex.srp_s, bytearray(b'user'), bytearray(b'password')) v = powMod(srv_key_ex.srp_g, x, srv_key_ex.srp_N) u = makeU(srv_key_ex.srp_N, A, srv_key_ex.srp_B) k = makeK(srv_key_ex.srp_N, srv_key_ex.srp_g) S = powMod((srv_key_ex.srp_B - (k*v)) % srv_key_ex.srp_N, a+(u*x), srv_key_ex.srp_N) cln_premaster = numberToByteArray(S) cln_key_ex = ClientKeyExchange(self.cipher_suite, (3, 3)).createSRP(A) srv_premaster = self.keyExchange.processClientKeyExchange(cln_key_ex) self.assertEqual(cln_premaster, srv_premaster)
def test_SRP_key_exchange(self): srv_key_ex = self.keyExchange.makeServerKeyExchange('sha256') KeyExchange.verifyServerKeyExchange(srv_key_ex, self.srv_pub_key, self.client_hello.random, self.server_hello.random, [(HashAlgorithm.sha256, SignatureAlgorithm.rsa)]) a = bytesToNumber(getRandomBytes(32)) A = powMod(srv_key_ex.srp_g, a, srv_key_ex.srp_N) x = makeX(srv_key_ex.srp_s, bytearray(b'user'), bytearray(b'password')) v = powMod(srv_key_ex.srp_g, x, srv_key_ex.srp_N) u = makeU(srv_key_ex.srp_N, A, srv_key_ex.srp_B) k = makeK(srv_key_ex.srp_N, srv_key_ex.srp_g) S = powMod((srv_key_ex.srp_B - (k*v)) % srv_key_ex.srp_N, a+(u*x), srv_key_ex.srp_N) cln_premaster = numberToByteArray(S) cln_key_ex = ClientKeyExchange(self.cipher_suite, (3, 3)).createSRP(A) srv_premaster = self.keyExchange.processClientKeyExchange(cln_key_ex) self.assertEqual(cln_premaster, srv_premaster)
def __call__(self, hostname): """Generate a client hello object, use hostname in SNI extension.""" # SNI is special in that we don't want to send it if it is empty if self.extensions: sni = next((x for x in self.extensions if isinstance(x, SNIExtension)), None) if sni: if hostname is not None: if sni.serverNames is None: sni.serverNames = [] sni.hostNames = [hostname] else: # but if we were not provided with a host name, we want # to remove empty extension if sni.serverNames is None: self.extensions = [x for x in self.extensions if not isinstance(x, SNIExtension)] if self.random: rand = self.random else: # we're not doing any crypto with it, just need "something" # TODO: place unix time at the beginning rand = numberToByteArray(random.getrandbits(256), 32) ch = ClientHello(self.ssl2).create(self.version, rand, self.session_id, self.ciphers, extensions=self.extensions) ch.compression_methods = self.compression_methods for cb in self.callbacks: ch = cb(ch) return ch
def test_HMAC_expand_1(self): # RFC 5869 Appendix A.1 Test Vector 1 self.assertEqual( HKDF_expand( numberToByteArray( int( '0x077709362c2e32df' '0ddc3f0dc47bba6390' 'b6c73bb50f9c3122ec' '844ad7c2b3e5', 16), 32), numberToByteArray(0xf0f1f2f3f4f5f6f7f8f9, 10), 42, 'sha256'), numberToByteArray( int( '0x3cb25f25faacd57a90434f64d036' '2f2a2d2d0a90cf1a5a4c5db02d56ec' 'c4c5bf34007208d5b887185865', 16), 42))
def _newRawPrivateKeyOp(self, m, original_rawPrivateKeyOp, subs=None, xors=None): signBytes = numberToByteArray(m, numBytes(self.n)) signBytes = substitute_and_xor(signBytes, subs, xors) m = bytesToNumber(signBytes) return original_rawPrivateKeyOp(m)
def generate(self, status): """Create a Client Key Exchange message.""" if self.version is None: self.version = status.version if self.cipher is None: self.cipher = status.cipher if self.client_version is None: self.client_version = status.client_version cke = ClientKeyExchange(self.cipher, self.version) if self.cipher in CipherSuite.certSuites: if self.modulus_as_encrypted_premaster: public_key = status.get_server_public_key() self.encrypted_premaster = numberToByteArray(public_key.n) if self.encrypted_premaster: cke.createRSA(self.encrypted_premaster) else: assert len(self.premaster_secret) > 1 self.premaster_secret[0] = self.client_version[0] self.premaster_secret[1] = self.client_version[1] status.premaster_secret = self.premaster_secret public_key = status.get_server_public_key() cke.createRSA(self._encrypt_with_fuzzing(public_key)) elif self.cipher in CipherSuite.dheCertSuites: if self.dh_Yc is not None: cke = ClientKeyExchange(self.cipher, self.version).createDH(self.dh_Yc) elif self.p_as_share or self.p_1_as_share: ske = next((i for i in reversed(status.handshake_messages) if isinstance(i, ServerKeyExchange)), None) assert ske, "No server key exchange in messages" if self.p_as_share: cke = ClientKeyExchange(self.cipher, self.version).createDH(ske.dh_p) else: cke = ClientKeyExchange(self.cipher, self.version).createDH(ske.dh_p-1) else: cke = status.key_exchange.makeClientKeyExchange() elif self.cipher in CipherSuite.ecdhAllSuites: if self.ecdh_Yc is not None: cke = ClientKeyExchange(self.cipher, self.version).createECDH(self.ecdh_Yc) else: cke = status.key_exchange.makeClientKeyExchange() else: raise AssertionError("Unknown cipher/key exchange type") self.msg = cke return cke
def _newRawPrivateKeyOp(self, m, original_rawPrivateKeyOp, subs=None, xors=None): signBytes = numberToByteArray(m, numBytes(self.n)) signBytes = substitute_and_xor(signBytes, subs, xors) m = bytesToNumber(signBytes) # RSA operations are defined only on numbers that are smaller # than the modulus, so ensure the XORing or substitutions # didn't break it (especially necessary for pycrypto as # it raises exception in such case) if m > self.n: m %= self.n return original_rawPrivateKeyOp(m)
def test_HMAC_expand_2(self): # RFC 5869 Appendix A.2 Test Vector 2 self.assertEqual(HKDF_expand( numberToByteArray(int('0x06a6b88c5853361a06104c9ceb35b45cef7600149' '04671014a193f40c15fc244', 16), 32), numberToByteArray(int('0xb0b1b2b3b4b5b6b7' 'b8b9babbbcbdbebfc0' 'c1c2c3c4c5c6c7c8c9' 'cacbcccdcecfd0d1d2' 'd3d4d5d6d7d8d9dadb' 'dcdddedfe0e1e2e3e4' 'e5e6e7e8e9eaebeced' 'eeeff0f1f2f3f4f5f6' 'f7f8f9fafbfcfdf' 'eff', 16), 80), 82, 'sha256'), numberToByteArray(int('0xb11e398dc80327a1c8e7f78c596a' '49344f012eda2d4efad8a050cc4c19' 'afa97c59045a99cac7827271cb41c6' '5e590e09da3275600c2f09b8367793' 'a9aca3db71cc30c58179ec3e87c14c' '01d5c1f3434f1d87', 16), 82))
def test_HMAC_expand_5(self): # RFC 5869 Appendix A.5 Test Vector 5 self.assertEqual(HKDF_expand(numberToByteArray(int('0x8adae09a2a307059' '478d309b26c4115a22' '4cfaf6', 16), 20), numberToByteArray(int('0xb0b1b2b3b4b5b6b7' 'b8b9babbbcbdbebfc0' 'c1c2c3c4c5c6c7c8c9' 'cacbcccdcecfd0d1d2' 'd3d4d5d6d7d8d9dadb' 'dcdddedfe0e1e2e3e4' 'e5e6e7e8e9eaebeced' 'eeeff0f1f2f3f4f5f6' 'f7f8f9fafbfcfdfe' 'ff', 16), 80), 82, 'sha1'), numberToByteArray(int('0x0bd770a74d1160f7c9f12cd5912a' '06ebff6adcae899d92191fe4305673' 'ba2ffe8fa3f1a4e5ad79f3f334b3b2' '02b2173c486ea37ce3d397ed034c7f' '9dfeb15c5e927336d0441f4c4300e2' 'cff0d0900b52d3b4', 16), 82))
def test_DHE_RSA_key_exchange(self): srv_key_ex = self.keyExchange.makeServerKeyExchange('sha1') cln_X = bytesToNumber(getRandomBytes(32)) cln_Yc = powMod(srv_key_ex.dh_g, cln_X, srv_key_ex.dh_p) cln_secret = numberToByteArray(powMod(srv_key_ex.dh_Ys, cln_X, srv_key_ex.dh_p)) cln_key_ex = ClientKeyExchange(self.cipher_suite, (3, 3)) cln_key_ex.createDH(cln_Yc) srv_secret = self.keyExchange.processClientKeyExchange(cln_key_ex) self.assertEqual(cln_secret, srv_secret)
def generate(self, status): if self.version is None: self.version = status.version if self.cipher is None: self.cipher = status.cipher if self.client_version is None: self.client_version = status.client_version cke = ClientKeyExchange(self.cipher, self.version) if self.cipher in CipherSuite.certSuites: if self.modulus_as_encrypted_premaster: public_key = status.get_server_public_key() self.encrypted_premaster = numberToByteArray(public_key.n) if self.encrypted_premaster: cke.createRSA(self.encrypted_premaster) else: assert len(self.premaster_secret) > 1 self.premaster_secret[0] = self.client_version[0] self.premaster_secret[1] = self.client_version[1] status.premaster_secret = self.premaster_secret public_key = status.get_server_public_key() cke.createRSA(self._encrypt_with_fuzzing(public_key)) elif self.cipher in CipherSuite.dheCertSuites: if self.dh_Yc is not None: cke = ClientKeyExchange(self.cipher, self.version).createDH(self.dh_Yc) else: cke = status.key_exchange.makeClientKeyExchange() elif self.cipher in CipherSuite.ecdhAllSuites: if self.ecdh_Yc is not None: cke = ClientKeyExchange(self.cipher, self.version).createECDH(self.ecdh_Yc) else: cke = status.key_exchange.makeClientKeyExchange() else: raise AssertionError("Unknown cipher/key exchange type") self.msg = cke return cke
def __call__(self, hostname): """Generate a client hello object, use hostname in SNI extension.""" # SNI is special in that we don't want to send it if it is empty if self.extensions: sni = next( (x for x in self.extensions if isinstance(x, SNIExtension)), None) if sni: if hostname is not None: if sni.serverNames is None: sni.serverNames = [] sni.hostNames = [hostname] else: # but if we were not provided with a host name, we want # to remove empty extension if sni.serverNames is None: self.extensions = [ x for x in self.extensions if not isinstance(x, SNIExtension) ] if self.random: rand = self.random else: # we're not doing any crypto with it, just need "something" # TODO: place unix time at the beginning rand = numberToByteArray(random.getrandbits(256), 32) ch = ClientHello(self.ssl2).create(self.version, rand, self.session_id, self.ciphers, extensions=self.extensions) ch.compression_methods = self.compression_methods for cb in self.callbacks: ch = cb(ch) return ch
def test_very_large_number(self): self.assertEqual(numberToByteArray((1<<128)-1, endian="little"), bytearray(b'\xff'*16))
def test_numberToByteArray_with_not_enough_length(self): self.assertEqual(numberToByteArray(0x0a0b0c, 2), bytearray(b'\x0b\x0c'))
def test_numberToByteArray_with_length(self): self.assertEqual(numberToByteArray(0xff, 2), bytearray(b'\x00\xff'))
def test_numberToByteArray(self): self.assertEqual(numberToByteArray(0x00000000000001), bytearray(b'\x01'))
def test_small_number(self, number): self.assertEqual(numberToByteArray(number, 1), bytearray(struct.pack(">B", number)))
def test_with_bad_endian_type(self): with self.assertRaises(ValueError): numberToByteArray(1, endian="middle")
def test_big_number(self, number): self.assertEqual(numberToByteArray(number, 4), bytearray(struct.pack(">L", number)))
def test_with_large_number_of_bytes_in_little_endian(self): self.assertEqual(numberToByteArray(1, 16, endian="little"), bytearray(b'\x01' + b'\x00'*15))
def test_numberToByteArray_with_not_enough_length_little_endian(self): self.assertEqual(numberToByteArray(0x0a0b0c, 2, endian="little"), bytearray(b'\x0c\x0b'))
def test_small_number_little_endian(self, number): self.assertEqual(numberToByteArray(number, 1, endian="little"), bytearray(struct.pack("<B", number)))
def test_with_large_number_of_bytes_in_little_endian(self): self.assertEqual(numberToByteArray(1, 16, endian="little"), bytearray(b'\x01' + b'\x00' * 15))
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() expected_failures = {} last_exp_tmp = None argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X:n:", ["help"]) for opt, arg in opts: if opt == '-h': host = arg elif opt == '-p': port = int(arg) elif opt == '-e': run_exclude.add(arg) elif opt == '-x': expected_failures[arg] = None last_exp_tmp = str(arg) elif opt == '-X': if not last_exp_tmp: raise ValueError("-x has to be specified before -X") expected_failures[last_exp_tmp] = str(arg) elif opt == '-n': num_limit = int(arg) elif opt == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None conversations = {} conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} groups = GroupName.allFF ext[ExtensionType.key_share] = key_share_ext_gen(groups) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256] sig_algs += ECDSA_SIG_TLS1_3_ALL ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectEncryptedExtensions()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child(ApplicationDataGenerator( bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child(AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation for group in groups: conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} ext[ExtensionType.key_share] = key_share_ext_gen([group]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectEncryptedExtensions()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child(ApplicationDataGenerator( bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child(AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity - {0}".format(GroupName.toRepr(group))] = conversation # duplicated key share entry conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_shares = [] key_shares.append(key_share_gen(group)) key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension()\ .create(key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - duplicated key share entry" .format(GroupName.toRepr(group))] = conversation # padded representation conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = key_share_gen(group) key_share.key_exchange += bytearray(b'\x00') ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - right 0-padded key_share" .format(GroupName.toRepr(group))] = conversation # truncated representation (given that all groups use safe primes, # any integer between 1 and p-1 is a valid key share, it's just that # after truncation we don't know the private key that generates it) conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = key_share_gen(group) key_share.key_exchange.pop() ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - right-truncated key_share" .format(GroupName.toRepr(group))] = conversation # key share from wrong group conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = key_share_gen(group) if group == GroupName.ffdhe2048: key_share2 = key_share_gen(GroupName.ffdhe3072) else: key_share2 = key_share_gen(GroupName.ffdhe2048) key_share.key_exchange = key_share2.key_exchange ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - key share from other group" .format(GroupName.toRepr(group))] = conversation # just 0 conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = KeyShareEntry().create(group, bytearray(b'\x00')) ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - 0 as one byte" .format(GroupName.toRepr(group))] = conversation # 0 key share conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = key_share_gen(group) key_share.key_exchange = bytearray(len(key_share.key_exchange)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - 0 as key share" .format(GroupName.toRepr(group))] = conversation # 1 key share conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = key_share_gen(group) key_share.key_exchange = bytearray(len(key_share.key_exchange)) key_share.key_exchange[-1] = 0x01 ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - 1 as key share" .format(GroupName.toRepr(group))] = conversation # all bits set key share conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = key_share_gen(group) key_share.key_exchange = bytearray([0xff] * len(key_share.key_exchange)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - all bits set key share" .format(GroupName.toRepr(group))] = conversation if group == GroupName.ffdhe2048: params = FFDHE2048 elif group == GroupName.ffdhe3072: params = FFDHE3072 elif group == GroupName.ffdhe4096: params = FFDHE4096 elif group == GroupName.ffdhe6144: params = FFDHE6144 else: assert group == GroupName.ffdhe8192 params = FFDHE8192 # p-1 key share conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = KeyShareEntry().create(group, numberToByteArray(params[1]-1)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - p-1 as key share" .format(GroupName.toRepr(group))] = conversation # p key share conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = KeyShareEntry().create(group, numberToByteArray(params[1])) ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - p as key share" .format(GroupName.toRepr(group))] = conversation # empty key share entry conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {} key_share = KeyShareEntry().create(group, bytearray()) ext[ExtensionType.key_share] = ClientKeyShareExtension().create([key_share]) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create([group]) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} - empty key share entry in key_share ext" .format(GroupName.toRepr(group))] = conversation # run the conversation good = 0 bad = 0 xfail = 0 xpass = 0 failed = [] xpassed = [] if not num_limit: num_limit = len(conversations) # make sure that sanity test is run first and last # to verify that server was running and kept running throughout sanity_tests = [('sanity', conversations['sanity'])] if run_only: if num_limit > len(run_only): num_limit = len(run_only) regular_tests = [(k, v) for k, v in conversations.items() if k in run_only] else: regular_tests = [(k, v) for k, v in conversations.items() if (k != 'sanity') and k not in run_exclude] sampled_tests = sample(regular_tests, min(num_limit, len(regular_tests))) ordered_tests = chain(sanity_tests, sampled_tests, sanity_tests) for c_name, c_test in ordered_tests: if run_only and c_name not in run_only or c_name in run_exclude: continue print("{0} ...".format(c_name)) runner = Runner(c_test) res = True exception = None try: runner.run() except Exception as exp: exception = exp print("Error while processing") print(traceback.format_exc()) res = False if c_name in expected_failures: if res: xpass += 1 xpassed.append(c_name) print("XPASS-expected failure but test passed\n") else: if expected_failures[c_name] is not None and \ expected_failures[c_name] not in str(exception): bad += 1 failed.append(c_name) print("Expected error message: {0}\n" .format(expected_failures[c_name])) else: xfail += 1 print("OK-expected failure\n") else: if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Basic FFDHE group tests in TLS 1.3") print("Check if invalid, malformed and incompatible group key_shares are") print("rejected by server") print("Test end") print(20 * '=') print("version: {0}".format(version)) print(20 * '=') print("TOTAL: {0}".format(len(sampled_tests) + 2*len(sanity_tests))) print("SKIP: {0}".format(len(run_exclude.intersection(conversations.keys())))) print("PASS: {0}".format(good)) print("XFAIL: {0}".format(xfail)) print("FAIL: {0}".format(bad)) print("XPASS: {0}".format(xpass)) print(20 * '=') sort = sorted(xpassed ,key=natural_sort_keys) if len(sort): print("XPASSED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) sort = sorted(failed, key=natural_sort_keys) if len(sort): print("FAILED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) if bad > 0: sys.exit(1)
def test_very_large_number(self): self.assertEqual(numberToByteArray((1 << 128) - 1, endian="little"), bytearray(b'\xff' * 16))
def test_numberToByteArray_with_MSB_number(self): self.assertEqual(numberToByteArray(0xff), bytearray(b'\xff'))
def test_big_number(self, number): self.assertEqual(numberToByteArray(number, 4, endian="little"), bytearray(struct.pack("<L", number)))
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() expected_failures = {} last_exp_tmp = None argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X:n:", ["help"]) for opt, arg in opts: if opt == '-h': host = arg elif opt == '-p': port = int(arg) elif opt == '-e': run_exclude.add(arg) elif opt == '-x': expected_failures[arg] = None last_exp_tmp = str(arg) elif opt == '-X': if not last_exp_tmp: raise ValueError("-x has to be specified before -X") expected_failures[last_exp_tmp] = str(arg) elif opt == '-n': num_limit = int(arg) elif opt == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None conversations = {} conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create(key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectEncryptedExtensions()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation test_groups = { GroupName.x25519: X25519_ORDER_SIZE, GroupName.x448: X448_ORDER_SIZE, } # check if server will negotiate x25519/x448 - sanity check for test_group, group_size in test_groups.items(): for compression_format in [ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, ECPointFormat.uncompressed ]: conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} ext[ExtensionType.ec_point_formats] = ECPointFormatsExtension( ).create([compression_format]) groups = [test_group] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectEncryptedExtensions()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity {0} with compression {1}".format( GroupName.toRepr(test_group), ECPointFormat.toRepr(compression_format))] = conversation # check if server will reject an all-zero key share for x25519/x448 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, bytearray(group_size)) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["all zero {0} key share".format( GroupName.toRepr(test_group))] = conversation # check if server will reject a key share or 1 for x25519/x448 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, numberToByteArray(1, group_size, "little")) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} key share of \"1\"".format( GroupName.toRepr(test_group))] = conversation # check if server will reject too small x25519/x448 share # (one with too few bytes in the key share) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, bytearray([55] * (group_size - 1))) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["too small {0} key share".format( GroupName.toRepr(test_group))] = conversation # check if server will reject empty x25519/x448 share # no compression conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [KeyShareEntry().create(test_group, bytearray())] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["empty {0} key share".format( GroupName.toRepr(test_group))] = conversation # check if server will reject too big x25519/x448 share # (one with too many bytes in the key share) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, bytearray([55] * (group_size + 1))) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["too big {0} key share".format( GroupName.toRepr(test_group))] = conversation # run the conversation good = 0 bad = 0 xfail = 0 xpass = 0 failed = [] xpassed = [] if not num_limit: num_limit = len(conversations) # make sure that sanity test is run first and last # to verify that server was running and kept running throughout sanity_tests = [('sanity', conversations['sanity'])] regular_tests = [(k, v) for k, v in conversations.items() if k != 'sanity'] sampled_tests = sample(regular_tests, min(num_limit, len(regular_tests))) ordered_tests = chain(sanity_tests, sampled_tests, sanity_tests) for c_name, c_test in ordered_tests: if run_only and c_name not in run_only or c_name in run_exclude: continue print("{0} ...".format(c_name)) runner = Runner(c_test) res = True exception = None try: runner.run() except Exception as exp: exception = exp print("Error while processing") print(traceback.format_exc()) res = False if c_name in expected_failures: if res: xpass += 1 xpassed.append(c_name) print("XPASS: expected failure but test passed\n") else: if expected_failures[c_name] is not None and \ expected_failures[c_name] not in str(exception): bad += 1 failed.append(c_name) print("Expected error message: {0}\n".format( expected_failures[c_name])) else: xfail += 1 print("OK-expected failure\n") else: if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Basic test to verify that server selects same ECDHE parameters") print("and ciphersuites when x25519 or x448 curve is an option\n") print("version: {0}\n".format(version)) print("Test end") print(20 * '=') print("TOTAL: {0}".format(len(sampled_tests) + 2 * len(sanity_tests))) print("SKIP: {0}".format( len(run_exclude.intersection(conversations.keys())))) print("PASS: {0}".format(good)) print("XFAIL: {0}".format(xfail)) print("FAIL: {0}".format(bad)) print("XPASS: {0}".format(xpass)) print(20 * '=') sort = sorted(xpassed, key=natural_sort_keys) if len(sort): print("XPASSED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) sort = sorted(failed, key=natural_sort_keys) if len(sort): print("FAILED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) if bad > 0: sys.exit(1)