aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src/ssl_handshake.erl
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2016-05-31 10:56:10 +0200
committerIngela Anderton Andin <[email protected]>2016-05-31 10:56:10 +0200
commit962b25f3b2879a48a8cd0596ffad862beb82d4d9 (patch)
treed6c1b9bcb667e7f0134d0002c3406190ce3b8584 /lib/ssl/src/ssl_handshake.erl
parent1a212675c4217bbedfab1e181a88b2fbe4cfa9c4 (diff)
parentd56242c69f84d7612aebd045255c41d85cbb1794 (diff)
downloadotp-962b25f3b2879a48a8cd0596ffad862beb82d4d9.tar.gz
otp-962b25f3b2879a48a8cd0596ffad862beb82d4d9.tar.bz2
otp-962b25f3b2879a48a8cd0596ffad862beb82d4d9.zip
Merge branch 'binarin/better-ssl-diagnostics/PR-1060/ERL-774/OTP-13632'
* binarin/better-ssl-diagnostics/PR-1060/ERL-774/OTP-13632: ssl: Remove error logger reports ssl: Better error handling of keys rejected by crypto Improve SSL diagnostics
Diffstat (limited to 'lib/ssl/src/ssl_handshake.erl')
-rw-r--r--lib/ssl/src/ssl_handshake.erl101
1 files changed, 57 insertions, 44 deletions
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 598d4e4112..0787e151c0 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -167,7 +167,7 @@ certificate(OwnCert, CertDbHandle, CertDbRef, server) ->
{ok, _, Chain} ->
#certificate{asn1_certificates = Chain};
{error, _} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR)
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, server_has_no_suitable_certificates)
end.
%%--------------------------------------------------------------------
@@ -195,7 +195,7 @@ client_certificate_verify(OwnCert, MasterSecret, Version,
PrivateKey, {Handshake, _}) ->
case public_key:pkix_is_fixed_dh_cert(OwnCert) of
true ->
- ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE);
+ ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE, fixed_diffie_hellman_prohibited);
false ->
Hashes =
calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
@@ -353,7 +353,7 @@ verify_server_key(#server_key_params{params_bin = EncParams,
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
certificate_verify(_, _, _, undefined, _, _) ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, invalid_certificate_verify_message);
certificate_verify(Signature, PublicKeyInfo, Version,
HashSign = {HashAlgo, _}, MasterSecret, {_, Handshake}) ->
@@ -417,7 +417,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
catch
error:_ ->
%% ASN-1 decode of certificate somehow failed
- ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN)
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, failed_to_decode_certificate)
end.
%%--------------------------------------------------------------------
@@ -605,7 +605,7 @@ select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, KeyExAlgo,
false
end, HashSigns) of
[] ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm);
[HashSign | _] ->
HashSign
end;
@@ -664,11 +664,8 @@ master_secret(RecordCB, Version, #session{master_secret = Mastersecret},
try master_secret(RecordCB, Version, Mastersecret, SecParams,
ConnectionStates, Role)
catch
- exit:Reason ->
- Report = io_lib:format("Key calculation failed due to ~p",
- [Reason]),
- error_logger:error_report(Report),
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+ exit:_ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, key_calculation_failure)
end;
master_secret(RecordCB, Version, PremasterSecret, ConnectionStates, Role) ->
@@ -683,11 +680,8 @@ master_secret(RecordCB, Version, PremasterSecret, ConnectionStates, Role) ->
ClientRandom, ServerRandom),
SecParams, ConnectionStates, Role)
catch
- exit:Reason ->
- Report = io_lib:format("Master secret calculation failed"
- " due to ~p", [Reason]),
- error_logger:error_report(Report),
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+ exit:_ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, master_secret_calculation_failure)
end.
%%-------------Encode/Decode --------------------------------
@@ -958,8 +952,8 @@ decode_handshake(_Version, ?CLIENT_KEY_EXCHANGE, PKEPMS) ->
#client_key_exchange{exchange_keys = PKEPMS};
decode_handshake(_Version, ?FINISHED, VerifyData) ->
#finished{verify_data = VerifyData};
-decode_handshake(_, _, _) ->
- throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
+decode_handshake(_, Message, _) ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {unknown_or_malformed_handshake, Message})).
%%--------------------------------------------------------------------
-spec decode_hello_extensions({client, binary()} | binary()) -> #hello_extensions{}.
@@ -1031,8 +1025,8 @@ dec_server_key(<<?UINT16(NLen), N:NLen/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
-dec_server_key(_, _, _) ->
- throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
+dec_server_key(_, KeyExchange, _) ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {unknown_or_malformed_key_exchange, KeyExchange})).
%%--------------------------------------------------------------------
-spec decode_suites('2_bytes'|'3_bytes', binary()) -> list().
@@ -1253,8 +1247,12 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
Protocol ->
{ConnectionStates, npn, Protocol}
end;
- _ -> %% {error, _Reason} or a list of 0/2+ protocols.
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+ {error, Reason} ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
+ [] ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, no_protocols_in_server_hello);
+ [_|_] ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, too_many_protocols_in_server_hello)
end.
select_version(RecordCB, ClientVersion, Versions) ->
@@ -1316,14 +1314,14 @@ handle_renegotiation_info(_RecordCB, client, #renegotiation_info{renegotiated_co
true ->
{ok, ConnectionStates};
false ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, client_renegotiation)
end;
handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_connection = ClientVerify},
ConnectionStates, true, _, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv});
false ->
CS = ssl_record:current_connection_state(ConnectionStates, read),
Data = CS#connection_state.client_verify_data,
@@ -1331,7 +1329,7 @@ handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_co
true ->
{ok, ConnectionStates};
false ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, server_renegotiation)
end
end;
@@ -1341,7 +1339,7 @@ handle_renegotiation_info(RecordCB, client, undefined, ConnectionStates, true, S
handle_renegotiation_info(RecordCB, server, undefined, ConnectionStates, true, SecureRenegotation, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv});
false ->
handle_renegotiation_info(RecordCB, ConnectionStates, SecureRenegotation)
end.
@@ -1350,7 +1348,7 @@ handle_renegotiation_info(_RecordCB, ConnectionStates, SecureRenegotation) ->
CS = ssl_record:current_connection_state(ConnectionStates, read),
case {SecureRenegotation, CS#connection_state.secure_renegotiation} of
{_, true} ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, already_secure);
{true, false} ->
?ALERT_REC(?FATAL, ?NO_RENEGOTIATION);
{false, false} ->
@@ -1523,8 +1521,8 @@ path_validation_alert({bad_cert, selfsigned_peer}) ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
path_validation_alert({bad_cert, unknown_ca}) ->
?ALERT_REC(?FATAL, ?UNKNOWN_CA);
-path_validation_alert(_) ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE).
+path_validation_alert(Reason) ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason).
encrypted_premaster_secret(Secret, RSAPublicKey) ->
try
@@ -1533,18 +1531,27 @@ encrypted_premaster_secret(Secret, RSAPublicKey) ->
rsa_pkcs1_padding}]),
#encrypted_premaster_secret{premaster_secret = PreMasterSecret}
catch
- _:_->
- throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE))
+ _:_->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, premaster_encryption_failed))
end.
-digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 ->
+digitally_signed(Version, Hashes, HashAlgo, PrivateKey) ->
+ try do_digitally_signed(Version, Hashes, HashAlgo, PrivateKey) of
+ Signature ->
+ Signature
+ catch
+ error:badkey->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, bad_key(PrivateKey)))
+ end.
+
+do_digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 ->
public_key:sign({digest, Hash}, HashAlgo, Key);
-digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
+do_digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
public_key:sign({digest, Hash}, HashAlgo, Key);
-digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
+do_digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
[{rsa_pad, rsa_pkcs1_padding}]);
-digitally_signed(_Version, Hash, HashAlgo, Key) ->
+do_digitally_signed(_Version, Hash, HashAlgo, Key) ->
public_key:sign({digest, Hash}, HashAlgo, Key).
calc_certificate_verify({3, 0}, HashAlgo, MasterSecret, Handshake) ->
@@ -1751,12 +1758,12 @@ dec_client_key(PKEPMS, ?KEY_EXCHANGE_RSA, {3, 0}) ->
dec_client_key(<<?UINT16(_), PKEPMS/binary>>, ?KEY_EXCHANGE_RSA, _) ->
#encrypted_premaster_secret{premaster_secret = PKEPMS};
dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
- throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE, empty_dh_public));
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
#client_diffie_hellman_public{dh_public = DH_Y};
dec_client_key(<<>>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
- throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE, empty_dh_public));
dec_client_key(<<?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
#client_ec_diffie_hellman_public{dh_public = DH_Y};
@@ -1800,7 +1807,7 @@ dec_server_key_signature(Params, <<?UINT16(0)>>, _) ->
dec_server_key_signature(Params, <<?UINT16(Len), Signature:Len/binary>>, _) ->
{Params, undefined, Signature};
dec_server_key_signature(_, _, _) ->
- throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, failed_to_decrypt_server_key_sign)).
dec_hello_extensions(<<>>, Acc) ->
Acc;
@@ -1955,8 +1962,8 @@ key_exchange_alg(_) ->
%%-------------Extension handling --------------------------------
%% Receive protocols, choose one from the list, return it.
-handle_alpn_extension(_, {error, _Reason}) ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
+handle_alpn_extension(_, {error, Reason}) ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
handle_alpn_extension([], _) ->
?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL);
handle_alpn_extension([ServerProtocol|Tail], ClientProtocols) ->
@@ -1976,7 +1983,7 @@ handle_next_protocol(#next_protocol_negotiation{} = NextProtocols,
true ->
select_next_protocol(decode_next_protocols(NextProtocols), NextProtocolSelector);
false ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE) % unexpected next protocol extension
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_next_protocol_extension)
end.
@@ -1996,17 +2003,17 @@ handle_next_protocol_on_server(#next_protocol_negotiation{extension_data = <<>>}
Protocols;
handle_next_protocol_on_server(_Hello, _Renegotiation, _SSLOpts) ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE). % unexpected next protocol extension
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, unexpected_next_protocol_extension).
next_protocol_extension_allowed(NextProtocolSelector, Renegotiating) ->
NextProtocolSelector =/= undefined andalso not Renegotiating.
-select_next_protocol({error, _Reason}, _NextProtocolSelector) ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
+select_next_protocol({error, Reason}, _NextProtocolSelector) ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
select_next_protocol(Protocols, NextProtocolSelector) ->
case NextProtocolSelector(Protocols) of
?NO_PROTOCOL ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, no_next_protocol);
Protocol when is_binary(Protocol) ->
Protocol
end.
@@ -2169,3 +2176,9 @@ is_acceptable_hash_sign(_,_,_,_) ->
is_acceptable_hash_sign(Algos, SupportedHashSigns) ->
lists:member(Algos, SupportedHashSigns).
+bad_key(#'DSAPrivateKey'{}) ->
+ unacceptable_dsa_key;
+bad_key(#'RSAPrivateKey'{}) ->
+ unacceptable_rsa_key;
+bad_key(#'ECPrivateKey'{}) ->
+ unacceptable_ecdsa_key.