From 9cdc4cb22a4465709e347c07f240fd6e3a74b490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Dimitrov?= Date: Fri, 11 Jan 2019 16:45:51 +0100 Subject: ssl: Encode/decode CertificateVerify Implement encoding/decoding of CertificateVerify. Update property tests with CertificateVerify. Refactor state handling function: 'do_negotiated'. Change-Id: Ifa066076960120717ddb472dc45fcc7a16a517d0 --- lib/ssl/src/ssl_logger.erl | 12 +++ lib/ssl/src/ssl_record.erl | 11 ++- lib/ssl/src/tls_connection_1_3.erl | 31 +------- lib/ssl/src/tls_handshake_1_3.erl | 94 ++++++++++++++---------- lib/ssl/test/property_test/ssl_eqc_handshake.erl | 50 ++++++++++++- 5 files changed, 126 insertions(+), 72 deletions(-) (limited to 'lib/ssl') 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, <>}; +encode_handshake(#certificate_verify_1_3{ + algorithm = Algorithm, + signature = Signature}) -> + EncAlgo = encode_algorithm(Algorithm), + EncSign = encode_signature(Signature), + {?CERTIFICATE_VERIFY, <>}; encode_handshake(#encrypted_extensions{extensions = Exts})-> {?ENCRYPTED_EXTENSIONS, encode_extensions(Exts)}; encode_handshake(#new_session_ticket{ @@ -164,6 +171,11 @@ decode_handshake(?CERTIFICATE, <>) -> + Algorithm = ssl_cipher:signature_scheme(EncAlgo), + #certificate_verify_1_3{ + algorithm = Algorithm, + signature = Signature}; decode_handshake(?ENCRYPTED_EXTENSIONS, <>) -> #encrypted_extensions{ extensions = decode_extensions(EncExts, encrypted_extensions) @@ -208,6 +220,14 @@ encode_cert_entries([#certificate_entry{data = Data, encode_cert_entries(Rest, [<> | Acc]). +encode_algorithm(Algo) -> + Scheme = ssl_cipher:signature_scheme(Algo), + <>. + +encode_signature(Signature) -> + Size = byte_size(Signature), + <>. + 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; -- cgit v1.2.3