def test_s2n_client_key_update(managed_process, cipher): host = "localhost" port = next(available_ports) update_requested = b"K\n" server_data = data_bytes(10) client_data = data_bytes(10) # Last statement printed out by Openssl after handshake starting_marker = "Secure Renegotiation IS supported" key_update_marker = "TLSv1.3 write server key update" read_key_update_marker = b"TLSv1.3 read client key update" send_marker_list = [starting_marker, key_update_marker] client_options = ProviderOptions( mode=Provider.ClientMode, host=host, port=port, cipher=cipher, data_to_send=[client_data], insecure=True, protocol=Protocols.TLS13, ) server_options = copy.copy(client_options) server_options.mode = Provider.ServerMode server_options.key = "../pems/ecdsa_p384_pkcs1_key.pem" server_options.cert = "../pems/ecdsa_p384_pkcs1_cert.pem" server_options.data_to_send = [update_requested, server_data] server = managed_process( OpenSSL, server_options, send_marker=send_marker_list, close_marker=str(client_data), timeout=5, ) client = managed_process( S2N, client_options, send_marker=[str(server_data)], close_marker=str(server_data), timeout=5, ) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert server_data in results.stdout for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert read_key_update_marker in results.stderr assert client_data in results.stdout
def test_s2n_server_key_update(managed_process, cipher): host = "localhost" port = next(available_ports) update_requested = b"K" server_data = data_bytes(10) client_data = data_bytes(10) starting_marker = "Verify return code" key_update_marker = "KEYUPDATE" send_marker_list = [starting_marker, key_update_marker] client_options = ProviderOptions( mode=Provider.ClientMode, host=host, port=port, cipher=cipher, data_to_send=[update_requested, client_data], insecure=True, protocol=Protocols.TLS13, ) server_options = copy.copy(client_options) server_options.mode = Provider.ServerMode server_options.key = "../pems/ecdsa_p384_pkcs1_key.pem" server_options.cert = "../pems/ecdsa_p384_pkcs1_cert.pem" server_options.data_to_send = [server_data] server = managed_process(S2N, server_options, send_marker=[str(client_data)], timeout=5) client = managed_process( OpenSSL, client_options, send_marker=send_marker_list, close_marker=str(server_data), timeout=5, ) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert key_update_marker in str(results.stderr) assert server_data in results.stdout for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert client_data in results.stdout
def test_s2n_server_low_latency(managed_process, multi_cipher, provider, protocol, certificate): port = next(available_ports) random_bytes = data_bytes(65519) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=multi_cipher, data_to_send=random_bytes, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.extra_flags = ['--prefer-low-latency'] server_options.key = certificate.key server_options.cert = certificate.cert server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 expected_version = get_expected_s2n_version(protocol, provider) for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Actual protocol version: {}".format( expected_version).encode('utf-8')) in results.stdout assert random_bytes in results.stdout
def test_s2n_server_low_latency(managed_process, multi_cipher, provider, protocol, certificate): if provider is OpenSSL and 'openssl-1.0.2' in provider.get_version(): pytest.skip('{} does not allow setting max fragmentation for packets'.format(provider)) port = next(available_ports) random_bytes = data_bytes(65519) client_options = ProviderOptions( mode=Provider.ClientMode, port=port, cipher=multi_cipher, data_to_send=random_bytes, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.extra_flags = ['--prefer-low-latency'] server_options.key = certificate.key server_options.cert = certificate.cert server_options.cipher = None server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) for results in client.get_results(): results.assert_success() expected_version = get_expected_s2n_version(protocol, provider) for results in server.get_results(): results.assert_success() assert to_bytes("Actual protocol version: {}".format(expected_version)) in results.stdout assert random_bytes in results.stdout
def get_ticket_from_s2n_server(options, managed_process, provider, certificate): port = next(available_ports) """ Generally clients start checking for stdin EoF to exit as soon as they finish the handshake. To make sure the client reliably receives the post-handshake NST, do NOT indicate stdin EoF until after some data has been received from the server. """ close_marker_bytes = data_bytes(10) client_options = copy.copy(options) client_options.mode = Provider.ClientMode client_options.port = port server_options = copy.copy(options) server_options.mode = Provider.ServerMode server_options.port = port server_options.key = certificate.key server_options.cert = certificate.cert server_options.data_to_send = close_marker_bytes assert not os.path.exists(options.ticket_file) s2n_server = managed_process( S2N, server_options, send_marker=S2N.get_send_marker()) client = managed_process(provider, client_options, close_marker=str(close_marker_bytes)) for results in s2n_server.get_results(): results.assert_success() for results in client.get_results(): results.assert_success() assert os.path.exists(options.ticket_file)
def test_s2n_server_ocsp_response(managed_process, cipher, provider, other_provider, curve, protocol, certificate): port = next(available_ports) random_bytes = data_bytes(128) client_options = ProviderOptions(mode=Provider.ClientMode, port=port, cipher=cipher, curve=curve, protocol=protocol, insecure=True, data_to_send=random_bytes, enable_client_ocsp=True) server_options = ProviderOptions( mode=Provider.ServerMode, port=port, cipher=cipher, curve=curve, protocol=protocol, insecure=True, key=certificate.key, cert=certificate.cert, ocsp_response={ "RSA": TEST_OCSP_DIRECTORY + "ocsp_response.der", "EC": TEST_OCSP_DIRECTORY + "ocsp_ecdsa_response.der" }.get(certificate.algorithm), ) kill_marker = None if provider == GnuTLS: # The GnuTLS client hangs for a while after sending. Speed up the tests by killing # it immediately after sending the message. kill_marker = b"Sent: " server = managed_process(S2N, server_options, timeout=2000) client = managed_process(provider, client_options, timeout=2000, kill_marker=kill_marker) for client_results in client.get_results(): client_results.assert_success() assert any([{ GnuTLS: b"OCSP Response Information:\n\tResponse Status: Successful", OpenSSL: b"OCSP Response Status: successful" }.get(provider) in stream for stream in client_results.output_streams()]) for server_results in server.get_results(): server_results.assert_success() # Avoid debugging information that sometimes gets inserted after the first character. assert any([ random_bytes[1:] in stream for stream in server_results.output_streams() ])
def test_s2n_client_happy_path(managed_process, cipher, provider, curve, protocol, certificate): port = next(available_ports) # We can only send 4096 - 1 (\n at the end) bytes here because of the # way some servers chunk output (when writing to stdout). If we send # 8192 bytes, then openssl will print some debugging information in # the middle of our chunk. We still want that debugging data in case # of a failure, so we just send less data, rather than lose debug # information. random_bytes = data_bytes(4095) client_options = ProviderOptions( mode=Provider.ClientMode, port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, insecure=True, protocol=protocol, ) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert kill_marker = None if provider == GnuTLS: kill_marker = random_bytes # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(provider, server_options, timeout=5, kill_marker=kill_marker) client = managed_process(S2N, client_options, timeout=5) expected_version = get_expected_s2n_version(protocol, provider) # The client is always S2N in this test, so we can examine # the stdout reliably. for client_results in client.get_results(): client_results.assert_success() assert to_bytes("Actual protocol version: {}".format( expected_version)) in client_results.stdout # The server will be one of all supported providers. We # just want to make sure there was no exception and that # the client exited cleanly. for server_results in server.get_results(): server_results.assert_success() # Avoid debugging information that sometimes gets inserted after the first character. assert any([ random_bytes[1:] in stream for stream in server_results.output_streams() ])
def test_s2n_client_multiple_psks(managed_process, cipher, curve, protocol, provider, other_provider, psk_identity, psk_secret): port = next(available_ports) random_bytes = data_bytes(10) psk_hash_alg = get_psk_hash_alg_from_cipher(cipher) skip_invalid_psk_tests(provider, psk_hash_alg) client_psk_params = setup_s2n_psk_params(psk_identity, psk_secret, psk_hash_alg) client_psk_params.extend( setup_s2n_psk_params(PSK_IDENTITY_NO_MATCH, PSK_SECRET_NO_MATCH, psk_hash_alg)) client_options = setup_provider_options(S2N.ClientMode, port, cipher, curve, None, random_bytes, client_psk_params) server_psk_params = [] if provider == OpenSSL: """ OpenSSL Provider does not support multiple PSKs in the same connection, the last psk params is the final psk used in the connection. """ server_psk_params.extend( setup_openssl_psk_params(PSK_IDENTITY_NO_MATCH_2, PSK_SECRET_NO_MATCH_2)) server_psk_params.extend( setup_openssl_psk_params(psk_identity, psk_secret)) server_psk_params += ['-nocert'] else: server_psk_params.extend( setup_s2n_psk_params(PSK_IDENTITY_NO_MATCH_2, PSK_SECRET_NO_MATCH_2, psk_hash_alg)) server_psk_params.extend( setup_s2n_psk_params(psk_identity, psk_secret, psk_hash_alg)) server_options = setup_provider_options(provider.ServerMode, port, cipher, curve, None, None, server_psk_params) server = managed_process(provider, server_options, timeout=5, close_marker=str(random_bytes)) client = managed_process(S2N, client_options, timeout=5) for results in client.get_results(): results.assert_success() validate_negotiated_psk_s2n(Outcome.psk_connection, psk_identity, results) for results in server.get_results(): results.assert_success() if provider == S2N: validate_negotiated_psk_s2n(Outcome.psk_connection, psk_identity, results) else: validate_negotiated_psk_openssl(Outcome.psk_connection, results) assert random_bytes in results.stdout
def test_s2n_client_signature_algorithms(managed_process, cipher, provider, protocol, certificate, signature, client_auth): port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, data_to_send=random_bytes, insecure=True, use_client_auth=client_auth, key=certificate.key, cert=certificate.cert, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.trust_store = certificate.cert server_options.extra_flags = ['-sigalgs', signature.name] if client_auth is True: client_options.trust_store = Certificates.RSA_2048_SHA256_WILDCARD.cert server_options.key = Certificates.RSA_2048_SHA256_WILDCARD.key server_options.cert = Certificates.RSA_2048_SHA256_WILDCARD.cert if signature.sig_type == 'RSA-PSS': client_options.trust_store = Certificates.RSA_PSS_2048_SHA256.cert server_options.key = Certificates.RSA_PSS_2048_SHA256.key server_options.cert = Certificates.RSA_PSS_2048_SHA256.cert elif signature.sig_type == 'ECDSA': client_options.trust_store = Certificates.ECDSA_256.cert server_options.key = Certificates.ECDSA_256.key server_options.cert = Certificates.ECDSA_256.cert server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes('Shared Signature Algorithms: {}+{}'.format( signature.sig_type, signature.sig_digest).encode('utf-8')) in results.stdout assert random_bytes in results.stdout expected_version = get_expected_s2n_version(protocol, provider) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Actual protocol version: {}".format( expected_version).encode('utf-8')) in results.stdout
def test_s2nd_tls13_negotiates_tls12(managed_process, cipher, curve, protocol, provider, certificate): port = next(available_ports) random_bytes = data_bytes(24) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.protocol = Protocols.TLS13 # Allow the server to use all ciphers, don't limit to TLS13 even though we are # forcing the protocol to be TLS13 server_options.extra_flags = ['-c', 'test_all'] server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) server_version = get_expected_s2n_version(Protocols.TLS13, provider) actual_version = get_expected_s2n_version(protocol, provider) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 if provider is S2N: # The client will get the server version from the SERVER HELLO, which will be the negotiated version assert bytes("Server protocol version: {}".format( actual_version).encode('utf-8')) in results.stdout assert bytes("Actual protocol version: {}".format( actual_version).encode('utf-8')) in results.stdout elif provider is OpenSSL: # This check cares about other providers because we want to know that they did negotiate the version # that our S2N server intended to negotiate. openssl_version = get_expected_openssl_version(protocol) assert bytes("Protocol : {}".format(openssl_version).encode( 'utf-8')) in results.stdout for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Server protocol version: {}".format( server_version).encode('utf-8')) in results.stdout assert bytes("Actual protocol version: {}".format( actual_version).encode('utf-8')) in results.stdout assert random_bytes in results.stdout
def test_s2nc_tls13_negotiates_tls12(managed_process, cipher, curve, certificate, protocol, provider, other_provider): port = next(available_ports) random_bytes = data_bytes(24) client_options = ProviderOptions(mode=Provider.ClientMode, port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, insecure=True, protocol=Protocols.TLS13) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.protocol = protocol kill_marker = None if provider == GnuTLS: kill_marker = random_bytes server = managed_process(provider, server_options, timeout=5, kill_marker=kill_marker) client = managed_process(S2N, client_options, timeout=5) client_version = get_expected_s2n_version(Protocols.TLS13, provider) actual_version = get_expected_s2n_version(protocol, provider) for results in client.get_results(): results.assert_success() assert to_bytes("Client protocol version: {}".format( client_version)) in results.stdout assert to_bytes("Actual protocol version: {}".format( actual_version)) in results.stdout for results in server.get_results(): results.assert_success() if provider is S2N: # The server is only TLS12, so it reads the version from the CLIENT_HELLO, which is never above TLS12 # This check only cares about S2N. Trying to maintain expected output of other providers doesn't # add benefit to whether the S2N client was able to negotiate a lower TLS version. assert to_bytes("Client protocol version: {}".format( actual_version)) in results.stdout assert to_bytes("Actual protocol version: {}".format( actual_version)) in results.stdout assert any([ random_bytes[1:] in stream for stream in results.output_streams() ])
def test_hrr_with_s2n_as_server(managed_process, cipher, provider, curve, protocol, certificate): port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions( mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, data_to_send=random_bytes, insecure=True, curve=curve, extra_flags=['-msg', '-curves', 'X448:' + str(curve)], protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.extra_flags = None # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) # The client should connect and return without error for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert random_bytes in results.stdout assert bytes("Curve: {}".format( CURVE_NAMES[curve.name]).encode('utf-8')) in results.stdout assert random_bytes in results.stdout client_hello_count = 0 server_hello_count = 0 finished_count = 0 # HRR random data Refer: https://tools.ietf.org/html/rfc8446#section-4.1.3 marker = b"cf 21 ad 74 e5 9a 61 11 be 1d" for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert marker in results.stdout client_hello_count = results.stdout.count(b'ClientHello') server_hello_count = results.stdout.count(b'ServerHello') finished_count = results.stdout.count(b'Finished') assert client_hello_count == 2 assert server_hello_count == 2 assert finished_count == 2
def test_s2nd_tls13_negotiates_tls12(managed_process, cipher, curve, certificate, protocol, provider, other_provider): port = next(available_ports) random_bytes = data_bytes(24) client_options = ProviderOptions(mode=Provider.ClientMode, port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert # When the protocol is set to TLS13, the s2n server provider will default to using # all ciphers, not just the TLS13 ciphers. This is the desired behavior for this test. server_options.protocol = Protocols.TLS13 server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) server_version = get_expected_s2n_version(Protocols.TLS13, provider) actual_version = get_expected_s2n_version(protocol, provider) for results in client.get_results(): results.assert_success() if provider is S2N: # The client will get the server version from the SERVER HELLO, which will be the negotiated version assert to_bytes("Server protocol version: {}".format( actual_version)) in results.stdout assert to_bytes("Actual protocol version: {}".format( actual_version)) in results.stdout elif provider is OpenSSL: # This check cares about other providers because we want to know that they did negotiate the version # that our S2N server intended to negotiate. openssl_version = get_expected_openssl_version(protocol) assert to_bytes( "Protocol : {}".format(openssl_version)) in results.stdout elif provider is GnuTLS: gnutls_version = get_expected_gnutls_version(protocol) assert to_bytes(f"Version: {gnutls_version}") in results.stdout for results in server.get_results(): results.assert_success() assert (to_bytes("Server protocol version: {}".format(server_version)) in results.stdout) assert (to_bytes("Actual protocol version: {}".format(actual_version)) in results.stdout) assert random_bytes[1:] in results.stdout
def test_client_auth_with_s2n_client_with_cert(managed_process, cipher, curve, protocol, provider, certificate): port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions( mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, use_client_auth=True, client_key_file=certificate.key, client_certificate_file=certificate.cert, client_trust_store=Certificates.RSA_2048_SHA256_WILDCARD.cert, insecure=False, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = Certificates.RSA_2048_SHA256_WILDCARD.key server_options.cert = Certificates.RSA_2048_SHA256_WILDCARD.cert # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) # The client should connect and return without error for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 # Openssl should indicate the procotol version in a successful connection. for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert random_bytes in results.stdout if protocol is Protocols.TLS13: message = bytes( "SSL_accept:SSLv3/TLS read client certificate\nSSL_accept:SSLv3/TLS read certificate verify\nSSL_accept:SSLv3/TLS read finished" .encode('utf-8')) else: message = bytes( 'SSL_accept:SSLv3/TLS read client certificate\nSSL_accept:SSLv3/TLS read client key exchange\nSSL_accept:SSLv3/TLS read certificate verify\nSSL_accept:SSLv3/TLS read change cipher spec\nSSL_accept:SSLv3/TLS read finished' .encode('utf-8')) assert message in results.stderr
def test_s2n_client_ocsp_response(managed_process, cipher, provider, other_provider, curve, protocol, certificate): if "boringssl" in get_flag(S2N_PROVIDER_VERSION): pytest.skip("s2n-tls client with boringssl does not support ocsp") port = next(available_ports) random_bytes = data_bytes(128) client_options = ProviderOptions(mode=Provider.ClientMode, port=port, cipher=cipher, curve=curve, protocol=protocol, insecure=True, data_to_send=random_bytes, enable_client_ocsp=True) server_options = ProviderOptions( mode=Provider.ServerMode, port=port, cipher=cipher, curve=curve, protocol=protocol, key=certificate.key, cert=certificate.cert, ocsp_response={ "RSA": TEST_OCSP_DIRECTORY + "ocsp_response.der", "EC": TEST_OCSP_DIRECTORY + "ocsp_ecdsa_response.der" }.get(certificate.algorithm), ) kill_marker = None if provider == GnuTLS: kill_marker = random_bytes server = managed_process(provider, server_options, timeout=30, kill_marker=kill_marker) client = managed_process(S2N, client_options, timeout=30) for client_results in client.get_results(): client_results.assert_success() assert b"OCSP response received" in client_results.stdout for server_results in server.get_results(): server_results.assert_success() # Avoid debugging information that sometimes gets inserted after the first character. assert random_bytes[1:] in server_results.stdout or random_bytes[ 1:] in server_results.stderr
def test_s2n_server_happy_path(managed_process, cipher, provider, curve, protocol, certificate): port = next(available_ports) # s2nd can receive large amounts of data because all the data is # echo'd to stdout unmodified. This lets us compare received to # expected easily. # We purposefully send a non block aligned number to make sure # nothing blocks waiting for more data. random_bytes = data_bytes(65519) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, cert=certificate, curve=curve, data_to_send=random_bytes, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) # The client will be one of all supported providers. We # just want to make sure there was no exception and that # the client exited cleanly. for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 expected_version = get_expected_s2n_version(protocol, provider) # The server is always S2N in this test, so we can examine # the stdout reliably. for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Actual protocol version: {}".format( expected_version).encode('utf-8')) in results.stdout assert random_bytes in results.stdout if provider is not S2N: assert bytes("Cipher negotiated: {}".format( cipher.name).encode('utf-8')) in results.stdout
def test_s2nc_tls13_negotiates_tls12(managed_process, cipher, curve, protocol, provider, certificate): port = next(available_ports) random_bytes = data_bytes(24) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, insecure=True, protocol=Protocols.TLS13) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.protocol = protocol server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) client_version = get_expected_s2n_version(Protocols.TLS13, provider) actual_version = get_expected_s2n_version(protocol, provider) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Client protocol version: {}".format( client_version).encode('utf-8')) in results.stdout assert bytes("Actual protocol version: {}".format( actual_version).encode('utf-8')) in results.stdout for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 if provider is S2N: # The server is only TLS12, so it reads the version from the CLIENT_HELLO, which is never above TLS12 # This check only cares about S2N. Trying to maintain expected output of other providers doesn't # add benefit to whether the S2N client was able to negotiate a lower TLS version. assert bytes("Client protocol version: {}".format( actual_version).encode('utf-8')) in results.stdout assert bytes("Actual protocol version: {}".format( actual_version).encode('utf-8')) in results.stdout assert random_bytes in results.stdout
def test_hrr_with_s2n_as_client(managed_process, cipher, provider, curve, protocol, certificate, keyshare): port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, data_to_send=random_bytes, insecure=True, curve=curve, extra_flags=keyshare, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.extra_flags = None server_options.curve = Curves.X25519 # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) # The client should connect and return without error for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes( "Curve: {}".format("x25519").encode('utf-8')) in results.stdout marker_part1 = b"cf 21 ad 74 e5" marker_part2 = b"9a 61 11 be 1d" for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert marker_part1 in results.stdout and marker_part2 in results.stdout if 'none' in keyshare: assert b'"key share" (id=51), len=2\n0000 - 00 00' in results.stdout assert b'Supported Elliptic Groups: X25519:P-256:P-384' in results.stdout assert bytes("Shared Elliptic groups: {}".format( server_options.curve).encode('utf-8')) in results.stdout assert random_bytes in results.stdout
def test_s2n_client_happy_path(managed_process, cipher, provider, curve, protocol, certificate): port = next(available_ports) # We can only send 4096 bytes here because of the way some servers chunk # output (when writing to stdout). If we send 8192 bytes, then openssl # will print some debugging information in the middle of our chunk. # We still want that debugging data in case of a failure, so we just # send less data, rather than lose debug information. random_bytes = data_bytes(4096) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) expected_version = get_expected_s2n_version(protocol, provider) # The client is always S2N in this test, so we can examine # the stdout reliably. for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Actual protocol version: {}".format( expected_version).encode('utf-8')) in results.stdout # The server will be one of all supported providers. We # just want to make sure there was no exception and that # the client exited cleanly. for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 # Avoid debugging information that sometimes gets inserted after the first character assert random_bytes[1:] in results.stdout
def test_s2n_client_dynamic_record(custom_mtu, managed_process, cipher, curve, provider, protocol, certificate): host = "localhost" port = next(available_ports) # 16384 bytes is enough to reliably get a packet that will exceed the MTU bytes_to_send = data_bytes(16384) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, data_to_send=bytes_to_send, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert expected_version = get_expected_s2n_version(protocol, provider) # This test shouldn't last longer than 5 seconds, even though # Tcpdump tends to take a second to startup. tcpdump = managed_process(Tcpdump, client_options, timeout=5) server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Actual protocol version: {}".format( expected_version).encode('utf-8')) in results.stdout for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 # The Tcpdump provider only captures 12 packets. This is enough # to detect a packet larger than the MTU, but less than the # total packets sent. This is important because it lets Tcpdump # exit cleanly, which means all the output is available for us # to examine. for results in tcpdump.get_results(): assert results.exit_code == 0 assert find_fragmented_packet(results.stdout) is True
def test_client_auth_with_s2n_server(managed_process, cipher, provider, protocol, certificate, client_certificate): port = next(available_ports) if protocol < Protocols.TLS12 and client_certificate.algorithm == 'EC': pytest.xfail( "Client auth with ECDSA certs is currently broken for versions < TLS1.2" ) random_bytes = data_bytes(64) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, data_to_send=random_bytes, use_client_auth=True, key=client_certificate.key, cert=client_certificate.cert, trust_store=certificate.cert, insecure=False, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.trust_store = client_certificate.cert server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) # Openssl should send a client certificate and complete the handshake for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert b'write client certificate' in results.stderr assert b'write certificate verify' in results.stderr assert_openssl_handshake_complete(results) # S2N should successfully connect for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert_s2n_handshake_complete(results, protocol, provider) assert random_bytes in results.stdout
def test_s2n_client_signature_algorithms(managed_process, cipher, provider, protocol, certificate, signature, client_auth): port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions( mode=Provider.ClientMode, port=port, cipher=cipher, data_to_send=random_bytes, insecure=True, use_client_auth=client_auth, key=certificate.key, cert=certificate.cert, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.trust_store = certificate.cert server_options.extra_flags=['-sigalgs', signature.name] server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) for results in server.get_results(): results.assert_success() assert random_bytes in results.stdout expected_version = get_expected_s2n_version(protocol, provider) # In versions before TLS1.3, the server uses the negotiated signature scheme for the # ServerKeyExchange message. The server only sends the ServerKeyExchange message when using # a key exchange method that provides forward secrecy, ie, NOT static RSA. # So if using RSA key exchange, there is no actual "negotiated" signature scheme, because # the server never sends the client a signature scheme. # # This mostly has to be inferred from the RFCs, but this blog post is a pretty good summary # of the situation: https://timtaubert.de/blog/2016/07/the-evolution-of-signatures-in-tls/ server_sigalg_used = not cipher.iana_standard_name.startswith("TLS_RSA_WITH_") for results in client.get_results(): results.assert_success() assert to_bytes("Actual protocol version: {}".format(expected_version)) in results.stdout assert signature_marker(Provider.ServerMode, signature) in results.stdout or not server_sigalg_used assert (signature_marker(Provider.ClientMode, signature) in results.stdout) == client_auth
def test_client_auth_with_s2n_server(managed_process, cipher, provider, curve, protocol, certificate): host = "localhost" port = next(available_ports) # NOTE: Client Auth is failing for ECDSA client certs if 'ecdsa' in certificate.cert: pytest.skip("Skipping known failure, ECDSA client auth certificate") random_bytes = data_bytes(64) client_options = ProviderOptions( mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, use_client_auth=True, client_key_file=certificate.key, client_certificate_file=certificate.cert, insecure=False, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = "../pems/rsa_2048_sha256_wildcard_key.pem" server_options.cert = "../pems/rsa_2048_sha256_wildcard_cert.pem" # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) # The client should connect and return without error for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 expected_version = get_expected_s2n_version(protocol, provider) # S2N should indicate the procotol version in a successful connection. for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Actual protocol version: {}".format(expected_version).encode('utf-8')) in results.stdout assert random_bytes in results.stdout
def test_s2n_server_framented_data(managed_process, cipher, provider, other_provider, protocol, certificate, frag_len): if provider is OpenSSL and 'openssl-1.0.2' in provider.get_version(): pytest.skip( '{} does not allow setting max fragmentation for packets'.format( provider)) port = next(available_ports) random_bytes = data_bytes(65519) client_options = ProviderOptions(mode=Provider.ClientMode, port=port, cipher=cipher, data_to_send=random_bytes, insecure=True, record_size=frag_len, protocol=protocol) server_options = copy.copy(client_options) server_options.extra_flags = None server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.cipher = None server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) for client_results in client.get_results(): client_results.assert_success() expected_version = get_expected_s2n_version(protocol, provider) for server_results in server.get_results(): server_results.assert_success() assert to_bytes("Actual protocol version: {}".format( expected_version)) in server_results.stdout if provider == GnuTLS: # GnuTLS ignores data sent through stdin past frag_len up to the application data # packet length of 4096. so, just check to make sure data up to frag_len was received. assert random_bytes[:frag_len] in server_results.stdout else: assert random_bytes in server_results.stdout
def test_hrr_with_s2n_as_client(managed_process, cipher, provider, curve, protocol, certificate): if curve == S2N_DEFAULT_CURVE: pytest.skip("No retry if server curve matches client curve") port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions(mode=Provider.ClientMode, port=port, cipher=cipher, data_to_send=random_bytes, insecure=True, protocol=protocol) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server_options.extra_flags = None server_options.curve = curve # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(provider, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) # The client should connect and return without error for results in client.get_results(): results.assert_success() assert to_bytes("Curve: {}".format( CURVE_NAMES[curve.name])) in results.stdout assert S2N_HRR_MARKER in results.stdout marker_part1 = b"cf 21 ad 74 e5" marker_part2 = b"9a 61 11 be 1d" for results in server.get_results(): results.assert_success() assert marker_part1 in results.stdout and marker_part2 in results.stdout assert b'Supported Elliptic Groups: X25519:P-256:P-384' in results.stdout assert to_bytes("Shared Elliptic groups: {}".format( server_options.curve)) in results.stdout assert random_bytes in results.stdout
def test_s2n_server_signature_algorithms(managed_process, cipher, provider, protocol, certificate, signature, client_auth): port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions(mode=Provider.ClientMode, port=port, cipher=cipher, data_to_send=random_bytes, insecure=False, use_client_auth=client_auth, key=certificate.key, cert=certificate.cert, signature_algorithm=signature, protocol=protocol) if provider == GnuTLS: # GnuTLS fails the CA verification. It must be run with this check disabled. client_options.extra_flags = ["--no-ca-verification"] server_options = copy.copy(client_options) server_options.extra_flags = None server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) for results in client.get_results(): results.assert_success() expected_version = get_expected_s2n_version(protocol, provider) for results in server.get_results(): results.assert_success() assert to_bytes("Actual protocol version: {}".format( expected_version)) in results.stdout assert signature_marker(Provider.ServerMode, signature) in results.stdout assert (signature_marker(Provider.ClientMode, signature) in results.stdout) == client_auth assert random_bytes in results.stdout
def test_s2n_server_signature_algorithms(managed_process, cipher, provider, protocol, certificate, signature, client_auth): port = next(available_ports) random_bytes = data_bytes(64) client_options = ProviderOptions(mode=Provider.ClientMode, host="localhost", port=port, cipher=cipher, data_to_send=random_bytes, insecure=False, use_client_auth=client_auth, key=certificate.key, cert=certificate.cert, extra_flags=['-sigalgs', signature.name], protocol=protocol) server_options = copy.copy(client_options) server_options.extra_flags = None server_options.data_to_send = None server_options.mode = Provider.ServerMode server_options.key = certificate.key server_options.cert = certificate.cert server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes('Peer signing digest: {}'.format( signature.sig_digest).encode('utf-8')) in results.stdout assert bytes('Peer signature type: {}'.format( signature.sig_type).encode('utf-8')) in results.stdout expected_version = get_expected_s2n_version(protocol, provider) for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert bytes("Actual protocol version: {}".format( expected_version).encode('utf-8')) in results.stdout assert random_bytes in results.stdout
def test_s2n_server_happy_path(managed_process, cipher, curve, provider): host = "localhost" port = next(available_ports) # s2nd can receive large amounts of data because all the data is # echo'd to stdout unmodified. This lets us compare received to # expected easily. # The downside here is that, should the test fail, all 4 mbs will # be dumped in the exception. random_bytes = data_bytes(4194304) client_options = ProviderOptions(mode="client", host="localhost", port=port, cipher=cipher, curve=curve, data_to_send=random_bytes, insecure=True, tls13=True) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = "server" server_options.key = "../pems/ecdsa_p384_pkcs1_key.pem" server_options.cert = "../pems/ecdsa_p384_pkcs1_cert.pem" # Passing the type of client and server as a parameter will # allow us to use a fixture to enumerate all possibilities. server = managed_process(S2N, server_options, timeout=5) client = managed_process(provider, client_options, timeout=5) # The client will be one of all supported providers. We # just want to make sure there was no exception and that # the client exited cleanly. for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 # The server is always S2N in this test, so we can examine # the stdout reliably. for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 assert b"Actual protocol version: 34" in results.stdout assert random_bytes in results.stdout
def test_s2n_client_psk_connection(managed_process, cipher, curve, protocol, provider, other_provider, psk_identity, psk_secret): port = next(available_ports) random_bytes = data_bytes(10) psk_hash_alg = get_psk_hash_alg_from_cipher(cipher) skip_invalid_psk_tests(provider, psk_hash_alg) client_psk_params = setup_s2n_psk_params(psk_identity, psk_secret, psk_hash_alg) client_options = setup_provider_options(S2N.ClientMode, port, cipher, curve, None, random_bytes, client_psk_params) if provider == S2N: server_psk_params = setup_s2n_psk_params(psk_identity, psk_secret, psk_hash_alg) else: server_psk_params = setup_openssl_psk_params(psk_identity, psk_secret) server_psk_params += ['-nocert'] server_options = setup_provider_options(provider.ServerMode, port, cipher, curve, None, None, server_psk_params) server = managed_process(provider, server_options, timeout=5, close_marker=str(random_bytes)) client = managed_process(S2N, client_options, timeout=5) for results in client.get_results(): results.assert_success() validate_negotiated_psk_s2n(Outcome.psk_connection, psk_identity, results) for results in server.get_results(): results.assert_success() if provider == S2N: validate_negotiated_psk_s2n(Outcome.psk_connection, psk_identity, results) else: validate_negotiated_psk_openssl(Outcome.psk_connection, results) assert random_bytes in results.stdout
def test_s2n_client_dynamic_record(custom_mtu, managed_process, cipher, curve): host = "localhost" port = next(available_ports) # 16384 bytes is enough to reliably get a packet that will exceed the MTU bytes_to_send = data_bytes(16384) client_options = ProviderOptions(mode="client", host="localhost", port=port, cipher=cipher, data_to_send=bytes_to_send, insecure=True, tls13=True) server_options = copy.copy(client_options) server_options.data_to_send = None server_options.mode = "server" server_options.key = "../pems/ecdsa_p384_pkcs1_key.pem" server_options.cert = "../pems/ecdsa_p384_pkcs1_cert.pem" # This test shouldn't last longer than 5 seconds, even though # Tcpdump tends to take a second to startup. tcpdump = managed_process(Tcpdump, client_options, timeout=5) server = managed_process(OpenSSL, server_options, timeout=5) client = managed_process(S2N, client_options, timeout=5) for results in client.get_results(): assert results.exception is None assert results.exit_code == 0 assert b"Actual protocol version: 34" in results.stdout for results in server.get_results(): assert results.exception is None assert results.exit_code == 0 # The Tcpdump provider only captures 12 packets. This is enough # to detect a packet larger than the MTU, but less than the # total packets sent. This is important because it lets Tcpdump # exit cleanly, which means all the output is available for us # to examine. for results in tcpdump.get_results(): assert results.exit_code == 0 assert find_fragmented_packet(results.stdout) is True