diff options
Diffstat (limited to 'lib/ssl/src')
-rw-r--r-- | lib/ssl/src/ssl.appup.src | 27 | ||||
-rw-r--r-- | lib/ssl/src/ssl.erl | 16 | ||||
-rw-r--r-- | lib/ssl/src/ssl_certificate.erl | 16 | ||||
-rw-r--r-- | lib/ssl/src/ssl_certificate_db.erl | 6 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 137 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 170 | ||||
-rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 134 | ||||
-rw-r--r-- | lib/ssl/src/ssl_internal.hrl | 6 | ||||
-rw-r--r-- | lib/ssl/src/ssl_record.erl | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl_ssl3.erl | 24 | ||||
-rw-r--r-- | lib/ssl/src/ssl_tls1.erl | 10 |
11 files changed, 257 insertions, 291 deletions
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 88cd73be74..f4e6b59b6d 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,32 +1,9 @@ %% -*- erlang -*- {"%VSN%", [ - {"4.0", [{restart_application, ssl}]}, - {"3.11.1", [{restart_application, ssl}]}, - {"3.11", [{restart_application, ssl}]}, - {"3.10", [{restart_application, ssl}]}, - {"3.10.1", [{restart_application, ssl}]}, - {"3.10.2", [{restart_application, ssl}]}, - {"3.10.3", [{restart_application, ssl}]}, - {"3.10.4", [{restart_application, ssl}]}, - {"3.10.5", [{restart_application, ssl}]}, - {"3.10.6", [{restart_application, ssl}]}, - {"3.10.7", [{restart_application, ssl}]}, - {"3.10.8", [{restart_application, ssl}]}, - {"3.10.9", [{restart_application, ssl}]} + {"4.0.1", [{restart_application, ssl}]} ], [ - {"4.0", [{restart_application, ssl}]}, - {"3.11.1", [{restart_application, ssl}]}, - {"3.11", [{restart_application, ssl}]}, - {"3.10", [{restart_application, ssl}]}, - {"3.10.1", [{restart_application, ssl}]}, - {"3.10.2", [{restart_application, ssl}]}, - {"3.10.3", [{restart_application, ssl}]}, - {"3.10.4", [{restart_application, ssl}]}, - {"3.10.5", [{restart_application, ssl}]}, - {"3.10.6", [{restart_application, ssl}]}, - {"3.10.8", [{restart_application, ssl}]}, - {"3.10.9", [{restart_application, ssl}]} + {"4.0.1", [{restart_application, ssl}]} ]}. diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 314bdd1aab..7e5929d708 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -621,17 +621,19 @@ handle_options(Opts0, _Role) -> ReuseSessionFun = fun(_, _, _, _) -> true end, - VerifyNoneFun = - {fun(_,{bad_cert, unknown_ca}, UserState) -> + DefaultVerifyNoneFun = + {fun(_,{bad_cert, _}, UserState) -> {valid, UserState}; - (_,{bad_cert, _} = Reason, _) -> - {fail, Reason}; (_,{extension, _}, UserState) -> {unknown, UserState}; (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> {valid, UserState} end, []}, + VerifyNoneFun = handle_option(verify_fun, Opts, DefaultVerifyNoneFun), + UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false), UserVerifyFun = handle_option(verify_fun, Opts, undefined), CaCerts = handle_option(cacerts, Opts, undefined), @@ -727,6 +729,8 @@ validate_option(verify_fun, Fun) when is_function(Fun) -> (_,{extension, _}, UserState) -> {unknown, UserState}; (_, valid, UserState) -> + {valid, UserState}; + (_, valid_peer, UserState) -> {valid, UserState} end, Fun}; validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) -> @@ -743,7 +747,7 @@ validate_option(depth, Value) when is_integer(Value), validate_option(cert, Value) when Value == undefined; is_binary(Value) -> Value; -validate_option(certfile, Value) when is_list(Value) -> +validate_option(certfile, Value) when Value == undefined; is_list(Value) -> Value; validate_option(key, undefined) -> @@ -886,7 +890,7 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) -> Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0], cipher_suites(Version, Ciphers); cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) -> - Supported = ssl_cipher:suites(Version), + Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(), case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of [] -> Supported; diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index d2ab21657c..5571fb01f6 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -57,30 +57,32 @@ trusted_cert_and_path(CertChain, CertDbRef) -> Path = [Cert | _] = lists:reverse(CertChain), OtpCert = public_key:pkix_decode_cert(Cert, otp), - IssuerID = + SignedAndIssuerID = case public_key:pkix_is_self_signed(OtpCert) of true -> {ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self), - IssuerId; + {self, IssuerId}; false -> case public_key:pkix_issuer_id(OtpCert, other) of {ok, IssuerId} -> - IssuerId; + {other, IssuerId}; {error, issuer_not_found} -> case find_issuer(OtpCert, no_candidate) of {ok, IssuerId} -> - IssuerId; + {other, IssuerId}; Other -> Other end end end, - case IssuerID of + case SignedAndIssuerID of {error, issuer_not_found} -> %% The root CA was not sent and can not be found. {unknown_ca, Path}; - {SerialNr, Issuer} -> + {self, _} when length(Path) == 1 -> + {selfsigned_peer, Path}; + {_ ,{SerialNr, Issuer}} -> case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of {ok, {BinCert,_}} -> {BinCert, Path}; @@ -130,6 +132,8 @@ validate_extension(_, {bad_cert, _} = Reason, _) -> validate_extension(_, {extension, _}, Role) -> {unknown, Role}; validate_extension(_, valid, Role) -> + {valid, Role}; +validate_extension(_, valid_peer, Role) -> {valid, Role}. %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index 39d9847e3b..2a5a7f3394 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -223,8 +223,8 @@ add_certs(Cert, Ref, CertsDb) -> TBSCertificate#'OTPTBSCertificate'.issuer), insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb) catch - error:Reason -> - Report = io_lib:format("SSL WARNING: Ignoring CA cert: ~p~n Due to decoding error:~p ~n", - [Cert, Reason]), + error:_ -> + Report = io_lib:format("SSL WARNING: Ignoring a CA cert as " + "it could not be correctly decoded.~n", []), error_logger:info_report(Report) end. diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 8230149304..1c8bbbaf06 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -34,7 +34,7 @@ -export([security_parameters/2, suite_definition/1, decipher/5, cipher/4, - suite/1, suites/1, + suite/1, suites/1, anonymous_suites/0, openssl_suite/1, openssl_suite_name/1, filter/2]). -compile(inline). @@ -75,20 +75,12 @@ cipher(?RC4, CipherState, Mac, Fragment) -> S -> S end, GenStreamCipherList = [Fragment, Mac], - - ?DBG_HEX(GenStreamCipherList), - ?DBG_HEX(State0), {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList), - ?DBG_HEX(T), {T, CipherState#cipher_state{state = State1}}; cipher(?DES, CipherState, Mac, Fragment) -> block_cipher(fun(Key, IV, T) -> crypto:des_cbc_encrypt(Key, IV, T) end, block_size(des_cbc), CipherState, Mac, Fragment); -%% cipher(?DES40, CipherState, Mac, Fragment) -> -%% block_cipher(fun(Key, IV, T) -> -%% crypto:des_cbc_encrypt(Key, IV, T) -%% end, block_size(des_cbc), CipherState, Mac, Fragment); cipher(?'3DES', CipherState, Mac, Fragment) -> block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> crypto:des3_cbc_encrypt(K1, K2, K3, IV, T) @@ -109,11 +101,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1, {PaddingLength, Padding} = get_padding(TotSz, BlockSz), L = [Fragment, Mac, PaddingLength, Padding], - ?DBG_HEX(Key), - ?DBG_HEX(IV), - ?DBG_HEX(L), T = Fun(Key, IV, L), - ?DBG_HEX(T), NextIV = next_iv(T, IV), {T, CS0#cipher_state{iv=NextIV}}. @@ -127,26 +115,29 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, decipher(?NULL, _HashSz, CipherState, Fragment, _) -> {Fragment, <<>>, CipherState}; decipher(?RC4, HashSz, CipherState, Fragment, _) -> - ?DBG_TERM(CipherState#cipher_state.key), State0 = case CipherState#cipher_state.state of undefined -> crypto:rc4_set_key(CipherState#cipher_state.key); S -> S end, - ?DBG_HEX(State0), - ?DBG_HEX(Fragment), - {State1, T} = crypto:rc4_encrypt_with_state(State0, Fragment), - ?DBG_HEX(T), - GSC = generic_stream_cipher_from_bin(T, HashSz), - #generic_stream_cipher{content=Content, mac=Mac} = GSC, - {Content, Mac, CipherState#cipher_state{state=State1}}; + try crypto:rc4_encrypt_with_state(State0, Fragment) of + {State, Text} -> + GSC = generic_stream_cipher_from_bin(Text, HashSz), + #generic_stream_cipher{content = Content, mac = Mac} = GSC, + {Content, Mac, CipherState#cipher_state{state = State}} + catch + _:_ -> + %% This is a DECRYPTION_FAILED but + %% "differentiating between bad_record_mac and decryption_failed + %% alerts may permit certain attacks against CBC mode as used in + %% TLS [CBCATT]. It is preferable to uniformly use the + %% bad_record_mac alert to hide the specific type of the error." + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + end; + decipher(?DES, HashSz, CipherState, Fragment, Version) -> block_decipher(fun(Key, IV, T) -> crypto:des_cbc_decrypt(Key, IV, T) end, CipherState, HashSz, Fragment, Version); -%% decipher(?DES40, HashSz, CipherState, Fragment, Version) -> -%% block_decipher(fun(Key, IV, T) -> -%% crypto:des_cbc_decrypt(Key, IV, T) -%% end, CipherState, HashSz, Fragment, Version); decipher(?'3DES', HashSz, CipherState, Fragment, Version) -> block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> crypto:des3_cbc_decrypt(K1, K2, K3, IV, T) @@ -164,22 +155,27 @@ decipher(?AES, HashSz, CipherState, Fragment, Version) -> block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, HashSz, Fragment, Version) -> - ?DBG_HEX(Key), - ?DBG_HEX(IV), - ?DBG_HEX(Fragment), - T = Fun(Key, IV, Fragment), - ?DBG_HEX(T), - GBC = generic_block_cipher_from_bin(T, HashSz), - case is_correct_padding(GBC, Version) of - true -> - Content = GBC#generic_block_cipher.content, - Mac = GBC#generic_block_cipher.mac, - CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, - {Content, Mac, CipherState1}; - false -> + try Fun(Key, IV, Fragment) of + Text -> + GBC = generic_block_cipher_from_bin(Text, HashSz), + case is_correct_padding(GBC, Version) of + true -> + Content = GBC#generic_block_cipher.content, + Mac = GBC#generic_block_cipher.mac, + CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)}, + {Content, Mac, CipherState1}; + false -> + ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) + end + catch + _:_ -> + %% This is a DECRYPTION_FAILED but + %% "differentiating between bad_record_mac and decryption_failed + %% alerts may permit certain attacks against CBC mode as used in + %% TLS [CBCATT]. It is preferable to uniformly use the + %% bad_record_mac alert to hide the specific type of the error." ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC) end. - %%-------------------------------------------------------------------- -spec suites(tls_version()) -> [cipher_suite()]. %% @@ -191,6 +187,19 @@ suites({3, N}) when N == 1; N == 2 -> ssl_tls1:suites(). %%-------------------------------------------------------------------- +-spec anonymous_suites() -> [cipher_suite()]. +%% +%% Description: Returns a list of the anonymous cipher suites, only supported +%% if explicitly set by user. Intended only for testing. +%%-------------------------------------------------------------------- +anonymous_suites() -> + [?TLS_DH_anon_WITH_RC4_128_MD5, + ?TLS_DH_anon_WITH_DES_CBC_SHA, + ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, + ?TLS_DH_anon_WITH_AES_128_CBC_SHA, + ?TLS_DH_anon_WITH_AES_256_CBC_SHA]. + +%%-------------------------------------------------------------------- -spec suite_definition(cipher_suite()) -> erl_cipher_suite(). %% %% Description: Return erlang cipher suite definition. @@ -235,7 +244,20 @@ suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) -> suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> {dhe_dss, aes_256_cbc, sha}; suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> - {dhe_rsa, aes_256_cbc, sha}. + {dhe_rsa, aes_256_cbc, sha}; + +%%% DH-ANON deprecated by TLS spec and not available +%%% by default, but good for testing purposes. +suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) -> + {dh_anon, rc4_128, md5}; +suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) -> + {dh_anon, des_cbc, sha}; +suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) -> + {dh_anon, '3des_ede_cbc', sha}; +suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) -> + {dh_anon, aes_128_cbc, sha}; +suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> + {dh_anon, aes_256_cbc, sha}. %%-------------------------------------------------------------------- -spec suite(erl_cipher_suite()) -> cipher_suite(). @@ -266,12 +288,12 @@ suite({dhe_rsa, des_cbc, sha}) -> ?TLS_DHE_RSA_WITH_DES_CBC_SHA; suite({dhe_rsa, '3des_ede_cbc', sha}) -> ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; -%% suite({dh_anon, rc4_128, md5}) -> -%% ?TLS_DH_anon_WITH_RC4_128_MD5; -%% suite({dh_anon, des40_cbc, sha}) -> -%% ?TLS_DH_anon_WITH_DES_CBC_SHA; -%% suite({dh_anon, '3des_ede_cbc', sha}) -> -%% ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; +suite({dh_anon, rc4_128, md5}) -> + ?TLS_DH_anon_WITH_RC4_128_MD5; +suite({dh_anon, des_cbc, sha}) -> + ?TLS_DH_anon_WITH_DES_CBC_SHA; +suite({dh_anon, '3des_ede_cbc', sha}) -> + ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; %%% TSL V1.1 AES suites suite({rsa, aes_128_cbc, sha}) -> @@ -280,16 +302,16 @@ suite({dhe_dss, aes_128_cbc, sha}) -> ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; suite({dhe_rsa, aes_128_cbc, sha}) -> ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA; -%% suite({dh_anon, aes_128_cbc, sha}) -> -%% ?TLS_DH_anon_WITH_AES_128_CBC_SHA; +suite({dh_anon, aes_128_cbc, sha}) -> + ?TLS_DH_anon_WITH_AES_128_CBC_SHA; suite({rsa, aes_256_cbc, sha}) -> ?TLS_RSA_WITH_AES_256_CBC_SHA; suite({dhe_dss, aes_256_cbc, sha}) -> ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA; suite({dhe_rsa, aes_256_cbc, sha}) -> - ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA. -%% suite({dh_anon, aes_256_cbc, sha}) -> -%% ?TLS_DH_anon_WITH_AES_256_CBC_SHA. + ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; +suite({dh_anon, aes_256_cbc, sha}) -> + ?TLS_DH_anon_WITH_AES_256_CBC_SHA. %%-------------------------------------------------------------------- -spec openssl_suite(openssl_cipher_suite()) -> cipher_suite(). @@ -390,8 +412,6 @@ bulk_cipher_algorithm(null) -> %% ?IDEA; bulk_cipher_algorithm(rc4_128) -> ?RC4; -%% bulk_cipher_algorithm(des40_cbc) -> -%% ?DES40; bulk_cipher_algorithm(des_cbc) -> ?DES; bulk_cipher_algorithm('3des_ede_cbc') -> @@ -405,7 +425,6 @@ type(Cipher) when Cipher == null; ?STREAM; type(Cipher) when Cipher == idea_cbc; - Cipher == des40_cbc; Cipher == des_cbc; Cipher == '3des_ede_cbc'; Cipher == aes_128_cbc; @@ -417,8 +436,6 @@ key_material(null) -> key_material(Cipher) when Cipher == idea_cbc; Cipher == rc4_128 -> 16; -%%key_material(des40_cbc) -> -%% 5; key_material(des_cbc) -> 8; key_material('3des_ede_cbc') -> @@ -433,8 +450,7 @@ expanded_key_material(null) -> expanded_key_material(Cipher) when Cipher == idea_cbc; Cipher == rc4_128 -> 16; -expanded_key_material(Cipher) when Cipher == des_cbc; - Cipher == des40_cbc -> +expanded_key_material(Cipher) when Cipher == des_cbc -> 8; expanded_key_material('3des_ede_cbc') -> 24; @@ -445,8 +461,6 @@ expanded_key_material(Cipher) when Cipher == aes_128_cbc; effective_key_bits(null) -> 0; -%%effective_key_bits(des40_cbc) -> -%% 40; effective_key_bits(des_cbc) -> 56; effective_key_bits(Cipher) when Cipher == idea_cbc; @@ -465,7 +479,6 @@ iv_size(Cipher) -> block_size(Cipher). block_size(Cipher) when Cipher == idea_cbc; - Cipher == des40_cbc; Cipher == des_cbc; Cipher == '3des_ede_cbc' -> 8; @@ -580,5 +593,3 @@ filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) -> false -> CipherSuits -- RsaSuites end. - - diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index bd1ba6978a..ce90d22c09 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -374,7 +374,7 @@ hello(#server_hello{cipher_suite = CipherSuite, case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of {Version, NewId, ConnectionStates} -> - {KeyAlgorithm, _, _} = + {KeyAlgorithm, _, _} = ssl_cipher:suite_definition(CipherSuite), PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), @@ -512,7 +512,7 @@ certify(#certificate{} = Cert, certify(#server_key_exchange{} = KeyExchangeMsg, #state{role = client, negotiated_version = Version, key_algorithm = Alg} = State0) - when Alg == dhe_dss; Alg == dhe_rsa -> + when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon -> case handle_server_key(KeyExchangeMsg, State0) of #state{} = State1 -> {Record, State} = next_record(State1), @@ -613,25 +613,10 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl #state{negotiated_version = Version, diffie_hellman_params = #'DHParameter'{prime = P, base = G}, - diffie_hellman_keys = {_, ServerDhPrivateKey}, - role = Role, - session = Session, - connection_states = ConnectionStates0} = State0) -> - - PMpint = crypto:mpint(P), - GMpint = crypto:mpint(G), - PremasterSecret = crypto:dh_compute_key(mpint_binary(ClientPublicDhKey), - ServerDhPrivateKey, - [PMpint, GMpint]), - - case ssl_handshake:master_secret(Version, PremasterSecret, - ConnectionStates0, Role) of - {MasterSecret, ConnectionStates} -> - State1 = State0#state{session = - Session#session{master_secret - = MasterSecret}, - connection_states = ConnectionStates}, + diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) -> + case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of + #state{} = State1 -> {Record, State} = next_record(State1), next_state(cipher, Record, State); #alert{} = Alert -> @@ -653,12 +638,10 @@ cipher(#certificate_verify{signature = Signature}, public_key_info = PublicKeyInfo, negotiated_version = Version, session = #session{master_secret = MasterSecret}, - key_algorithm = Algorithm, tls_handshake_hashes = Hashes } = State0) -> case ssl_handshake:certificate_verify(Signature, PublicKeyInfo, - Version, MasterSecret, - Algorithm, Hashes) of + Version, MasterSecret, Hashes) of valid -> {Record, State} = next_record(State0), next_state(cipher, Record, State); @@ -984,15 +967,14 @@ handle_info(Msg, StateName, State) -> %% necessary cleaning up. When it returns, the gen_fsm terminates with %% Reason. The return value is ignored. %%-------------------------------------------------------------------- -terminate(_Reason, connection, #state{negotiated_version = Version, +terminate(Reason, connection, #state{negotiated_version = Version, connection_states = ConnectionStates, transport_cb = Transport, socket = Socket, send_queue = SendQueue, renegotiation = Renegotiate}) -> notify_senders(SendQueue), notify_renegotiater(Renegotiate), - {BinAlert, _} = encode_alert(?ALERT_REC(?WARNING,?CLOSE_NOTIFY), - Version, ConnectionStates), + BinAlert = terminate_alert(Reason, Version, ConnectionStates), Transport:send(Socket, BinAlert), workaround_transport_delivery_problems(Socket, Transport), Transport:close(Socket); @@ -1058,6 +1040,8 @@ init_certificates(#ssl_options{cacerts = CaCerts, end, init_certificates(Cert, CertDbRef, CacheRef, CertFile, Role). +init_certificates(undefined, CertDbRef, CacheRef, "", _) -> + {ok, CertDbRef, CacheRef, undefined}; init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) -> try @@ -1068,18 +1052,18 @@ init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) -> end; init_certificates(undefined, CertDbRef, CacheRef, CertFile, server) -> - try + try [OwnCert] = ssl_certificate:file_to_certificats(CertFile), {ok, CertDbRef, CacheRef, OwnCert} - catch - Error:Reason -> - handle_file_error(?LINE, Error, Reason, CertFile, ecertfile, - erlang:get_stacktrace()) - end; + catch + Error:Reason -> + handle_file_error(?LINE, Error, Reason, CertFile, ecertfile, + erlang:get_stacktrace()) + end; init_certificates(Cert, CertDbRef, CacheRef, _, _) -> {ok, CertDbRef, CacheRef, Cert}. -init_private_key(undefined, "", _Password, client) -> +init_private_key(undefined, "", _Password, _Client) -> undefined; init_private_key(undefined, KeyFile, Password, _) -> try @@ -1182,16 +1166,15 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, negotiated_version = Version, own_cert = OwnCert, socket = Socket, - key_algorithm = KeyAlg, private_key = PrivateKey, session = #session{master_secret = MasterSecret}, tls_handshake_hashes = Hashes0} = State) -> + case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret, - Version, KeyAlg, - PrivateKey, Hashes0) of + Version, PrivateKey, Hashes0) of #certificate_verify{} = Verified -> {BinVerified, ConnectionStates1, Hashes1} = - encode_handshake(Verified, KeyAlg, Version, + encode_handshake(Verified, Version, ConnectionStates0, Hashes0), Transport:send(Socket, BinVerified), State#state{connection_states = ConnectionStates1, @@ -1340,15 +1323,17 @@ server_hello_done(#state{transport_cb = Transport, Transport:send(Socket, BinHelloDone), State#state{connection_states = NewConnectionStates, tls_handshake_hashes = NewHashes}. - -certify_server(#state{transport_cb = Transport, - socket = Socket, - negotiated_version = Version, - connection_states = ConnectionStates, - tls_handshake_hashes = Hashes, - cert_db_ref = CertDbRef, - own_cert = OwnCert} = State) -> +certify_server(#state{key_algorithm = dh_anon} = State) -> + State; + +certify_server(#state{transport_cb = Transport, + socket = Socket, + negotiated_version = Version, + connection_states = ConnectionStates, + tls_handshake_hashes = Hashes, + cert_db_ref = CertDbRef, + own_cert = OwnCert} = State) -> case ssl_handshake:certificate(OwnCert, CertDbRef, server) of CertMsg = #certificate{} -> {BinCertMsg, NewConnectionStates, NewHashes} = @@ -1373,7 +1358,8 @@ key_exchange(#state{role = server, key_algorithm = Algo, transport_cb = Transport } = State) when Algo == dhe_dss; - Algo == dhe_rsa -> + Algo == dhe_rsa; + Algo == dh_anon -> Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), ConnectionState = @@ -1392,11 +1378,6 @@ key_exchange(#state{role = server, key_algorithm = Algo, diffie_hellman_keys = Keys, tls_handshake_hashes = Hashes1}; - -%% key_algorithm = dh_anon is not supported. Should be by default disabled -%% if support is implemented and then we need a key_exchange clause for it -%% here. - key_exchange(#state{role = client, connection_states = ConnectionStates0, key_algorithm = rsa, @@ -1419,7 +1400,8 @@ key_exchange(#state{role = client, socket = Socket, transport_cb = Transport, tls_handshake_hashes = Hashes0} = State) when Algorithm == dhe_dss; - Algorithm == dhe_rsa -> + Algorithm == dhe_rsa; + Algorithm == dh_anon -> Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}), {BinMsg, ConnectionStates1, Hashes1} = encode_handshake(Msg, Version, ConnectionStates0, Hashes0), @@ -1497,23 +1479,30 @@ save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbrev save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) -> ssl_record:set_server_verify_data(current_write, Data, ConnectionStates). +handle_server_key(#server_key_exchange{params = + #server_dh_params{dh_p = P, + dh_g = G, + dh_y = ServerPublicDhKey}, + signed_params = <<>>}, + #state{key_algorithm = dh_anon} = State) -> + dh_master_secret(P, G, ServerPublicDhKey, undefined, State); + handle_server_key( #server_key_exchange{params = #server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}, signed_params = Signed}, - #state{session = Session, negotiated_version = Version, role = Role, - public_key_info = PubKeyInfo, + #state{public_key_info = PubKeyInfo, key_algorithm = KeyAlgo, - connection_states = ConnectionStates0} = State) -> + connection_states = ConnectionStates} = State) -> PLen = size(P), GLen = size(G), YLen = size(ServerPublicDhKey), ConnectionState = - ssl_record:pending_connection_state(ConnectionStates0, read), + ssl_record:pending_connection_state(ConnectionStates, read), SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, @@ -1527,29 +1516,11 @@ handle_server_key( case verify_dh_params(Signed, Hash, PubKeyInfo) of true -> - PMpint = mpint_binary(P), - GMpint = mpint_binary(G), - Keys = {_, ClientDhPrivateKey} = - crypto:dh_generate_key([PMpint,GMpint]), - PremasterSecret = - crypto:dh_compute_key(mpint_binary(ServerPublicDhKey), - ClientDhPrivateKey, [PMpint, GMpint]), - case ssl_handshake:master_secret(Version, PremasterSecret, - ConnectionStates0, Role) of - {MasterSecret, ConnectionStates} -> - State#state{diffie_hellman_keys = Keys, - session = - Session#session{master_secret - = MasterSecret}, - connection_states = ConnectionStates}; - #alert{} = Alert -> - Alert - end; + dh_master_secret(P, G, ServerPublicDhKey, undefined, State); false -> - ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE) + ?ALERT_REC(?FATAL, ?DECRYPT_ERROR) end. - verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> case public_key:decrypt_public(Signed, PubKey, [{rsa_pad, rsa_pkcs1_padding}]) of @@ -1561,6 +1532,30 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) -> public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}). +dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> + PMpint = mpint_binary(Prime), + GMpint = mpint_binary(Base), + Keys = {_, PrivateDhKey} = + crypto:dh_generate_key([PMpint,GMpint]), + dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); + +dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, + #state{session = Session, + negotiated_version = Version, role = Role, + connection_states = ConnectionStates0} = State) -> + PremasterSecret = + crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + [PMpint, GMpint]), + case ssl_handshake:master_secret(Version, PremasterSecret, + ConnectionStates0, Role) of + {MasterSecret, ConnectionStates} -> + State#state{ + session = + Session#session{master_secret = MasterSecret}, + connection_states = ConnectionStates}; + #alert{} = Alert -> + Alert + end. cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) -> ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0), @@ -1578,20 +1573,13 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0 tls_handshake_hashes = Hashes})). encode_alert(#alert{} = Alert, Version, ConnectionStates) -> - ?DBG_TERM(Alert), ssl_record:encode_alert_record(Alert, Version, ConnectionStates). encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) -> - ?DBG_TERM(#change_cipher_spec{}), ssl_record:encode_change_cipher_spec(Version, ConnectionStates). -encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) -> - encode_handshake(HandshakeRec, null, Version, - ConnectionStates, Hashes). - -encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) -> - ?DBG_TERM(HandshakeRec), - Frag = ssl_handshake:encode_handshake(HandshakeRec, Version, SigAlg), +encode_handshake(HandshakeRec, Version, ConnectionStates0, Hashes0) -> + Frag = ssl_handshake:encode_handshake(HandshakeRec, Version), Hashes1 = ssl_handshake:update_hashes(Hashes0, Frag), {E, ConnectionStates1} = ssl_record:encode_handshake(Frag, Version, ConnectionStates0), @@ -1848,7 +1836,6 @@ next_state(StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State next_state(StateName, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} = _ChangeCipher, #state{connection_states = ConnectionStates0} = State0) -> - ?DBG_TERM(_ChangeCipher), ConnectionStates1 = ssl_record:activate_pending_connection_state(ConnectionStates0, read), {Record, State} = next_record(State0#state{connection_states = ConnectionStates1}), @@ -2179,7 +2166,7 @@ renegotiate(#state{role = server, negotiated_version = Version, connection_states = ConnectionStates0} = State0) -> HelloRequest = ssl_handshake:hello_request(), - Frag = ssl_handshake:encode_handshake(HelloRequest, Version, null), + Frag = ssl_handshake:encode_handshake(HelloRequest, Version), Hs0 = ssl_handshake:init_hashes(), {BinMsg, ConnectionStates} = ssl_record:encode_handshake(Frag, Version, ConnectionStates0), @@ -2199,6 +2186,15 @@ notify_renegotiater({true, From}) when not is_atom(From) -> notify_renegotiater(_) -> ok. +terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown -> + {BinAlert, _} = encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), + Version, ConnectionStates), + BinAlert; +terminate_alert(_, Version, ConnectionStates) -> + {BinAlert, _} = encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR), + Version, ConnectionStates), + BinAlert. + workaround_transport_delivery_problems(Socket, Transport) -> %% Standard trick to try to make sure all %% data sent to to tcp port is really sent diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 3f01be101c..7082a23fd0 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -33,11 +33,11 @@ -export([master_secret/4, client_hello/5, server_hello/4, hello/4, hello_request/0, certify/6, certificate/3, - client_certificate_verify/6, certificate_verify/6, + client_certificate_verify/5, certificate_verify/5, certificate_request/2, key_exchange/2, server_key_exchange_hash/2, finished/4, verify_connection/5, get_tls_handshake/2, - decode_client_key/3, server_hello_done/0, sig_alg/1, - encode_handshake/3, init_hashes/0, update_hashes/2, + decode_client_key/3, server_hello_done/0, + encode_handshake/2, init_hashes/0, update_hashes/2, decrypt_premaster_secret/2]). -type tls_handshake() :: #client_hello{} | #server_hello{} | @@ -237,7 +237,7 @@ certificate(OwnCert, CertDbRef, client) -> {error, _} -> %% If no suitable certificate is available, the client %% SHOULD send a certificate message containing no - %% certificates. (chapter 7.4.6. rfc 4346) + %% certificates. (chapter 7.4.6. RFC 4346) [] end, #certificate{asn1_certificates = Chain}; @@ -252,17 +252,17 @@ certificate(OwnCert, CertDbRef, server) -> %%-------------------------------------------------------------------- -spec client_certificate_verify(undefined | der_cert(), binary(), - tls_version(), key_algo(), private_key(), + tls_version(), private_key(), {{binary(), binary()},{binary(), binary()}}) -> #certificate_verify{} | ignore | #alert{}. %% %% Description: Creates a certificate_verify message, called by the client. %%-------------------------------------------------------------------- -client_certificate_verify(undefined, _, _, _, _, _) -> +client_certificate_verify(undefined, _, _, _, _) -> ignore; -client_certificate_verify(_, _, _, _, undefined, _) -> +client_certificate_verify(_, _, _, undefined, _) -> ignore; -client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm, +client_certificate_verify(OwnCert, MasterSecret, Version, PrivateKey, {Hashes0, _}) -> case public_key:pkix_is_fixed_dh_cert(OwnCert) of true -> @@ -270,33 +270,30 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm, false -> Hashes = calc_certificate_verify(Version, MasterSecret, - Algorithm, Hashes0), + alg_oid(PrivateKey), Hashes0), Signed = digitally_signed(Hashes, PrivateKey), #certificate_verify{signature = Signed} end. %%-------------------------------------------------------------------- -spec certificate_verify(binary(), public_key_info(), tls_version(), - binary(), key_algo(), - {_, {binary(), binary()}}) -> valid | #alert{}. + binary(), {_, {binary(), binary()}}) -> valid | #alert{}. %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- -certificate_verify(Signature, {_, PublicKey, _}, Version, - MasterSecret, Algorithm, {_, Hashes0}) - when Algorithm == rsa; - Algorithm == dhe_rsa -> +certificate_verify(Signature, {?'rsaEncryption'= Algorithm, PublicKey, _}, Version, + MasterSecret, {_, Hashes0}) -> Hashes = calc_certificate_verify(Version, MasterSecret, Algorithm, Hashes0), - case public_key:decrypt_public(Signature, PublicKey, + case public_key:decrypt_public(Signature, PublicKey, [{rsa_pad, rsa_pkcs1_padding}]) of Hashes -> valid; _ -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE) end; -certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version, - MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) -> +certificate_verify(Signature, {?'id-dsa' = Algorithm, PublicKey, PublicKeyParams}, Version, + MasterSecret, {_, Hashes0}) -> Hashes = calc_certificate_verify(Version, MasterSecret, Algorithm, Hashes0), case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of @@ -355,15 +352,22 @@ key_exchange(server, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _}, YLen = byte_size(PublicKey), ServerDHParams = #server_dh_params{dh_p = PBin, dh_g = GBin, dh_y = PublicKey}, - Hash = - server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary, - ServerRandom/binary, - ?UINT16(PLen), PBin/binary, - ?UINT16(GLen), GBin/binary, - ?UINT16(YLen), PublicKey/binary>>), - Signed = digitally_signed(Hash, PrivateKey), - #server_key_exchange{params = ServerDHParams, - signed_params = Signed}. + + case KeyAlgo of + dh_anon -> + #server_key_exchange{params = ServerDHParams, + signed_params = <<>>}; + _ -> + Hash = + server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary, + ServerRandom/binary, + ?UINT16(PLen), PBin/binary, + ?UINT16(GLen), GBin/binary, + ?UINT16(YLen), PublicKey/binary>>), + Signed = digitally_signed(Hash, PrivateKey), + #server_key_exchange{params = ServerDHParams, + signed_params = Signed} + end. %%-------------------------------------------------------------------- -spec master_secret(tls_version(), #session{} | binary(), #connection_states{}, @@ -424,13 +428,11 @@ finished(Version, Role, MasterSecret, {Hashes, _}) -> % use the current hashes verify_connection(Version, #finished{verify_data = Data}, Role, MasterSecret, {_, {MD5, SHA}}) -> %% use the previous hashes - ?DBG_HEX(crypto:md5_final(MD5)), - ?DBG_HEX(crypto:sha_final(SHA)), case calc_finished(Version, Role, MasterSecret, {MD5, SHA}) of Data -> verified; - _E -> - ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE) + _ -> + ?ALERT_REC(?FATAL, ?DECRYPT_ERROR) end. %%-------------------------------------------------------------------- -spec server_hello_done() -> #server_hello_done{}. @@ -441,13 +443,12 @@ server_hello_done() -> #server_hello_done{}. %%-------------------------------------------------------------------- --spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> iolist(). +-spec encode_handshake(tls_handshake(), tls_version()) -> iolist(). %% %% Description: Encode a handshake packet to binary %%-------------------------------------------------------------------- -encode_handshake(Package, Version, KeyAlg) -> - SigAlg = sig_alg(KeyAlg), - {MsgType, Bin} = enc_hs(Package, Version, SigAlg), +encode_handshake(Package, Version) -> + {MsgType, Bin} = enc_hs(Package, Version), Len = byte_size(Bin), [MsgType, ?uint24(Len), Bin]. @@ -504,11 +505,8 @@ update_hashes(Hashes, % special-case SSL2 client hello CipherSuites:CSLength/binary, ChallengeData:CDLength/binary>>); update_hashes({{MD50, SHA0}, _Prev}, Data) -> - ?DBG_HEX(Data), {MD51, SHA1} = {crypto:md5_update(MD50, Data), crypto:sha_update(SHA0, Data)}, - ?DBG_HEX(crypto:md5_final(MD51)), - ?DBG_HEX(crypto:sha_final(SHA1)), {{MD51, SHA1}, {MD50, SHA0}}. %%-------------------------------------------------------------------- @@ -522,11 +520,11 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) -> [{rsa_pad, rsa_pkcs1_padding}]) catch _:_ -> - throw(?ALERT_REC(?FATAL, ?DECRYPTION_FAILED)) + throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR)) end. %%-------------------------------------------------------------------- --spec server_key_exchange_hash(rsa | dhe_rsa| dhe_dss, binary()) -> binary(). +-spec server_key_exchange_hash(rsa | dhe_rsa| dhe_dss | dh_anon, binary()) -> binary(). %% %% Description: Calculate server key exchange hash @@ -541,21 +539,6 @@ server_key_exchange_hash(dhe_dss, Value) -> crypto:sha(Value). %%-------------------------------------------------------------------- --spec sig_alg(atom()) -> integer(). - -%% -%% Description: Translate atom representation to enum representation. -%%-------------------------------------------------------------------- -sig_alg(dh_anon) -> - ?SIGNATURE_ANONYMOUS; -sig_alg(Alg) when Alg == dhe_rsa; Alg == rsa -> - ?SIGNATURE_RSA; -sig_alg(dhe_dss) -> - ?SIGNATURE_DSA; -sig_alg(_) -> - ?NULL. - -%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length), @@ -578,6 +561,8 @@ path_validation_alert({bad_cert, unknown_critical_extension}) -> ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE); path_validation_alert({bad_cert, cert_revoked}) -> ?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED); +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(_) -> @@ -792,8 +777,7 @@ master_secret(Version, MasterSecret, #security_parameters{ ServerWriteKey, ClientIV, ServerIV} = setup_keys(Version, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS), - ?DBG_HEX(ClientWriteKey), - ?DBG_HEX(ClientIV), + ConnStates1 = ssl_record:set_master_secret(MasterSecret, ConnectionStates), ConnStates2 = ssl_record:set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret, @@ -817,8 +801,6 @@ dec_hs(?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), ?UINT16(CDLength), CipherSuites:CSLength/binary, ChallengeData:CDLength/binary>>) -> - ?DBG_HEX(CipherSuites), - ?DBG_HEX(CipherSuites), #client_hello{client_version = {Major, Minor}, random = ssl_ssl2:client_random(ChallengeData, CDLength), session_id = 0, @@ -874,6 +856,13 @@ dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) -> dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, ?UINT16(GLen), G:GLen/binary, ?UINT16(YLen), Y:YLen/binary, + ?UINT16(0)>>) -> %% May happen if key_algorithm is dh_anon + #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, + dh_y = Y}, + signed_params = <<>>}; +dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, + ?UINT16(GLen), G:GLen/binary, + ?UINT16(YLen), Y:YLen/binary, ?UINT16(Len), Sig:Len/binary>>) -> #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G, dh_y = Y}, @@ -956,14 +945,14 @@ certs_from_list(ACList) -> <<?UINT24(CertLen), Cert/binary>> end || Cert <- ACList]). -enc_hs(#hello_request{}, _Version, _) -> +enc_hs(#hello_request{}, _Version) -> {?HELLO_REQUEST, <<>>}; enc_hs(#client_hello{client_version = {Major, Minor}, random = Random, session_id = SessionID, cipher_suites = CipherSuites, compression_methods = CompMethods, - renegotiation_info = RenegotiationInfo}, _Version, _) -> + renegotiation_info = RenegotiationInfo}, _Version) -> SIDLength = byte_size(SessionID), BinCompMethods = list_to_binary(CompMethods), CmLength = byte_size(BinCompMethods), @@ -981,20 +970,20 @@ enc_hs(#server_hello{server_version = {Major, Minor}, session_id = Session_ID, cipher_suite = Cipher_suite, compression_method = Comp_method, - renegotiation_info = RenegotiationInfo}, _Version, _) -> + renegotiation_info = RenegotiationInfo}, _Version) -> SID_length = byte_size(Session_ID), Extensions = hello_extensions(RenegotiationInfo), ExtensionsBin = enc_hello_extensions(Extensions), {?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID/binary, Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>}; -enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version, _) -> +enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) -> ASN1Certs = certs_from_list(ASN1CertList), ACLen = erlang:iolist_size(ASN1Certs), {?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>}; enc_hs(#server_key_exchange{params = #server_dh_params{ dh_p = P, dh_g = G, dh_y = Y}, - signed_params = SignedParams}, _Version, _) -> + signed_params = SignedParams}, _Version) -> PLen = byte_size(P), GLen = byte_size(G), YLen = byte_size(Y), @@ -1006,21 +995,21 @@ enc_hs(#server_key_exchange{params = #server_dh_params{ }; enc_hs(#certificate_request{certificate_types = CertTypes, certificate_authorities = CertAuths}, - _Version, _) -> + _Version) -> CertTypesLen = byte_size(CertTypes), CertAuthsLen = byte_size(CertAuths), {?CERTIFICATE_REQUEST, <<?BYTE(CertTypesLen), CertTypes/binary, ?UINT16(CertAuthsLen), CertAuths/binary>> }; -enc_hs(#server_hello_done{}, _Version, _) -> +enc_hs(#server_hello_done{}, _Version) -> {?SERVER_HELLO_DONE, <<>>}; -enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version, _) -> +enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version) -> {?CLIENT_KEY_EXCHANGE, enc_cke(ExchangeKeys, Version)}; -enc_hs(#certificate_verify{signature = BinSig}, _, _) -> +enc_hs(#certificate_verify{signature = BinSig}, _) -> EncSig = enc_bin_sig(BinSig), {?CERTIFICATE_VERIFY, EncSig}; -enc_hs(#finished{verify_data = VerifyData}, _Version, _) -> +enc_hs(#finished{verify_data = VerifyData}, _Version) -> {?FINISHED, VerifyData}. enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS},{3, 0}) -> @@ -1150,7 +1139,7 @@ calc_certificate_verify({3, N}, _, Algorithm, Hashes) key_exchange_alg(rsa) -> ?KEY_EXCHANGE_RSA; key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss; - Alg == dh_dss; Alg == dh_rsa -> + Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon -> ?KEY_EXCHANGE_DIFFIE_HELLMAN; key_exchange_alg(_) -> ?NULL. @@ -1164,3 +1153,8 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) -> {unknown, UserState} -> {unknown, {SslState, UserState}} end. + +alg_oid(#'RSAPrivateKey'{}) -> + ?'rsaEncryption'; +alg_oid(#'DSAPrivateKey'{}) -> + ?'id-dsa'. diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index ddb05e70f6..4148032cb7 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -104,11 +104,11 @@ -type tls_atom_version() :: sslv3 | tlsv1. -type cache_ref() :: term(). -type certdb_ref() :: term(). --type key_algo() :: null | rsa | dhe_rsa | dhe_dss. --type enum_algo() :: integer(). +-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon. +-type oid() :: tuple(). -type public_key() :: #'RSAPublicKey'{} | integer(). -type public_key_params() :: #'Dss-Parms'{} | term(). --type public_key_info() :: {enum_algo(), public_key(), public_key_params()}. +-type public_key_info() :: {oid(), public_key(), public_key_params()}. -type der_cert() :: binary(). -type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}. -type issuer() :: tuple(). diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 803baeb09c..e7a2d8ecf1 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -649,9 +649,7 @@ cipher(Type, Version, Fragment, CS0) -> BCA} }} = hash_and_bump_seqno(CS0, Type, Version, Length, Fragment), - ?DBG_HEX(Fragment), {Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, MacHash, Fragment), - ?DBG_HEX(Ciphered), CS2 = CS1#connection_state{cipher_state=CipherS1}, {Ciphered, CS2}. diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index 1add203fb0..18c3f4ed3d 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -41,9 +41,6 @@ -spec master_secret(binary(), binary(), binary()) -> binary(). master_secret(PremasterSecret, ClientRandom, ServerRandom) -> - ?DBG_HEX(PremasterSecret), - ?DBG_HEX(ClientRandom), - ?DBG_HEX(ServerRandom), %% draft-ietf-tls-ssl-version3-00 - 6.2.2 %% key_block = %% MD5(master_secret + SHA(`A' + master_secret + @@ -55,9 +52,8 @@ master_secret(PremasterSecret, ClientRandom, ServerRandom) -> %% MD5(master_secret + SHA(`CCC' + master_secret + %% ServerHello.random + %% ClientHello.random)) + [...]; - B = generate_keyblock(PremasterSecret, ClientRandom, ServerRandom, 48), - ?DBG_HEX(B), - B. + Block = generate_keyblock(PremasterSecret, ClientRandom, ServerRandom, 48), + Block. -spec finished(client | server, binary(), {binary(), binary()}) -> binary(). @@ -79,10 +75,9 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> SHA = handshake_hash(?SHA, MasterSecret, Sender, SHAHash), <<MD5/binary, SHA/binary>>. --spec certificate_verify(key_algo(), binary(), {binary(), binary()}) -> binary(). +-spec certificate_verify(OID::tuple(), binary(), {binary(), binary()}) -> binary(). -certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash}) - when Algorithm == rsa; Algorithm == dhe_rsa -> +certificate_verify(?'rsaEncryption', MasterSecret, {MD5Hash, SHAHash}) -> %% md5_hash %% MD5(master_secret + pad_2 + %% MD5(handshake_messages + master_secret + pad_1)); @@ -94,7 +89,7 @@ certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash}) SHA = handshake_hash(?SHA, MasterSecret, undefined, SHAHash), <<MD5/binary, SHA/binary>>; -certificate_verify(dhe_dss, MasterSecret, {_, SHAHash}) -> +certificate_verify(?'id-dsa', MasterSecret, {_, SHAHash}) -> %% sha_hash %% SHA(master_secret + pad_2 + %% SHA(handshake_messages + master_secret + pad_1)); @@ -111,14 +106,11 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) -> case Method of ?NULL -> ok; _ -> - ?DBG_HEX(Mac_write_secret), - ?DBG_HEX(hash(Method, Fragment)), ok end, Mac = mac_hash(Method, Mac_write_secret, [<<?UINT64(Seq_num), ?BYTE(Type), ?UINT16(Length)>>, Fragment]), - ?DBG_HEX(Mac), Mac. -spec setup_keys(binary(), binary(), binary(), @@ -140,12 +132,6 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) -> <<ClientWriteMacSecret:HS/binary, ServerWriteMacSecret:HS/binary, ClientWriteKey:KML/binary, ServerWriteKey:KML/binary, ClientIV:IVS/binary, ServerIV:IVS/binary>> = KeyBlock, - ?DBG_HEX(ClientWriteMacSecret), - ?DBG_HEX(ServerWriteMacSecret), - ?DBG_HEX(ClientWriteKey), - ?DBG_HEX(ServerWriteKey), - ?DBG_HEX(ClientIV), - ?DBG_HEX(ServerIV), {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, ServerWriteKey, ClientIV, ServerIV}. diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index d1bc0730ba..88394b23ba 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -60,15 +60,14 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> SHA = hash_final(?SHA, SHAHash), prf(MasterSecret, finished_label(Role), [MD5, SHA], 12). --spec certificate_verify(key_algo(), {binary(), binary()}) -> binary(). +-spec certificate_verify(OID::tuple(), {binary(), binary()}) -> binary(). -certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa; - Algorithm == dhe_rsa -> +certificate_verify(?'rsaEncryption', {MD5Hash, SHAHash}) -> MD5 = hash_final(?MD5, MD5Hash), SHA = hash_final(?SHA, SHAHash), <<MD5/binary, SHA/binary>>; -certificate_verify(dhe_dss, {_, SHAHash}) -> +certificate_verify(?'id-dsa', {_, SHAHash}) -> hash_final(?SHA, SHAHash). -spec setup_keys(binary(), binary(), binary(), integer(), @@ -133,15 +132,12 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, case Method of ?NULL -> ok; _ -> - ?DBG_HEX(Mac_write_secret), - ?DBG_HEX(hash(Method, Fragment)), ok end, Mac = hmac_hash(Method, Mac_write_secret, [<<?UINT64(Seq_num), ?BYTE(Type), ?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>, Fragment]), - ?DBG_HEX(Mac), Mac. -spec suites() -> [cipher_suite()]. |