%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2007-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% %%---------------------------------------------------------------------- %% Purpose: TODO %%---------------------------------------------------------------------- %% RFC 8446 %% A.1. Client %% %% START <----+ %% Send ClientHello | | Recv HelloRetryRequest %% [K_send = early data] | | %% v | %% / WAIT_SH ----+ %% | | Recv ServerHello %% | | K_recv = handshake %% Can | V %% send | WAIT_EE %% early | | Recv EncryptedExtensions %% data | +--------+--------+ %% | Using | | Using certificate %% | PSK | v %% | | WAIT_CERT_CR %% | | Recv | | Recv CertificateRequest %% | | Certificate | v %% | | | WAIT_CERT %% | | | | Recv Certificate %% | | v v %% | | WAIT_CV %% | | | Recv CertificateVerify %% | +> WAIT_FINISHED <+ %% | | Recv Finished %% \ | [Send EndOfEarlyData] %% | K_send = handshake %% | [Send Certificate [+ CertificateVerify]] %% Can send | Send Finished %% app data --> | K_send = K_recv = application %% after here v %% CONNECTED %% %% A.2. Server %% %% START <-----+ %% Recv ClientHello | | Send HelloRetryRequest %% v | %% RECVD_CH ----+ %% | Select parameters %% v %% NEGOTIATED %% | Send ServerHello %% | K_send = handshake %% | Send EncryptedExtensions %% | [Send CertificateRequest] %% Can send | [Send Certificate + CertificateVerify] %% app data | Send Finished %% after --> | K_send = application %% here +--------+--------+ %% No 0-RTT | | 0-RTT %% | | %% K_recv = handshake | | K_recv = early data %% [Skip decrypt errors] | +------> WAIT_EOED -+ %% | | Recv | | Recv EndOfEarlyData %% | | early data | | K_recv = handshake %% | +------------+ | %% | | %% +> WAIT_FLIGHT2 <--------+ %% | %% +--------+--------+ %% No auth | | Client auth %% | | %% | v %% | WAIT_CERT %% | Recv | | Recv Certificate %% | empty | v %% | Certificate | WAIT_CV %% | | | Recv %% | v | CertificateVerify %% +-> WAIT_FINISHED <---+ %% | Recv Finished %% | K_recv = application %% v %% CONNECTED -module(tls_connection_1_3). -include("ssl_alert.hrl"). -include("ssl_connection.hrl"). -include("tls_handshake.hrl"). -include("tls_handshake_1_3.hrl"). %% gen_statem helper functions -export([start/4, negotiated/4, wait_cert/4, wait_cv/4, wait_finished/4, wait_sh/4, wait_ee/4, wait_cert_cr/4 ]). start(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); start(internal, #client_hello{} = Hello, State0, _Module) -> case tls_handshake_1_3:do_start(Hello, State0) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, {3,4}, start, State0); {State, start} -> {next_state, start, State, []}; {State, negotiated} -> {next_state, negotiated, State, [{next_event, internal, start_handshake}]} end; start(internal, #server_hello{} = ServerHello, State0, _Module) -> case tls_handshake_1_3:do_start(ServerHello, State0) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, {3,4}, start, State0); {State, NextState} -> {next_state, NextState, State, []} end; start(Type, Msg, State, Connection) -> ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). negotiated(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); negotiated(internal, Message, State0, _Module) -> case tls_handshake_1_3:do_negotiated(Message, State0) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, {3,4}, negotiated, State0); {State, NextState} -> {next_state, NextState, State, []} end. wait_cert(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); wait_cert(internal, #certificate_1_3{} = Certificate, State0, _Module) -> case tls_handshake_1_3:do_wait_cert(Certificate, State0) of {#alert{} = Alert, State} -> ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert, State); {State, NextState} -> tls_connection:next_event(NextState, no_record, State) end; wait_cert(Type, Msg, State, Connection) -> ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). wait_cv(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); wait_cv(internal, #certificate_verify_1_3{} = CertificateVerify, State0, _Module) -> case tls_handshake_1_3:do_wait_cv(CertificateVerify, State0) of {#alert{} = Alert, State} -> ssl_connection:handle_own_alert(Alert, {3,4}, wait_cv, State); {State, NextState} -> tls_connection:next_event(NextState, no_record, State) end; wait_cv(Type, Msg, State, Connection) -> ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). wait_finished(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); 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). wait_sh(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); wait_sh(internal, #server_hello{} = Hello, State0, _Module) -> case tls_handshake_1_3:do_wait_sh(Hello, State0) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, {3,4}, wait_sh, State0); {State1, start, ServerHello} -> %% hello_retry_request: go to start {next_state, start, State1, [{next_event, internal, ServerHello}]}; {State1, wait_ee} -> tls_connection:next_event(wait_ee, no_record, State1) end; wait_sh(Type, Msg, State, Connection) -> ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). wait_ee(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); wait_ee(internal, #encrypted_extensions{} = EE, State0, _Module) -> case tls_handshake_1_3:do_wait_ee(EE, State0) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, {3,4}, wait_ee, State0); {State1, NextState} -> tls_connection:next_event(NextState, no_record, State1) end; wait_ee(Type, Msg, State, Connection) -> ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection). wait_cert_cr(internal, #change_cipher_spec{}, State, _Module) -> tls_connection:next_event(?FUNCTION_NAME, no_record, State); wait_cert_cr(internal, #certificate_1_3{} = Certificate, State0, _Module) -> case tls_handshake_1_3:do_wait_cert_cr(Certificate, State0) of {#alert{} = Alert, State} -> ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State); {State1, NextState} -> tls_connection:next_event(NextState, no_record, State1) end; wait_cert_cr(internal, #certificate_request_1_3{} = CertificateRequest, State0, _Module) -> case tls_handshake_1_3:do_wait_cert_cr(CertificateRequest, State0) of #alert{} = Alert -> ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State0); {State1, NextState} -> tls_connection:next_event(NextState, no_record, State1) end; wait_cert_cr(Type, Msg, State, Connection) -> ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).