diff options
author | Péter Dimitrov <[email protected]> | 2019-02-14 14:40:40 +0100 |
---|---|---|
committer | Péter Dimitrov <[email protected]> | 2019-02-14 14:40:40 +0100 |
commit | 5da74b88496c9231d2fbd9cb2b7aea1121b79fa0 (patch) | |
tree | 3edf51c8096c1f44a5bb87bfe59aca8bddab67a6 /lib/ssl | |
parent | 3103cc205c30dff1c9fe50380eaeed9189a799e4 (diff) | |
parent | a3de6360569ccbf3be7c10bde88d903f5968d825 (diff) | |
download | otp-5da74b88496c9231d2fbd9cb2b7aea1121b79fa0.tar.gz otp-5da74b88496c9231d2fbd9cb2b7aea1121b79fa0.tar.bz2 otp-5da74b88496c9231d2fbd9cb2b7aea1121b79fa0.zip |
Merge branch 'peterdmv/ssl/server-process-client-finished'
* peterdmv/ssl/server-process-client-finished:
ssl: Test TLS 1.3 connectivity
ssl: Fix crash when sending Alerts
ssl: Fix dialyzer warning
ssl: Improve TLS 1.3 statem
Change-Id: I258e0309ba3a132d5ab2056151935a3df8646344
Diffstat (limited to 'lib/ssl')
-rw-r--r-- | lib/ssl/src/ssl_cipher.hrl | 1 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 2 | ||||
-rw-r--r-- | lib/ssl/src/tls_connection.erl | 7 | ||||
-rw-r--r-- | lib/ssl/src/tls_connection_1_3.erl | 33 | ||||
-rw-r--r-- | lib/ssl/src/tls_handshake_1_3.erl | 165 | ||||
-rw-r--r-- | lib/ssl/src/tls_record.erl | 14 | ||||
-rw-r--r-- | lib/ssl/src/tls_record_1_3.erl | 17 | ||||
-rw-r--r-- | lib/ssl/src/tls_v1.erl | 10 | ||||
-rw-r--r-- | lib/ssl/test/ssl_basic_SUITE.erl | 188 | ||||
-rw-r--r-- | lib/ssl/test/ssl_test_lib.erl | 16 |
10 files changed, 390 insertions, 63 deletions
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 5891f3a7cc..00822ad9de 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -47,6 +47,7 @@ -record(cipher_state, { iv, key, + finished_key, state, nonce, tag_len diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index cd8baf0434..57f7027ba6 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -39,7 +39,7 @@ %% Setup --export([connect/8, handshake/7, handshake/2, handshake/3, +-export([connect/8, handshake/7, handshake/2, handshake/3, handle_common_event/5, handshake_continue/3, handshake_cancel/1, socket_control/4, socket_control/5, start_or_recv_cancel_timer/2]). diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl index 159250e6d7..e7388f9573 100644 --- a/lib/ssl/src/tls_connection.erl +++ b/lib/ssl/src/tls_connection.erl @@ -50,7 +50,8 @@ handle_protocol_record/3]). %% Handshake handling --export([renegotiation/2, renegotiate/2, send_handshake/2, +-export([renegotiation/2, renegotiate/2, send_handshake/2, + send_handshake_flight/1, queue_handshake/2, queue_change_cipher/2, reinit/1, reinit_handshake_data/1, select_sni_extension/1, empty_connection_state/2]). @@ -225,8 +226,8 @@ decode_cipher_texts(Version, Type, {#ssl_tls{type = ?APPLICATION_DATA, fragment = Plain}, ConnectionStates} -> decode_cipher_texts(Version, Type, CipherTexts, ConnectionStates, Check, <<Acc/binary, Plain/binary>>); - {#ssl_tls{type = Type, fragment = Plain}, ConnectionStates} -> - {#ssl_tls{type = Type, fragment = Plain}, ConnectionStates, CipherTexts}; + {#ssl_tls{type = Type0, fragment = Plain}, ConnectionStates} -> + {#ssl_tls{type = Type0, fragment = Plain}, ConnectionStates, CipherTexts}; #alert{} = Alert -> {Alert, ConnectionStates0, CipherTexts} end; diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl index 48b3ff0d97..621e86f4b5 100644 --- a/lib/ssl/src/tls_connection_1_3.erl +++ b/lib/ssl/src/tls_connection_1_3.erl @@ -109,7 +109,8 @@ %% gen_statem helper functions -export([start/4, - negotiated/4 + negotiated/4, + wait_finished/4 ]). start(internal, @@ -135,20 +136,38 @@ start(internal, end. -%% TODO: remove suppression when function implemented! --dialyzer([{nowarn_function, [negotiated/4]}, no_match]). negotiated(internal, Map, State0, _Module) -> case tls_handshake_1_3:do_negotiated(Map, State0) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, {3,4}, negotiated, State0); - M -> - %% TODO: implement update_state - %% State = update_state(State0, M), - {next_state, wait_flight2, State0, [{next_event, internal, M}]} + State -> + {next_state, wait_finished, State, []} end. +wait_finished(internal, + #change_cipher_spec{} = ChangeCipherSpec, State0, _Module) -> + case tls_handshake_1_3:do_wait_finished(ChangeCipherSpec, State0) of + #alert{} = Alert -> + ssl_connection:handle_own_alert(Alert, {3,4}, wait_finished, State0); + State1 -> + {Record, State} = tls_connection:next_record(State1), + tls_connection:next_event(?FUNCTION_NAME, Record, State) + end; +wait_finished(internal, + #finished{} = Finished, State0, Module) -> + case tls_handshake_1_3:do_wait_finished(Finished, State0) of + #alert{} = Alert -> + ssl_connection:handle_own_alert(Alert, {3,4}, finished, State0); + State1 -> + {Record, State} = ssl_connection:prepare_connection(State1, Module), + tls_connection:next_event(connection, Record, State) + end; +wait_finished(Type, Msg, State, Connection) -> + ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). + + update_state(#state{connection_states = ConnectionStates0, session = Session} = State, #{cipher := Cipher, diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl index f92c54dc53..e009524f98 100644 --- a/lib/ssl/src/tls_handshake_1_3.erl +++ b/lib/ssl/src/tls_handshake_1_3.erl @@ -45,7 +45,8 @@ encrypted_extensions/0, server_hello/4]). --export([do_negotiated/2]). +-export([do_negotiated/2, + do_wait_finished/2]). %%==================================================================== %% Create handshake messages @@ -148,12 +149,11 @@ finished(#state{connection_states = ConnectionStates, handshake_env = #handshake_env{ tls_handshake_history = {Messages, _}}}) -> - #{security_parameters := SecParamsR} = + #{security_parameters := SecParamsR, + cipher_state := #cipher_state{finished_key = FinishedKey}} = ssl_record:current_connection_state(ConnectionStates, write), - #security_parameters{prf_algorithm = HKDFAlgo, - master_secret = SHTS} = SecParamsR, + #security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR, - FinishedKey = tls_v1:finished_key(SHTS, HKDFAlgo), VerifyData = tls_v1:finished_verify_data(FinishedKey, HKDFAlgo, Messages), #finished{ @@ -468,12 +468,8 @@ do_negotiated(#{client_share := ClientKey, {State1, _} = tls_connection:send_handshake(ServerHello, State0), - {HandshakeSecret, ReadKey, ReadIV, WriteKey, WriteIV} = - calculate_security_parameters(ClientKey, SelectedGroup, KeyShare, State1), - State2 = - update_pending_connection_states(State1, HandshakeSecret, - ReadKey, ReadIV, WriteKey, WriteIV), + calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare, State1), State3 = ssl_record:step_encryption_state(State2), @@ -498,33 +494,88 @@ do_negotiated(#{client_share := ClientKey, %% Create Finished Finished = finished(State6), - %% Encode Certificate, CertifricateVerify - {_State7, _} = tls_connection:send_handshake(Finished, State6), + %% Encode Finished + State7 = tls_connection:queue_handshake(Finished, State6), + + %% Send first flight + {State8, _} = tls_connection:send_handshake_flight(State7), + + State8 + + catch + {Ref, {state_not_implemented, State}} -> + %% TODO + ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {state_not_implemented, State}) + end. - %% Send finished - %% Next record/Next event +do_wait_finished(#change_cipher_spec{}, + #state{connection_states = _ConnectionStates0, + session = #session{session_id = _SessionId, + own_certificate = _OwnCert}, + ssl_options = #ssl_options{} = _SslOpts, + key_share = _KeyShare, + handshake_env = #handshake_env{tls_handshake_history = _HHistory0}, + private_key = _CertPrivateKey, + static_env = #static_env{ + cert_db = _CertDbHandle, + cert_db_ref = _CertDbRef, + socket = _Socket, + transport_cb = _Transport} + } = State0) -> + %% {Ref,Maybe} = maybe(), - Maybe(not_implemented(negotiated)) + try + State0 catch - {Ref, {state_not_implemented, State}} -> + {_Ref, {state_not_implemented, State}} -> + ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {state_not_implemented, State}) + end; +do_wait_finished(#finished{}, + #state{connection_states = _ConnectionStates0, + session = #session{session_id = _SessionId, + own_certificate = _OwnCert}, + ssl_options = #ssl_options{} = _SslOpts, + key_share = _KeyShare, + handshake_env = #handshake_env{tls_handshake_history = _HHistory0}, + private_key = _CertPrivateKey, + static_env = #static_env{ + cert_db = _CertDbHandle, + cert_db_ref = _CertDbRef, + socket = _Socket, + transport_cb = _Transport} + } = State0) -> + + %% {Ref,Maybe} = maybe(), + + try + %% TODO: validate client Finished + + State1 = calculate_traffic_secrets(State0), + + %% Configure traffic keys + ssl_record:step_encryption_state(State1) + + + catch + {_Ref, {state_not_implemented, State}} -> %% TODO ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {state_not_implemented, State}) end. %% TODO: Remove this function! -not_implemented(State) -> - {error, {state_not_implemented, State}}. +%% not_implemented(State) -> +%% {error, {state_not_implemented, State}}. -calculate_security_parameters(ClientKey, SelectedGroup, KeyShare, +calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare, #state{connection_states = ConnectionStates, handshake_env = #handshake_env{ - tls_handshake_history = HHistory}}) -> + tls_handshake_history = HHistory}} = State0) -> #{security_parameters := SecParamsR} = ssl_record:pending_connection_state(ConnectionStates, read), #security_parameters{prf_algorithm = HKDFAlgo, @@ -550,23 +601,46 @@ calculate_security_parameters(ClientKey, SelectedGroup, KeyShare, {ReadKey, ReadIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ClientHSTrafficSecret), {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ServerHSTrafficSecret), - %% TODO: store all relevant secrets in state! - {ServerHSTrafficSecret, ReadKey, ReadIV, WriteKey, WriteIV}. + %% Calculate Finished Keys + ReadFinishedKey = tls_v1:finished_key(ClientHSTrafficSecret, HKDFAlgo), + WriteFinishedKey = tls_v1:finished_key(ServerHSTrafficSecret, HKDFAlgo), + + update_pending_connection_states(State0, HandshakeSecret, + ReadKey, ReadIV, ReadFinishedKey, + WriteKey, WriteIV, WriteFinishedKey). + +calculate_traffic_secrets(#state{connection_states = ConnectionStates, + handshake_env = + #handshake_env{ + tls_handshake_history = HHistory}} = State0) -> + #{security_parameters := SecParamsR} = + ssl_record:pending_connection_state(ConnectionStates, read), + #security_parameters{prf_algorithm = HKDFAlgo, + cipher_suite = CipherSuite, + master_secret = HandshakeSecret} = SecParamsR, + + MasterSecret = + tls_v1:key_schedule(master_secret, HKDFAlgo, HandshakeSecret), - %% %% Update pending connection state - %% PendingRead0 = ssl_record:pending_connection_state(ConnectionStates, read), - %% PendingWrite0 = ssl_record:pending_connection_state(ConnectionStates, write), + {Messages0, _} = HHistory, - %% PendingRead = update_conn_state(PendingRead0, HandshakeSecret, ReadKey, ReadIV), - %% PendingWrite = update_conn_state(PendingWrite0, HandshakeSecret, WriteKey, WriteIV), + %% Drop Client Finish + [_|Messages] = Messages0, + + %% Calculate [sender]_application_traffic_secret_0 + ClientAppTrafficSecret0 = + tls_v1:client_application_traffic_secret_0(HKDFAlgo, MasterSecret, lists:reverse(Messages)), + ServerAppTrafficSecret0 = + tls_v1:server_application_traffic_secret_0(HKDFAlgo, MasterSecret, lists:reverse(Messages)), + + %% Calculate traffic keys + #{cipher := Cipher} = ssl_cipher_format:suite_definition(CipherSuite), + {ReadKey, ReadIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ClientAppTrafficSecret0), + {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ServerAppTrafficSecret0), - %% %% Update pending and copy to current (activate) - %% %% All subsequent handshake messages are encrypted - %% %% ([sender]_handshake_traffic_secret) - %% #{current_read => PendingRead, - %% current_write => PendingWrite, - %% pending_read => PendingRead, - %% pending_write => PendingWrite}. + update_pending_connection_states(State0, MasterSecret, + ReadKey, ReadIV, undefined, + WriteKey, WriteIV, undefined). get_server_private_key(#key_share_server_hello{server_share = ServerShare}) -> @@ -602,24 +676,31 @@ calculate_shared_secret(OthersKey, MyKey = #'ECPrivateKey'{}, _Group) update_pending_connection_states(#state{connection_states = CS = #{pending_read := PendingRead0, pending_write := PendingWrite0}} = State, - HandshakeSecret, ReadKey, ReadIV, WriteKey, WriteIV) -> - PendingRead = update_connection_state(PendingRead0, HandshakeSecret, ReadKey, ReadIV), - PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret, WriteKey, WriteIV), + HandshakeSecret, + ReadKey, ReadIV, ReadFinishedKey, + WriteKey, WriteIV, WriteFinishedKey) -> + PendingRead = update_connection_state(PendingRead0, HandshakeSecret, + ReadKey, ReadIV, ReadFinishedKey), + PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret, + WriteKey, WriteIV, WriteFinishedKey), State#state{connection_states = CS#{pending_read => PendingRead, - pending_write => PendingWrite}}. + pending_write => PendingWrite}}. update_connection_state(ConnectionState = #{security_parameters := SecurityParameters0}, - HandshakeSecret, Key, IV) -> + HandshakeSecret, Key, IV, FinishedKey) -> %% Store secret SecurityParameters = SecurityParameters0#security_parameters{ master_secret = HandshakeSecret}, ConnectionState#{security_parameters => SecurityParameters, - cipher_state => cipher_init(Key, IV)}. + cipher_state => cipher_init(Key, IV, FinishedKey)}. -cipher_init(Key, IV) -> - #cipher_state{key = Key, iv = IV, tag_len = 16}. +cipher_init(Key, IV, FinishedKey) -> + #cipher_state{key = Key, + iv = IV, + finished_key = FinishedKey, + tag_len = 16}. %% If there is no overlap between the received diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl index ad2bfb7a5c..96e851de41 100644 --- a/lib/ssl/src/tls_record.erl +++ b/lib/ssl/src/tls_record.erl @@ -119,7 +119,7 @@ encode_handshake(Frag, Version, %% Description: Encodes an alert message to send on the ssl-socket. %%-------------------------------------------------------------------- encode_alert_record(Alert, {3, 4}, ConnectionStates) -> - tls_record_1_3:encode_handshake(Alert, ConnectionStates); + tls_record_1_3:encode_alert_record(Alert, ConnectionStates); encode_alert_record(#alert{level = Level, description = Description}, Version, ConnectionStates) -> encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>, @@ -398,6 +398,18 @@ initial_connection_state(ConnectionEnd, BeastMitigation) -> server_verify_data => undefined }. +%% TLS 1.3 +get_tls_records_aux({3,4} = Version, <<?BYTE(Type),?BYTE(3),?BYTE(3), + ?UINT16(Length), Data:Length/binary, + Rest/binary>> = RawTLSRecord, + Acc, SslOpts) when Type == ?APPLICATION_DATA; + Type == ?HANDSHAKE; + Type == ?ALERT; + Type == ?CHANGE_CIPHER_SPEC -> + ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'tls_record', [RawTLSRecord]), + get_tls_records_aux(Version, Rest, [#ssl_tls{type = Type, + version = {3,3}, %% Use legacy version + fragment = Data} | Acc], SslOpts); get_tls_records_aux({MajVer, MinVer} = Version, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer), ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawTLSRecord, Acc, SslOpts) when Type == ?APPLICATION_DATA; diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl index 1681babed9..05acc08392 100644 --- a/lib/ssl/src/tls_record_1_3.erl +++ b/lib/ssl/src/tls_record_1_3.erl @@ -123,6 +123,23 @@ decode_cipher_text(#ssl_tls{type = ?OPAQUE_TYPE, ReadState0#{sequence_number => Seq + 1}}, {decode_inner_plaintext(PlainFragment), ConnectionStates} end; + +%% RFC8446 - TLS 1.3 +%% D.4. Middlebox Compatibility Mode +%% - If not offering early data, the client sends a dummy +%% change_cipher_spec record (see the third paragraph of Section 5) +%% immediately before its second flight. This may either be before +%% its second ClientHello or before its encrypted handshake flight. +%% If offering early data, the record is placed immediately after the +%% first ClientHello. +decode_cipher_text(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, + version = ?LEGACY_VERSION, + fragment = <<1>>}, + ConnectionStates0) -> + {#ssl_tls{type = ?CHANGE_CIPHER_SPEC, + version = {3,4}, %% Internally use real version + fragment = <<1>>}, ConnectionStates0}; + decode_cipher_text(#ssl_tls{type = Type, version = ?LEGACY_VERSION, fragment = CipherFragment}, diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl index 5c023bd2d8..f103f3218b 100644 --- a/lib/ssl/src/tls_v1.erl +++ b/lib/ssl/src/tls_v1.erl @@ -64,7 +64,7 @@ %% TLS 1.3 --------------------------------------------------- -spec derive_secret(Secret::binary(), Label::binary(), - Messages::iodata(), Algo::ssl_cipher_format:hash()) -> Key::binary(). + Messages::iodata(), Algo::ssl:hash()) -> Key::binary(). derive_secret(Secret, Label, Messages, Algo) -> Hash = crypto:hash(mac_algo(Algo), Messages), hkdf_expand_label(Secret, Label, @@ -72,7 +72,7 @@ derive_secret(Secret, Label, Messages, Algo) -> -spec hkdf_expand_label(Secret::binary(), Label0::binary(), Context::binary(), Length::integer(), - Algo::ssl_cipher_format:hash()) -> KeyingMaterial::binary(). + Algo::ssl:hash()) -> KeyingMaterial::binary(). hkdf_expand_label(Secret, Label0, Context, Length, Algo) -> HkdfLabel = create_info(Label0, Context, Length), hkdf_expand(Secret, HkdfLabel, Length, Algo). @@ -93,7 +93,7 @@ create_info(Label0, Context0, Length) -> Content = <<Label/binary, Context/binary>>, <<?UINT16(Length), Content/binary>>. --spec hkdf_extract(MacAlg::ssl_cipher_format:hash(), Salt::binary(), +-spec hkdf_extract(MacAlg::ssl:hash(), Salt::binary(), KeyingMaterial::binary()) -> PseudoRandKey::binary(). hkdf_extract(MacAlg, Salt, KeyingMaterial) -> @@ -101,14 +101,14 @@ hkdf_extract(MacAlg, Salt, KeyingMaterial) -> -spec hkdf_expand(PseudoRandKey::binary(), ContextInfo::binary(), - Length::integer(), Algo::ssl_cipher_format:hash()) -> KeyingMaterial::binary(). + Length::integer(), Algo::ssl:hash()) -> KeyingMaterial::binary(). hkdf_expand(PseudoRandKey, ContextInfo, Length, Algo) -> Iterations = erlang:ceil(Length / ssl_cipher:hash_size(Algo)), hkdf_expand(Algo, PseudoRandKey, ContextInfo, Length, 1, Iterations, <<>>, <<>>). --spec transcript_hash(Messages::iodata(), Algo::ssl_cipher_format:hash()) -> Hash::binary(). +-spec transcript_hash(Messages::iodata(), Algo::ssl:hash()) -> Hash::binary(). transcript_hash(Messages, Algo) -> crypto:hash(mac_algo(Algo), Messages). diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index bcb1f4f4fd..6e34ab73b8 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -275,7 +275,8 @@ tls13_test_group() -> tls13_enable_server_side, tls_record_1_3_encode_decode, tls13_finished_verify_data, - tls13_1_RTT_handshake]. + tls13_1_RTT_handshake, + tls13_basic_ssl_s_client]. %%-------------------------------------------------------------------- init_per_suite(Config0) -> @@ -4438,7 +4439,7 @@ tls_record_1_3_encode_decode(_Config) -> 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, - undefined,undefined,16}, + undefined,undefined,undefined,16}, client_verify_data => undefined,compression_state => undefined, mac_secret => undefined,secure_renegotiation => undefined, security_parameters => @@ -4464,7 +4465,7 @@ tls_record_1_3_encode_decode(_Config) -> 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>, <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228, 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>, - undefined,undefined,16}, + undefined,undefined,undefined,16}, client_verify_data => undefined,compression_state => undefined, mac_secret => undefined,secure_renegotiation => undefined, security_parameters => @@ -5029,7 +5030,164 @@ tls13_1_RTT_handshake(_Config) -> FinishedHS = #finished{verify_data = FinishedVerifyData}, FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}), - FinishedHSBin = iolist_to_binary(FinishedIOList). + FinishedHSBin = iolist_to_binary(FinishedIOList), + + %% {server} derive secret "tls13 c ap traffic": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 + %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce + %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5 + + %% PRK = MasterSecret + CAPTHash = + hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + CAPTInfo = + hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72 + 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + CAPTrafficSecret = + hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce + 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"), + + CHSF = <<ClientHello/binary, + ServerHello/binary, + EncryptedExtensions/binary, + Certificate/binary, + CertificateVerify/binary, + FinishedHSBin/binary>>, + + CAPTHash = crypto:hash(HKDFAlgo, CHSF), + + CAPTInfo = + tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + CAPTrafficSecret = + tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive secret "tls13 s ap traffic": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 + %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 + %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 + + %% PRK = MasterSecret + %% hash = CAPTHash + SAPTInfo = + hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72 + 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b + 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + SAPTrafficSecret = + hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 + 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"), + + SAPTInfo = + tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + SAPTrafficSecret = + tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive secret "tls13 exp master": + %% + %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 + %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19 + %% + %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a + %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 + %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 + %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13 + %% + %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 + %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50 + + %% PRK = MasterSecret + %% hash = CAPTHash + ExporterInfo = + hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73 + 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00 + 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"), + + ExporterMasterSecret = + hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67 + 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"), + + ExporterInfo = + tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)), + + ExporterMasterSecret = + tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF), + + %% {server} derive write traffic keys for application data: + %% + %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32 + %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac + %% 92 e3 56 + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84 + + %% PRK = SAPTrafficsecret + %% key info = WriteKeyInfo + %% iv info = WrtieIVInfo + SWKey = + hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"), + + SWIV = + hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"), + + {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret), + + %% {server} derive read traffic keys for handshake data: + %% + %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f + %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21 + %% + %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00 + %% + %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 + %% 25 8d 01 + %% + %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00 + %% + %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f + + %% PRK = CHSTrafficsecret + %% key info = WriteKeyInfo + %% iv info = WrtieIVInfo + SRKey = + hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"), + + SRIV = + hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"), + + {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret). tls13_finished_verify_data() -> @@ -5154,6 +5312,28 @@ tls13_finished_verify_data(_Config) -> FinishedKey = tls_v1:finished_key(BaseKey, sha256), VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages). +tls13_basic_ssl_s_client() -> + [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client"}]. + +tls13_basic_ssl_s_client(Config) -> + ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config), + ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config), + %% Set versions + ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], + {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts), + + ssl_test_lib:check_result(Server, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close_port(Client). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index b350dabcaf..c921dcae4c 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -1106,6 +1106,20 @@ ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) -> Client = start_client_ecc_error(erlang, Port, COpts, CECCOpts, Config), check_server_alert(Server, Client, insufficient_security). +start_basic_client(openssl, Version, Port, ClientOpts) -> + Cert = proplists:get_value(certfile, ClientOpts), + Key = proplists:get_value(keyfile, ClientOpts), + CA = proplists:get_value(cacertfile, ClientOpts), + Exe = "openssl", + Args = ["s_client", "-verify", "2", "-port", integer_to_list(Port), + ssl_test_lib:version_flag(Version), + "-cert", Cert, "-CAfile", CA, + "-key", Key, "-host","localhost", "-msg", "-debug"], + + OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args), + true = port_command(OpenSslPort, "Hello world"), + OpenSslPort. + start_client(openssl, Port, ClientOpts, Config) -> Cert = proplists:get_value(certfile, ClientOpts), Key = proplists:get_value(keyfile, ClientOpts), @@ -1911,6 +1925,8 @@ version_flag('tlsv1.1') -> "-tls1_1"; version_flag('tlsv1.2') -> "-tls1_2"; +version_flag('tlsv1.3') -> + "-tls1_3"; version_flag(sslv3) -> "-ssl3"; version_flag(sslv2) -> |