aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
authorPéter Dimitrov <[email protected]>2019-01-11 16:45:51 +0100
committerPéter Dimitrov <[email protected]>2019-01-28 09:37:07 +0100
commit9cdc4cb22a4465709e347c07f240fd6e3a74b490 (patch)
treed6ea189eda72b9fe9c0aff0e4765619780b944f6 /lib/ssl
parent1ea703443fa0bbc3aade0bb61fc96b2f0cf6b84c (diff)
downloadotp-9cdc4cb22a4465709e347c07f240fd6e3a74b490.tar.gz
otp-9cdc4cb22a4465709e347c07f240fd6e3a74b490.tar.bz2
otp-9cdc4cb22a4465709e347c07f240fd6e3a74b490.zip
ssl: Encode/decode CertificateVerify
Implement encoding/decoding of CertificateVerify. Update property tests with CertificateVerify. Refactor state handling function: 'do_negotiated'. Change-Id: Ifa066076960120717ddb472dc45fcc7a16a517d0
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/src/ssl_logger.erl12
-rw-r--r--lib/ssl/src/ssl_record.erl11
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl31
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl94
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_handshake.erl50
5 files changed, 126 insertions, 72 deletions
diff --git a/lib/ssl/src/ssl_logger.erl b/lib/ssl/src/ssl_logger.erl
index ce8225bf72..39b8c517b6 100644
--- a/lib/ssl/src/ssl_logger.erl
+++ b/lib/ssl/src/ssl_logger.erl
@@ -35,6 +35,7 @@
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
-include("tls_handshake.hrl").
+-include("tls_handshake_1_3.hrl").
-include_lib("kernel/include/logger.hrl").
%%-------------------------------------------------------------------------
@@ -159,8 +160,19 @@ parse_handshake(Direction, #hello_request{} = HelloRequest) ->
Header = io_lib:format("~s Handshake, HelloRequest",
[header_prefix(Direction)]),
Message = io_lib:format("~p", [?rec_info(hello_request, HelloRequest)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_1_3{} = Certificate) ->
+ Header = io_lib:format("~s Handshake, Certificate",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_1_3, Certificate)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_verify_1_3{} = CertificateVerify) ->
+ Header = io_lib:format("~s Handshake, CertificateVerify",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_verify_1_3, CertificateVerify)]),
{Header, Message}.
+
parse_cipher_suites([_|_] = Ciphers) ->
[format_cipher(C) || C <- Ciphers].
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 499ba108f2..d0a72ce51f 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -25,6 +25,7 @@
-module(ssl_record).
-include("ssl_record.hrl").
+-include("ssl_connection.hrl").
-include("ssl_internal.hrl").
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
@@ -124,12 +125,14 @@ activate_pending_connection_state(#{current_write := Current,
%% Description: Activates the next encyrption state (e.g. handshake
%% encryption).
%%--------------------------------------------------------------------
-step_encryption_state(#{pending_read := PendingRead,
- pending_write := PendingWrite} = States) ->
+step_encryption_state(#state{connection_states =
+ #{pending_read := PendingRead,
+ pending_write := PendingWrite} = ConnStates} = State) ->
NewRead = PendingRead#{sequence_number => 0},
NewWrite = PendingWrite#{sequence_number => 0},
- States#{current_read => NewRead,
- current_write => NewWrite}.
+ State#state{connection_states =
+ ConnStates#{current_read => NewRead,
+ current_write => NewWrite}}.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
index a20499972b..c88ec5021c 100644
--- a/lib/ssl/src/tls_connection_1_3.erl
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -135,32 +135,8 @@ start(internal,
end.
-negotiated(internal,
- Map,
- #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, _Module) ->
- Env = #{connection_states => ConnectionStates0,
- session_id => SessionId,
- own_certificate => OwnCert,
- cert_db => CertDbHandle,
- cert_db_ref => CertDbRef,
- ssl_options => SslOpts,
- key_share => KeyShare,
- tls_handshake_history => HHistory0,
- transport_cb => Transport,
- socket => Socket,
- private_key => CertPrivateKey},
- case tls_handshake_1_3:do_negotiated(Map, Env) of
+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 ->
@@ -187,4 +163,5 @@ update_state(#state{connection_states = ConnectionStates0,
pending_write => PendingWrite#{security_parameters => SecParamsW}},
State#state{connection_states = ConnectionStates,
key_share = KeyShare,
- session = Session#session{session_id = SessionId}}.
+ session = Session#session{session_id = SessionId},
+ negotiated_version = {3,4}}.
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 670c4d424d..e04242410e 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -28,6 +28,7 @@
-include("tls_handshake_1_3.hrl").
-include("ssl_alert.hrl").
-include("ssl_cipher.hrl").
+-include("ssl_connection.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -115,6 +116,12 @@ encode_handshake(#certificate_1_3{
EncContext = encode_cert_req_context(Context),
EncEntries = encode_cert_entries(Entries),
{?CERTIFICATE, <<EncContext/binary, EncEntries/binary>>};
+encode_handshake(#certificate_verify_1_3{
+ algorithm = Algorithm,
+ signature = Signature}) ->
+ EncAlgo = encode_algorithm(Algorithm),
+ EncSign = encode_signature(Signature),
+ {?CERTIFICATE_VERIFY, <<EncAlgo/binary, EncSign/binary>>};
encode_handshake(#encrypted_extensions{extensions = Exts})->
{?ENCRYPTED_EXTENSIONS, encode_extensions(Exts)};
encode_handshake(#new_session_ticket{
@@ -164,6 +171,11 @@ decode_handshake(?CERTIFICATE, <<?BYTE(CSize), Context:CSize/binary,
certificate_request_context = Context,
certificate_list = CertList
};
+decode_handshake(?CERTIFICATE_VERIFY, <<?UINT16(EncAlgo), ?UINT16(Size), Signature:Size/binary>>) ->
+ Algorithm = ssl_cipher:signature_scheme(EncAlgo),
+ #certificate_verify_1_3{
+ algorithm = Algorithm,
+ signature = Signature};
decode_handshake(?ENCRYPTED_EXTENSIONS, <<?UINT16(Size), EncExts:Size/binary>>) ->
#encrypted_extensions{
extensions = decode_extensions(EncExts, encrypted_extensions)
@@ -208,6 +220,14 @@ encode_cert_entries([#certificate_entry{data = Data,
encode_cert_entries(Rest,
[<<?UINT24(DSize), Data/binary, ?UINT16(ExtSize), BinExts/binary>> | Acc]).
+encode_algorithm(Algo) ->
+ Scheme = ssl_cipher:signature_scheme(Algo),
+ <<?UINT16(Scheme)>>.
+
+encode_signature(Signature) ->
+ Size = byte_size(Signature),
+ <<?UINT16(Size), Signature/binary>>.
+
decode_cert_entries(Entries) ->
decode_cert_entries(Entries, []).
@@ -362,17 +382,19 @@ do_negotiated(#{client_share := ClientKey,
group := SelectedGroup,
sign_alg := SignatureScheme
} = Map,
- #{connection_states := ConnectionStates0,
- session_id := SessionId,
- own_certificate := OwnCert,
- cert_db := CertDbHandle,
- cert_db_ref := CertDbRef,
- ssl_options := SslOpts,
- key_share := KeyShare,
- tls_handshake_history := HHistory0,
- transport_cb := Transport,
- socket := Socket,
- private_key := CertPrivateKey}) ->
+ #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
@@ -380,46 +402,35 @@ do_negotiated(#{client_share := ClientKey,
%% Extensions: supported_versions, key_share, (pre_shared_key)
ServerHello = server_hello(SessionId, KeyShare, ConnectionStates0, Map),
- %% Update handshake_history (done in encode!)
- %% Encode handshake
- {BinMsg, ConnectionStates1, HHistory1} =
- tls_connection:encode_handshake(ServerHello, {3,4}, ConnectionStates0, HHistory0),
- %% Send server_hello
- tls_connection:send(Transport, Socket, BinMsg),
- log_handshake(SslOpts, ServerHello),
- log_tls_record(SslOpts, BinMsg),
-
- %% ConnectionStates2 = calculate_security_parameters(ClientKey, SelectedGroup, KeyShare,
- %% HHistory1, ConnectionStates1),
+ {State1, _} = tls_connection:send_handshake(ServerHello, State0),
+
{HandshakeSecret, ReadKey, ReadIV, WriteKey, WriteIV} =
- calculate_security_parameters(ClientKey, SelectedGroup, KeyShare,
- HHistory1, ConnectionStates1),
- ConnectionStates2 =
- update_pending_connection_states(ConnectionStates1, HandshakeSecret,
+ calculate_security_parameters(ClientKey, SelectedGroup, KeyShare, State1),
+
+ State2 =
+ update_pending_connection_states(State1, HandshakeSecret,
ReadKey, ReadIV, WriteKey, WriteIV),
- ConnectionStates3 =
- ssl_record:step_encryption_state(ConnectionStates2),
+
+ State3 = ssl_record:step_encryption_state(State2),
%% Create Certificate
Certificate = certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, server),
%% Encode Certificate
- {_, _ConnectionStates4, HHistory2} =
- tls_connection:encode_handshake(Certificate, {3,4}, ConnectionStates3, HHistory1),
- %% log_handshake(SslOpts, Certificate),
+ State4 = tls_connection:queue_handshake(Certificate, State3),
%% Create CertificateVerify
- {Messages, _} = HHistory2,
+ #state{handshake_env =
+ #handshake_env{tls_handshake_history = {Messages, _}}} = State4,
%% Use selected signature_alg from here, HKDF only used for key_schedule
CertificateVerify =
tls_handshake_1_3:certificate_verify(OwnCert, CertPrivateKey, SignatureScheme,
Messages, server),
- io:format("### CertificateVerify: ~p~n", [CertificateVerify]),
%% Encode CertificateVerify
-
%% Send Certificate, CertifricateVerify
+ {_State5, _} = tls_connection:send_handshake(CertificateVerify, State4),
%% Send finished
@@ -454,7 +465,11 @@ log_tls_record(SslOpts, BinMsg) ->
ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}).
-calculate_security_parameters(ClientKey, SelectedGroup, KeyShare, HHistory, ConnectionStates) ->
+calculate_security_parameters(ClientKey, SelectedGroup, KeyShare,
+ #state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = HHistory}}) ->
#{security_parameters := SecParamsR} =
ssl_record:pending_connection_state(ConnectionStates, read),
#security_parameters{prf_algorithm = HKDFAlgo,
@@ -527,13 +542,14 @@ calculate_shared_secret(OthersKey, MyKey = #'ECPrivateKey'{}, _Group)
public_key:compute_key(Point, MyKey).
-update_pending_connection_states(CS = #{pending_read := PendingRead0,
- pending_write := PendingWrite0},
+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),
- CS#{pending_read => PendingRead,
- pending_write => PendingWrite}.
+ State#state{connection_states = CS#{pending_read => PendingRead,
+ pending_write => PendingWrite}}.
update_connection_state(ConnectionState = #{security_parameters := SecurityParameters0},
HandshakeSecret, Key, IV) ->
diff --git a/lib/ssl/test/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
index e4c4c89021..38a4b7fb11 100644
--- a/lib/ssl/test/property_test/ssl_eqc_handshake.erl
+++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
@@ -96,7 +96,7 @@ tls_msg(?'TLS_v1.3'= Version) ->
encrypted_extensions(),
certificate_1_3(),
%%certificate_request_1_3,
- %%certificate_verify()
+ certificate_verify_1_3(),
finished(),
key_update()
]);
@@ -163,6 +163,13 @@ certificate_1_3() ->
certificate_list = certificate_entries(Certs, [])
}).
+certificate_verify_1_3() ->
+ ?LET(Certs, certificate_chain(),
+ #certificate_verify_1_3{
+ algorithm = sig_scheme(),
+ signature = signature()
+ }).
+
finished() ->
?LET(Size, digest_size(),
#finished{verify_data = crypto:strong_rand_bytes(Size)}).
@@ -511,6 +518,42 @@ sig_scheme_list() ->
ecdsa_sha1]
]).
+sig_scheme() ->
+ oneof([rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1]).
+
+signature() ->
+ <<44,119,215,137,54,84,156,26,121,212,64,173,189,226,
+ 191,46,76,89,204,2,78,79,163,228,90,21,89,179,4,198,
+ 109,14,52,26,230,22,56,8,170,129,86,0,7,132,245,81,
+ 181,131,62,70,79,167,112,85,14,171,175,162,110,29,
+ 212,198,45,188,83,176,251,197,224,104,95,74,89,59,
+ 26,60,63,79,238,196,137,65,23,199,127,145,176,184,
+ 216,3,48,116,172,106,97,83,227,172,246,137,91,79,
+ 173,119,169,60,67,1,177,117,9,93,38,86,232,253,73,
+ 140,17,147,130,110,136,245,73,10,91,70,105,53,225,
+ 158,107,60,190,30,14,26,92,147,221,60,117,104,53,70,
+ 142,204,7,131,11,183,192,120,246,243,68,99,147,183,
+ 49,149,48,188,8,218,17,150,220,121,2,99,194,140,35,
+ 13,249,201,37,216,68,45,87,58,18,10,106,11,132,241,
+ 71,170,225,216,197,212,29,107,36,80,189,184,202,56,
+ 86,213,45,70,34,74,71,48,137,79,212,194,172,151,57,
+ 57,30,126,24,157,198,101,220,84,162,89,105,185,245,
+ 76,105,212,176,25,6,148,49,194,106,253,241,212,200,
+ 37,154,227,53,49,216,72,82,163>>.
+
client_hello_versions(?'TLS_v1.3') ->
?LET(SupportedVersions,
oneof([[{3,4}],
@@ -739,10 +782,13 @@ key_share_entry_list(N, Pool, Acc) ->
key_exchange = P},
key_share_entry_list(N - 1, Pool -- [G], [KeyShareEntry|Acc]).
+%% TODO: fix curve generation
generate_public_key(Group)
when Group =:= secp256r1 orelse
Group =:= secp384r1 orelse
- Group =:= secp521r1 ->
+ Group =:= secp521r1 orelse
+ Group =:= x448 orelse
+ Group =:= x25519 ->
#'ECPrivateKey'{publicKey = PublicKey} =
public_key:generate_key({namedCurve, secp256r1}),
PublicKey;