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 hrr_ext_handler_key_share(state, extension): """Process the key_share extension in HRR message.""" cln_hello = state.get_last_message_of_type(ClientHello) cln_ext = cln_hello.getExtension(ExtensionType.supported_groups) group_id = extension.selected_group if group_id not in cln_ext.groups: raise AssertionError("Server selected group we didn't advertise: {0}" .format(GroupName.toStr(group_id)))
def printGoodConnection(connection, seconds): print(" Handshake time: %.3f seconds" % seconds) print(" Version: %s" % connection.getVersionName()) print(" Cipher: %s %s" % (connection.getCipherName(), connection.getCipherImplementation())) print(" Ciphersuite: {0}". \ format(CipherSuite.ietfNames[connection.session.cipherSuite])) if connection.session.srpUsername: print(" Client SRP username: %s" % connection.session.srpUsername) if connection.session.clientCertChain: if connection.session.clientCertChain.is_fido2_cert_chain(): fido2_mode = connection.session.clientCertChain.get_fido2_mode() fido2_string = "(FIDO2: " + FIDO2Mode.toRepr(fido2_mode) + ")" else: fido2_string = "" print(" Client X.509 SHA1 fingerprint: %s %s" % (connection.session.clientCertChain.getFingerprint(), fido2_string)) else: print(" No client certificate provided by peer") if connection.session.serverCertChain: print(" Server X.509 SHA1 fingerprint: %s" % connection.session.serverCertChain.getFingerprint()) if connection.version >= (3, 3) and connection.serverSigAlg is not None: scheme = SignatureScheme.toRepr(connection.serverSigAlg) if scheme is None: scheme = "{1}+{0}".format( HashAlgorithm.toStr(connection.serverSigAlg[0]), SignatureAlgorithm.toStr(connection.serverSigAlg[1])) print(" Key exchange signature: {0}".format(scheme)) if connection.ecdhCurve is not None: print(" Group used for key exchange: {0}".format( \ GroupName.toStr(connection.ecdhCurve))) if connection.dhGroupSize is not None: print(" DH group size: {0} bits".format(connection.dhGroupSize)) if connection.session.serverName: print(" SNI: %s" % connection.session.serverName) if connection.session.tackExt: if connection.session.tackInHelloExt: emptyStr = "\n (via TLS Extension)" else: emptyStr = "\n (via TACK Certificate)" print(" TACK: %s" % emptyStr) print(str(connection.session.tackExt)) if connection.session.appProto: print(" Application Layer Protocol negotiated: {0}".format( connection.session.appProto.decode('utf-8'))) print(" Next-Protocol Negotiated: %s" % connection.next_proto) print(" Encrypt-then-MAC: {0}".format(connection.encryptThenMAC)) print(" Extended Master Secret: {0}".format( connection.extendedMasterSecret))
def printGoodConnection(connection, seconds, hv=None): print(" Handshake time: %.3f seconds" % seconds) print(" Version: %s" % connection.getVersionName()) print(" Cipher: %s %s" % (connection.getCipherName(), connection.getCipherImplementation())) print(" Ciphersuite: {0}".\ format(CipherSuite.ietfNames[connection.session.cipherSuite])) if connection.session.srpUsername: print(" Client SRP username: %s" % connection.session.srpUsername) if connection.session.clientCertChain: print(" Client X.509 SHA1 fingerprint: %s" % connection.session.clientCertChain.getFingerprint()) else: print(" No client certificate provided by peer") if connection.session.serverCertChain: print(" Server X.509 SHA1 fingerprint: %s" % connection.session.serverCertChain.getFingerprint()) if connection.version >= (3, 3) and connection.serverSigAlg is not None: scheme = SignatureScheme.toRepr(connection.serverSigAlg) if scheme is None: scheme = "{1}+{0}".format( HashAlgorithm.toStr(connection.serverSigAlg[0]), SignatureAlgorithm.toStr(connection.serverSigAlg[1])) print(" Key exchange signature: {0}".format(scheme)) if connection.ecdhCurve is not None: print(" Group used for key exchange: {0}".format(\ GroupName.toStr(connection.ecdhCurve))) if connection.dhGroupSize is not None: print(" DH group size: {0} bits".format(connection.dhGroupSize)) if connection.session.serverName: print(" SNI: %s" % connection.session.serverName) if connection.session.tackExt: if connection.session.tackInHelloExt: emptyStr = "\n (via TLS Extension)" else: emptyStr = "\n (via TACK Certificate)" print(" TACK: %s" % emptyStr) print(str(connection.session.tackExt)) if connection.session.appProto: print(" Application Layer Protocol negotiated: {0}".format( connection.session.appProto.decode('utf-8'))) print(" Next-Protocol Negotiated: %s" % connection.next_proto) print(" Encrypt-then-MAC: {0}".format(connection.encryptThenMAC)) print(" Extended Master Secret: {0}".format(connection.extendedMasterSecret)) # PGP # from hashlib import sha256 sha_ = sha256(connection.session.masterSecret) print("SHA256 of this session's master secret:\n",sha_.hexdigest()) if hv is not None: hv.hvSignal.emit(bytearray(sha_.digest()))
def printGoodConnection(connection, seconds): print(" Handshake time: %.3f seconds" % seconds) print(" Version: %s" % connection.getVersionName()) print(" Cipher: %s %s" % (connection.getCipherName(), connection.getCipherImplementation())) print(" Ciphersuite: {0}".\ format(CipherSuite.ietfNames[connection.session.cipherSuite])) if connection.session.srpUsername: print(" Client SRP username: %s" % connection.session.srpUsername) if connection.session.clientCertChain: print(" Client X.509 SHA1 fingerprint: %s" % connection.session.clientCertChain.getFingerprint()) else: print(" No client certificate provided by peer") if connection.session.serverCertChain: print(" Server X.509 SHA1 fingerprint: %s" % connection.session.serverCertChain.getFingerprint()) if connection.version >= (3, 3) and connection.serverSigAlg is not None: scheme = SignatureScheme.toRepr(connection.serverSigAlg) if scheme is None: scheme = "{1}+{0}".format( HashAlgorithm.toStr(connection.serverSigAlg[0]), SignatureAlgorithm.toStr(connection.serverSigAlg[1])) print(" Key exchange signature: {0}".format(scheme)) if connection.ecdhCurve is not None: print(" Group used for key exchange: {0}".format(\ GroupName.toStr(connection.ecdhCurve))) if connection.dhGroupSize is not None: print(" DH group size: {0} bits".format(connection.dhGroupSize)) if connection.session.serverName: print(" SNI: %s" % connection.session.serverName) if connection.session.tackExt: if connection.session.tackInHelloExt: emptyStr = "\n (via TLS Extension)" else: emptyStr = "\n (via TACK Certificate)" print(" TACK: %s" % emptyStr) print(str(connection.session.tackExt)) if connection.session.appProto: print(" Application Layer Protocol negotiated: {0}".format( connection.session.appProto.decode('utf-8'))) print(" Next-Protocol Negotiated: %s" % connection.next_proto) print(" Encrypt-then-MAC: {0}".format(connection.encryptThenMAC)) print(" Extended Master Secret: {0}".format( connection.extendedMasterSecret))
def srv_ext_handler_key_share(state, extension): """Process the key_share extension from server.""" cln_hello = state.get_last_message_of_type(ClientHello) cln_ext = cln_hello.getExtension(ExtensionType.key_share) group_id = extension.server_share.group cl_ext = next((i for i in cln_ext.client_shares if i.group == group_id), None) if cl_ext is None: raise AssertionError("Server selected group we didn't advertise: {0}" .format(GroupName.toStr(group_id))) kex = kex_for_group(group_id, state.version) z = kex.calc_shared_key(cl_ext.private, extension.server_share.key_exchange) state.key['DH shared secret'] = z
def printGoodConnection(connection, seconds): print(" Handshake time: %.3f seconds" % seconds) print(" Version: %s" % connection.getVersionName()) print(" Cipher: %s %s" % (connection.getCipherName(), connection.getCipherImplementation())) print(" Ciphersuite: {0}".\ format(CipherSuite.ietfNames[connection.session.cipherSuite])) if connection.session.srpUsername: print(" Client SRP username: %s" % connection.session.srpUsername) if connection.session.clientCertChain: print(" Client X.509 SHA1 fingerprint: %s" % connection.session.clientCertChain.getFingerprint()) else: print(" No client certificate provided by peer") if connection.session.serverCertChain: print(" Server X.509 SHA1 fingerprint: %s" % connection.session.serverCertChain.getFingerprint()) if connection.version >= (3, 3) and connection.serverSigAlg is not None: print(" Key exchange signature: {1}+{0}".format(\ HashAlgorithm.toStr(connection.serverSigAlg[0]), SignatureAlgorithm.toStr(connection.serverSigAlg[1]))) if connection.ecdhCurve is not None: print(" Group used for key exchange: {0}".format(\ GroupName.toStr(connection.ecdhCurve))) if connection.dhGroupSize is not None: print(" DH group size: {0} bits".format(connection.dhGroupSize)) if connection.session.serverName: print(" SNI: %s" % connection.session.serverName) if connection.session.tackExt: if connection.session.tackInHelloExt: emptyStr = "\n (via TLS Extension)" else: emptyStr = "\n (via TACK Certificate)" print(" TACK: %s" % emptyStr) print(str(connection.session.tackExt)) print(" Next-Protocol Negotiated: %s" % connection.next_proto) print(" Encrypt-then-MAC: {0}".format(connection.encryptThenMAC))
def test_ECDHE_key_exchange_with_invalid_CKE(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_key_ex.ecdh_Yc[-1] ^= 0x01 with self.assertRaises(TLSIllegalParameterException): self.keyExchange.processClientKeyExchange(cln_key_ex)
def main(): """Test if server supports the RFC 7919 key exchange""" host = "localhost" port = 4433 run_exclude = set() argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:", ["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 == '--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_DHE_RSA_WITH_AES_128_CBC_SHA] node = node.add_child( ClientHelloGenerator( ciphers, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child( ExpectServerHello(extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["sanity"] = conversation conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] node = node.add_child( ClientHelloGenerator( ciphers, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child( ExpectServerHello(cipher=CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["Check if DHE preferred"] = conversation for group in GroupName.allFF: conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([group]) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectServerHello( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange(valid_groups=[group])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["{0} negotiation".format(GroupName.toStr(group))] = \ conversation conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511, group]) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectServerHello( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange(valid_groups=[group])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["unassigned tolerance, {0} negotiation".format(GroupName.toStr(group))] = \ conversation conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([GroupName.secp256r1, group]) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectServerHello( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange(valid_groups=[group])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["tolerate ECC curve in groups without ECC cipher, " "negotiate {0} ".format(GroupName.toStr(group))] = \ conversation for group2 in GroupName.allFF: if group == group2: continue conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511, group, group2]) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectServerHello( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child( ExpectServerKeyExchange(valid_groups=[group, group2])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["{0} or {1} negotiation".format( GroupName.toStr(group), GroupName.toStr(group2))] = conversation conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511]) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectServerHello(cipher=CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["fallback to non-ffdhe"] = conversation conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([GroupName.secp256r1, 511]) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectServerHello(cipher=CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations[ "fallback to non-ffdhe with secp256r1 advertised"] = conversation # first paragraph of section 4 in RFC 7919 conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_NULL_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511]) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.insufficient_security)) node.add_child(ExpectClose()) conversations["no overlap between groups"] = conversation good = 0 bad = 0 failed = [] # make sure that sanity test is run first and last # to verify that server was running and kept running throught sanity_test = ('sanity', conversations['sanity']) ordered_tests = chain([sanity_test], filter(lambda x: x[0] != 'sanity', conversations.items()), [sanity_test]) 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 try: runner.run() except: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad)) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0: sys.exit(1)
def main(): """Test if server supports the RFC 7919 key exchange""" host = "localhost" port = 4433 num_limit = None fatal_alert = "insufficient_security" run_exclude = set() expected_failures = {} last_exp_tmp = None sig_algs = None # `sigalgs` w/o underscore is used for client certificates timeout = 5.0 argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:S:e:x:X:t:n:", ["help", "alert="]) for opt, arg in opts: if opt == '-h': host = arg elif opt == '-p': port = int(arg) elif opt == '-S': sig_algs = sig_algs_to_ids(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 == '--alert': fatal_alert = arg elif opt == '--help': help_msg() sys.exit(0) elif opt == '-t': timeout = float(arg) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None conversations = {} conversation = Connect(host, port, timeout=timeout) node = conversation ext = {ExtensionType.renegotiation_info: None} ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] if sig_algs: 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(extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["sanity"] = conversation conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] ext = {ExtensionType.renegotiation_info: None} if sig_algs: 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(cipher=CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["Check if DHE preferred"] = conversation for group in GroupName.allFF: conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([group]) if sig_algs: 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( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange(valid_groups=[group])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["{0} negotiation".format(GroupName.toStr(group))] = \ conversation conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511, group]) if sig_algs: 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( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange(valid_groups=[group])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["unassigned tolerance, {0} negotiation".format(GroupName.toStr(group))] = \ conversation conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([GroupName.secp256r1, group]) if sig_algs: 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( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange(valid_groups=[group])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["tolerate ECC curve in groups without ECC cipher, " "negotiate {0} ".format(GroupName.toStr(group))] = \ conversation for group2 in GroupName.allFF: if group == group2: continue conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511, group, group2]) if sig_algs: 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( extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child( ExpectServerKeyExchange(valid_groups=[group, group2])) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["{0} or {1} negotiation".format( GroupName.toStr(group), GroupName.toStr(group2))] = conversation conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511]) if sig_algs: 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(cipher=CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations["fallback to non-ffdhe"] = conversation conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([GroupName.secp256r1, 511]) if sig_algs: 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(cipher=CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node.add_child(ExpectClose()) conversations[ "fallback to non-ffdhe with secp256r1 advertised"] = conversation # first paragraph of section 4 in RFC 7919 conversation = Connect(host, port, timeout=timeout) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_NULL_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA ] ext = {ExtensionType.renegotiation_info: None} ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create([511]) if sig_algs: 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, getattr(AlertDescription, fatal_alert))) node.add_child(ExpectClose()) conversations["no overlap between groups"] = conversation good = 0 bad = 0 xfail = 0 xpass = 0 failed = [] xpassed = [] num_limit = num_limit or 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("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 or xpass: sys.exit(1)
def main(): """Verify correct ECDHE shared secret handling.""" host = "localhost" port = 4433 num_limit = None run_exclude = set() min_zeros = 1 record_split = True argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:z", ["help", "min-zeros="]) 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 == '-n': num_limit = int(arg) elif opt == '-z': record_split = False elif opt == '--help': help_msg() sys.exit(0) elif opt == '--min-zeros': min_zeros = int(arg) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None collected_premaster_secrets = [] variables_check = \ {'premaster_secret': collected_premaster_secrets} groups = [ GroupName.x25519, GroupName.x448, GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1 ] conversations = {} conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] groups_ext = SupportedGroupsExtension().create(groups) points_ext = ECPointFormatsExtension().create([ECPointFormat.uncompressed]) exts = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child(ClientHelloGenerator(ciphers, extensions=exts)) exts = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=exts)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation for prot in [(3, 0), (3, 1), (3, 2), (3, 3)]: for ssl2 in [True, False]: for group in groups: # with SSLv2 compatible or with SSLv3 we can't advertise # curves so do just one check if (ssl2 or prot == (3, 0)) and group != groups[0]: continue conversation = Connect(host, port, version=(0, 2) if ssl2 else (3, 0)) node = conversation ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] if ssl2 or prot == (3, 0): exts = None else: groups_ext = SupportedGroupsExtension().create([group]) exts = { ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child( ClientHelloGenerator(ciphers, version=prot, extensions=exts, ssl2=ssl2)) if prot > (3, 0): if ssl2: ext = {ExtensionType.renegotiation_info: None} else: ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } else: ext = None node = node.add_child( ExpectServerHello(extensions=ext, version=prot)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) if prot < (3, 2) and record_split: # 1/n-1 record splitting node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["Protocol {0}{1}{2}".format( prot, "" if ssl2 or prot < (3, 1) else " with {0} group".format(GroupName.toStr(group)), " in SSLv2 compatible ClientHello" if ssl2 else "")] = \ conversation # run the conversation good = 0 bad = 0 failed = [] 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 i = 0 break_loop = False while True: # don't hog the memory unnecessairly collected_premaster_secrets[:] = [] print("\"{1}\" repeat {0}...".format(i, c_name)) i += 1 if c_name == 'sanity': break_loop = True runner = Runner(c_test) res = True try: runner.run() except Exception: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 if collected_premaster_secrets[-1][:min_zeros] == \ bytearray(min_zeros): print("Got premaster secret with {0} most significant " "bytes equal to zero.".format(min_zeros)) break_loop = True print("OK\n") else: bad += 1 failed.append(c_name) break if break_loop: break print('') print("Check if the connections work when the calculated ECDH shared") print("secret must be padded on the left with zeros") print("version: {0}\n".format(version)) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad)) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0: sys.exit(1)
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() repeats = 32 argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:", ["help", "repeat="]) 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 == '-n': num_limit = int(arg) elif opt == '--help': help_msg() sys.exit(0) elif opt == '--repeat': repeats = int(arg) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None collected_randoms = [] collected_key_shares = [] variables_check = \ {'ServerHello.random': collected_randoms, 'ServerHello.extensions.key_share.key_exchange': collected_key_shares} 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 = [] 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 ] 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(CopyVariables(variables_check)) 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 [ GroupName.secp384r1, GroupName.secp521r1, GroupName.x25519, GroupName.x448, GroupName.ffdhe2048, GroupName.ffdhe3072 ]: conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [group] key_shares = [] 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 ] 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(CopyVariables(variables_check)) 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["TLS 1.3 with {0}".format(GroupName.toStr(group))] \ = conversation # run the conversation good = 0 bad = 0 failed = [] 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 throught sanity_test = ('sanity', conversations['sanity']) ordered_tests = chain([sanity_test], islice( filter(lambda x: x[0] != 'sanity', conversations.items()), num_limit), [sanity_test]) 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 for i in range(repeats): print("\"{1}\" repeat {0}...".format(i, c_name)) runner = Runner(c_test) res = True try: runner.run() except Exception: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) failed_tests = uniqueness_check(variables_check, good + bad) if failed_tests: print("\n".join(failed_tests)) else: print("\n".join("{0} values: OK".format(i) for i in variables_check)) print('') print("Check if the ServerHello random values are unique") print("version: {0}\n".format(version)) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad + len(failed_tests))) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0 or failed_tests: sys.exit(1)
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() groups = GroupName.allFF argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e: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 == '-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 = {} 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_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) 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 specific ones for key_share_group in groups: 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(key_share_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([key_share_group]) sig_algs = [SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256] ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) 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["{0}".format(GroupName.toStr(key_share_group))] = conversation # run the conversation good = 0 bad = 0 failed = [] 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 throught sanity_test = ('sanity', conversations['sanity']) ordered_tests = chain([sanity_test], islice(filter(lambda x: x[0] != 'sanity', conversations.items()), num_limit), [sanity_test]) 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 try: runner.run() except Exception: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Basic FFDHE test with TLS 1.3 server") print("Check if FFDHE groups are supported on the TLS 1.3 server.\n") print("version: {0}\n".format(version)) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad)) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0: sys.exit(1)
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() expected_failures = {} last_exp_tmp = None groups = GroupName.allFF 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 = {} 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_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) 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 specific ones for key_share_group in groups: 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(key_share_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([key_share_group]) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) 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["{0}".format( GroupName.toStr(key_share_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 test with TLS 1.3 server") print("Check if FFDHE groups are supported on the TLS 1.3 server.\n") 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 main(): host = "localhost" port = 4433 num_limit = 1 run_exclude = set() expected_failures = {} last_exp_tmp = None min_zeros = 1 argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X:n:", ["help", "min-zeros="]) 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) elif opt == '--min-zeros': min_zeros = int(arg) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None collected_shared_secrets = [] collected_key_shares = [] variables_check = \ {'DH shared secret': collected_shared_secrets, 'ServerHello.extensions.key_share.key_exchange': collected_key_shares} conversations = {} conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [GroupName.secp256r1] 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 ] 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(CopyVariables(variables_check)) 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 [ GroupName.secp384r1, GroupName.secp521r1, GroupName.x25519, GroupName.x448, GroupName.ffdhe2048, GroupName.ffdhe3072 ]: conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [group] 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 ] 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(CopyVariables(variables_check)) 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["TLS 1.3 with {0}".format(GroupName.toStr(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 i = 0 break_shared = False break_key_share = False while True: # don't hog the memory unnecessairly collected_shared_secrets[:] = [] print("\"{1}\" repeat {0}...".format(i, c_name)) i += 1 if c_name == 'sanity': break_shared = True break_key_share = True 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") break else: if res: good += 1 if collected_shared_secrets[-1][:min_zeros] == \ bytearray(min_zeros): print("Got shared secret with {0} most significant " "bytes equal to zero.".format(min_zeros)) break_shared = True # ECDSA key shares have a constant first byte indicating # the point encoding if "secp" in c_name: if collected_key_shares[-1][:min_zeros+1] == \ bytearray(b'\x04') + bytearray(min_zeros): print( "Got key share with {0} most significant bytes equal" " to zero.".format(min_zeros)) break_key_share = True else: if collected_key_shares[-1][:min_zeros] == \ bytearray(min_zeros): print( "Got key share with {0} most significant bytes equal" " to zero.".format(min_zeros)) break_key_share = True print("OK\n") else: bad += 1 failed.append(c_name) break if break_shared and break_key_share: break print('') print("Check if the connections work when the calculated DH shared secret") print("must be padded on the left with zeros or when the server needs") print("to pad its key share") 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 or xpass: sys.exit(1)
def main(): """Test if server provides unique ECDHE_RSA key shares.""" host = "localhost" port = 4433 num_limit = None run_exclude = set() repeats = 32 argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:", ["help", "repeat="]) 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 == '-n': num_limit = int(arg) elif opt == '--help': help_msg() sys.exit(0) elif opt == '--repeat': repeats = int(arg) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None collected_randoms = [] collected_key_shares = [] collected_session_ids = [] variables_check = \ {'ServerHello.random': collected_randoms, 'ServerKeyExchange.key_share': collected_key_shares, 'ServerHello.session_id': collected_session_ids} groups = [ GroupName.x25519, GroupName.x448, GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1 ] conversations = {} conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] groups_ext = SupportedGroupsExtension().create(groups) points_ext = ECPointFormatsExtension().create([ECPointFormat.uncompressed]) exts = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child(ClientHelloGenerator(ciphers, extensions=exts)) exts = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=exts)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation for prot in [(3, 0), (3, 1), (3, 2), (3, 3)]: for ssl2 in [True, False]: for group in groups: # with SSLv2 compatible or with SSLv3 we can't advertise # curves so do just one check if (ssl2 or prot == (3, 0)) and group != groups[0]: continue conversation = Connect(host, port, version=(0, 2) if ssl2 else (3, 0)) node = conversation ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] if ssl2 or prot == (3, 0): exts = None else: groups_ext = SupportedGroupsExtension().create([group]) exts = { ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child( ClientHelloGenerator(ciphers, version=prot, extensions=exts, ssl2=ssl2)) if prot > (3, 0): if ssl2: ext = {ExtensionType.renegotiation_info: None} else: ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } else: ext = None node = node.add_child( ExpectServerHello(extensions=ext, version=prot)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) if prot < (3, 2): # 1/n-1 record splitting node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["Protocol {0}{1}{2}".format( prot, "" if ssl2 or prot < (3, 1) else " with {0} group".format(GroupName.toStr(group)), " in SSLv2 compatible ClientHello" if ssl2 else "")] = \ conversation # run the conversation good = 0 bad = 0 failed = [] 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 for i in range(repeats): print("\"{1}\" repeat {0}...".format(i, c_name)) runner = Runner(c_test) res = True try: runner.run() except Exception: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) failed_tests = uniqueness_check(variables_check, good + bad) if failed_tests: print("\n".join(failed_tests)) else: print("\n".join("{0} values: OK".format(i) for i in variables_check)) print('') print("Check if the server provided random values are unique") print("Checks random and session_id from Server Hello and ECDHE key share") print("Note: not supporting ECDHE in SSLv3 or with SSLv2 Client Hello is") print("valid behaviour, as the client can't advertise groups it supports") print("there.") print("version: {0}\n".format(version)) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad + len(failed_tests))) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0 or failed_tests: sys.exit(1)