diff options
Diffstat (limited to 'lib/ssl')
-rw-r--r-- | lib/ssl/doc/src/new_ssl.xml | 19 | ||||
-rw-r--r-- | lib/ssl/src/ssl.erl | 5 | ||||
-rw-r--r-- | lib/ssl/src/ssl_certificate.erl | 8 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 477 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.hrl | 59 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 252 | ||||
-rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 67 | ||||
-rw-r--r-- | lib/ssl/src/ssl_manager.erl | 29 | ||||
-rw-r--r-- | lib/ssl/src/ssl_record.erl | 32 | ||||
-rw-r--r-- | lib/ssl/src/ssl_ssl3.erl | 71 | ||||
-rw-r--r-- | lib/ssl/src/ssl_tls1.erl | 75 | ||||
-rw-r--r-- | lib/ssl/test/ssl_basic_SUITE.erl | 535 | ||||
-rw-r--r-- | lib/ssl/test/ssl_to_openssl_SUITE.erl | 118 |
13 files changed, 914 insertions, 833 deletions
diff --git a/lib/ssl/doc/src/new_ssl.xml b/lib/ssl/doc/src/new_ssl.xml index ab6e112a35..4ffaa9d96a 100644 --- a/lib/ssl/doc/src/new_ssl.xml +++ b/lib/ssl/doc/src/new_ssl.xml @@ -88,6 +88,10 @@ extensions are not supported yet. </item> <item>Supported SSL/TLS-versions are SSL-3.0 and TLS-1.0 </item> <item>For security reasons sslv2 is not supported.</item> + <item>Ephemeral Diffie-Hellman cipher suites are supported + but not Diffie Hellman Certificates cipher suites.</item> + <item>Export cipher suites are not supported as the + U.S. lifted its export restrictions in early 2000.</item> </list> </section> @@ -148,25 +152,20 @@ <p><c>protocol() = sslv3 | tlsv1 </c></p> - <p><c>ciphers() = [ciphersuite()] | sting() (according to old API)</c></p> + <p><c>ciphers() = [ciphersuite()] | string() (according to old API)</c></p> <p><c>ciphersuite() = - {key_exchange(), cipher(), hash(), exportable()}</c></p> + {key_exchange(), cipher(), hash()}</c></p> - <p><c>key_exchange() = rsa | dh_dss | dh_rsa | dh_anon | dhe_dss - | dhe_rsa | krb5 | KeyExchange_export + <p><c>key_exchange() = rsa | dhe_dss | dhe_rsa </c></p> - <p><c>cipher() = rc4_128 | idea_cbc | des_cbc | '3des_ede_cbc' - des40_cbc | dh_dss | aes_128_cbc | aes_256_cbc | - rc2_cbc_40 | rc4_40 </c></p> + <p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc' + | aes_128_cbc | aes_256_cbc </c></p> <p> <c>hash() = md5 | sha </c></p> - <p> <c>exportable() = export | no_export | ignore - </c></p> - <p><c>ssl_imp() = new | old - default is old.</c></p> </section> diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 95cd92ee60..185a1f755a 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -718,7 +718,10 @@ emulated_options([], Inet,Emulated) -> cipher_suites(Version, []) -> ssl_cipher:suites(Version); -cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> +cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility + Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0], + cipher_suites(Version, Ciphers); +cipher_suites(Version, [{_,_,_}| _] = Ciphers0) -> Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0], cipher_suites(Version, Ciphers); cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) -> diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 686e90a70c..37d5646673 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -67,7 +67,7 @@ trusted_cert_and_path(CertChain, CertDbRef, Verify) -> %% The root CA was not sent and can not be found, we fail if verify = true not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA), Verify, {Cert, RestPath}); {{SerialNr, Issuer}, Path} -> - case ssl_certificate_db:lookup_trusted_cert(CertDbRef, + case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of {ok, {BinCert,_}} -> {BinCert, Path, []}; @@ -85,7 +85,7 @@ certificate_chain(OwnCert, CertsDbRef) -> {ok, ErlCert} = public_key:pkix_decode_cert(OwnCert, otp), certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]). -file_to_certificats(File) -> +file_to_certificats(File) -> {ok, List} = ssl_manager:cache_pem_file(File), [Bin || {cert, Bin, not_encrypted} <- List]. @@ -148,7 +148,7 @@ certificate_chain(_CertsDbRef, Chain, _SerialNr, _Issuer, true) -> {ok, lists:reverse(Chain)}; certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) -> - case ssl_certificate_db:lookup_trusted_cert(CertsDbRef, + case ssl_manager:lookup_trusted_cert(CertsDbRef, SerialNr, Issuer) of {ok, {IssuerCert, ErlCert}} -> {ok, ErlCert} = public_key:pkix_decode_cert(IssuerCert, otp), @@ -164,7 +164,7 @@ certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) -> end. find_issuer(OtpCert, PrevCandidateKey) -> - case ssl_certificate_db:issuer_candidate(PrevCandidateKey) of + case ssl_manager:issuer_candidate(PrevCandidateKey) of no_more_candidates -> {error, issuer_not_found}; {Key, {_Cert, ErlCertCandidate}} -> diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index 3d3d11b7f3..daf4ef48b7 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -48,7 +48,7 @@ %% cipher values has been updated according to <CipherSuite> %%------------------------------------------------------------------- security_parameters(CipherSuite, SecParams) -> - { _, Cipher, Hash, Exportable} = suite_definition(CipherSuite), + { _, Cipher, Hash} = suite_definition(CipherSuite), SecParams#security_parameters{ cipher_suite = CipherSuite, bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher), @@ -58,8 +58,7 @@ security_parameters(CipherSuite, SecParams) -> key_material_length = key_material(Cipher), iv_size = iv_size(Cipher), mac_algorithm = mac_algorithm(Hash), - hash_size = hash_size(Hash), - exportable = Exportable}. + hash_size = hash_size(Hash)}. %%-------------------------------------------------------------------- %% Function: cipher(Method, CipherState, Mac, Data) -> @@ -91,10 +90,10 @@ 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(?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) @@ -104,15 +103,11 @@ cipher(?AES, CipherState, Mac, Fragment) -> crypto:aes_cbc_128_encrypt(Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> crypto:aes_cbc_256_encrypt(Key, IV, T) - end, block_size(aes_128_cbc), CipherState, Mac, Fragment); + end, block_size(aes_128_cbc), CipherState, Mac, Fragment). %% cipher(?IDEA, CipherState, Mac, Fragment) -> %% block_cipher(fun(Key, IV, T) -> %% crypto:idea_cbc_encrypt(Key, IV, T) %% end, block_size(idea_cbc), CipherState, Mac, Fragment); -cipher(?RC2, CipherState, Mac, Fragment) -> - block_cipher(fun(Key, IV, T) -> - crypto:rc2_40_cbc_encrypt(Key, IV, T) - end, block_size(rc2_cbc_40), CipherState, Mac, Fragment). block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, Mac, Fragment) -> @@ -157,10 +152,10 @@ decipher(?DES, HashSz, CipherState, Fragment) -> block_decipher(fun(Key, IV, T) -> crypto:des_cbc_decrypt(Key, IV, T) end, CipherState, HashSz, Fragment); -decipher(?DES40, HashSz, CipherState, Fragment) -> - block_decipher(fun(Key, IV, T) -> - crypto:des_cbc_decrypt(Key, IV, T) - end, CipherState, HashSz, Fragment); +%% decipher(?DES40, HashSz, CipherState, Fragment) -> +%% block_decipher(fun(Key, IV, T) -> +%% crypto:des_cbc_decrypt(Key, IV, T) +%% end, CipherState, HashSz, Fragment); decipher(?'3DES', HashSz, CipherState, Fragment) -> block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) -> crypto:des3_cbc_decrypt(K1, K2, K3, IV, T) @@ -170,15 +165,11 @@ decipher(?AES, HashSz, CipherState, Fragment) -> crypto:aes_cbc_128_decrypt(Key, IV, T); (Key, IV, T) when byte_size(Key) =:= 32 -> crypto:aes_cbc_256_decrypt(Key, IV, T) - end, CipherState, HashSz, Fragment); + end, CipherState, HashSz, Fragment). %% decipher(?IDEA, HashSz, CipherState, Fragment) -> %% block_decipher(fun(Key, IV, T) -> %% crypto:idea_cbc_decrypt(Key, IV, T) %% end, CipherState, HashSz, Fragment); -decipher(?RC2, HashSz, CipherState, Fragment) -> - block_decipher(fun(Key, IV, T) -> - crypto:rc2_40_cbc_decrypt(Key, IV, T) - end, CipherState, HashSz, Fragment). block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0, HashSz, Fragment) -> @@ -209,289 +200,147 @@ suites({3, N}) when N == 1; N == 2 -> %%-------------------------------------------------------------------- %% Function: suite_definition(CipherSuite) -> -%% {KeyExchange, Cipher, Hash, Exportable} +%% {KeyExchange, Cipher, Hash} %% %% %% CipherSuite - as defined in ssl_cipher.hrl -%% KeyExchange - rsa | dh_dss | dh_rsa | dh_anon | dhe_dss | dhe_rsa -%% krb5 | *_export (old ssl) +%% KeyExchange - rsa | dh_anon | dhe_dss | dhe_rsa | kerb5 +%% %% Cipher - null | rc4_128 | idea_cbc | des_cbc | '3des_ede_cbc' -%% des40_cbc | dh_dss | aes_128_cbc | aes_256_cbc | -%% rc2_cbc_40 | rc4_40 +%% des40_cbc | aes_128_cbc | aes_256_cbc %% Hash - null | md5 | sha -%% Exportable - export | no_export | ignore(?) %% -%% Description: Returns a security parameters record where the +%% Description: Returns a security parameters tuple where the %% cipher values has been updated according to <CipherSuite> -%% Note: since idea is unsupported on the openssl version used by -%% crypto (as of OTP R12B), we've commented away the idea stuff +%% Note: Currently not supported suites are commented away. +%% They should be supported or removed in the future. %%------------------------------------------------------------------- %% TLS v1.1 suites suite_definition(?TLS_NULL_WITH_NULL_NULL) -> - {null, null, null, ignore}; -suite_definition(?TLS_RSA_WITH_NULL_MD5) -> - {rsa, null, md5, ignore}; -suite_definition(?TLS_RSA_WITH_NULL_SHA) -> - {rsa, null, sha, ignore}; -suite_definition(?TLS_RSA_WITH_RC4_128_MD5) -> % ok - {rsa, rc4_128, md5, no_export}; -suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> % ok - {rsa, rc4_128, sha, no_export}; -%% suite_definition(?TLS_RSA_WITH_IDEA_CBC_SHA) -> % unsupported -%% {rsa, idea_cbc, sha, no_export}; -suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> % ok - {rsa, des_cbc, sha, no_export}; + {null, null, null}; +%% suite_definition(?TLS_RSA_WITH_NULL_MD5) -> +%% {rsa, null, md5}; +%% suite_definition(?TLS_RSA_WITH_NULL_SHA) -> +%% {rsa, null, sha}; +suite_definition(?TLS_RSA_WITH_RC4_128_MD5) -> + {rsa, rc4_128, md5}; +suite_definition(?TLS_RSA_WITH_RC4_128_SHA) -> + {rsa, rc4_128, sha}; +%% suite_definition(?TLS_RSA_WITH_IDEA_CBC_SHA) -> +%% {rsa, idea_cbc, sha}; +suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) -> + {rsa, des_cbc, sha}; suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) -> - {rsa, '3des_ede_cbc', sha, no_export}; -suite_definition(?TLS_DH_DSS_WITH_DES_CBC_SHA) -> - {dh_dss, des_cbc, sha, no_export}; -suite_definition(?TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA) -> - {dh_dss, '3des_ede_cbc', sha, no_export}; -suite_definition(?TLS_DH_RSA_WITH_DES_CBC_SHA) -> - {dh_rsa, des_cbc, sha, no_export}; -suite_definition(?TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA) -> - {dh_rsa, '3des_ede_cbc', sha, no_export}; + {rsa, '3des_ede_cbc', sha}; suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) -> - {dhe_dss, des_cbc, sha, no_export}; + {dhe_dss, des_cbc, sha}; suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) -> - {dhe_dss, '3des_ede_cbc', sha, no_export}; + {dhe_dss, '3des_ede_cbc'}; suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> - {dhe_rsa, des_cbc, sha, no_export}; + {dhe_rsa, des_cbc, sha}; suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) -> - {dhe_rsa, '3des_ede_cbc', sha, no_export}; -suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) -> - {dh_anon, rc4_128, md5, no_export}; -suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) -> - {dh_anon, des40_cbc, sha, no_export}; -suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) -> - {dh_anon, '3des_ede_cbc', sha, no_export}; + {dhe_rsa, '3des_ede_cbc', sha}; %%% TSL V1.1 AES suites -suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) -> % ok - {rsa, aes_128_cbc, sha, ignore}; -suite_definition(?TLS_DH_DSS_WITH_AES_128_CBC_SHA) -> - {dh_dss, aes_128_cbc, sha, ignore}; -suite_definition(?TLS_DH_RSA_WITH_AES_128_CBC_SHA) -> - {dh_rsa, aes_128_cbc, sha, ignore}; +suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) -> + {rsa, aes_128_cbc, sha}; suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) -> - {dhe_dss, aes_128_cbc, sha, ignore}; + {dhe_dss, aes_128_cbc, sha}; suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) -> - {dhe_rsa, aes_128_cbc, sha, ignore}; -suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) -> - {dh_anon, aes_128_cbc, sha, ignore}; -suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) -> % ok - {rsa, aes_256_cbc, sha, ignore}; -suite_definition(?TLS_DH_DSS_WITH_AES_256_CBC_SHA) -> - {dh_dss, aes_256_cbc, sha, ignore}; -suite_definition(?TLS_DH_RSA_WITH_AES_256_CBC_SHA) -> - {dh_rsa, aes_256_cbc, sha, ignore}; + {dhe_rsa, aes_128_cbc, sha}; +suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) -> + {rsa, aes_256_cbc, sha}; suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) -> - {dhe_dss, aes_256_cbc, sha, ignore}; + {dhe_dss, aes_256_cbc, sha}; suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> - {dhe_rsa, aes_256_cbc, sha, ignore}; -suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) -> - {dh_anon, aes_256_cbc, sha, ignore}; - -%% TSL V1.1 KRB SUITES -suite_definition(?TLS_KRB5_WITH_DES_CBC_SHA) -> - {krb5, des_cbc, sha, ignore}; -suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_SHA) -> - {krb5, '3des_ede_cbc', sha, ignore}; -suite_definition(?TLS_KRB5_WITH_RC4_128_SHA) -> - {krb5, rc4_128, sha, ignore}; + {dhe_rsa, aes_256_cbc, sha}. + +%% TODO: support kerbos key exchange? +%% TSL V1.1 KRB SUITES +%% suite_definition(?TLS_KRB5_WITH_DES_CBC_SHA) -> +%% {krb5, des_cbc, sha}; +%% suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_SHA) -> +%% {krb5, '3des_ede_cbc', sha}; +%% suite_definition(?TLS_KRB5_WITH_RC4_128_SHA) -> +%% {krb5, rc4_128, sha}; %% suite_definition(?TLS_KRB5_WITH_IDEA_CBC_SHA) -> -%% {krb5, idea_cbc, sha, ignore}; -suite_definition(?TLS_KRB5_WITH_DES_CBC_MD5) -> - {krb5, des_cbc, md5, ignore}; -suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_MD5) -> - {krb5, '3des_ede_cbc', md5, ignore}; -suite_definition(?TLS_KRB5_WITH_RC4_128_MD5) -> - {krb5, rc4_128, md5, ignore}; +%% {krb5, idea_cbc, sha}; +%% suite_definition(?TLS_KRB5_WITH_DES_CBC_MD5) -> +%% {krb5, des_cbc, md5}; +%% suite_definition(?TLS_KRB5_WITH_3DES_EDE_CBC_MD5) -> +%% {krb5, '3des_ede_cbc', md5}; +%% suite_definition(?TLS_KRB5_WITH_RC4_128_MD5) -> +%% {krb5, rc4_128, md5}; %% suite_definition(?TLS_KRB5_WITH_IDEA_CBC_MD5) -> -%% {krb5, idea_cbc, md5, ignore}; - -suite_definition(?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5) -> - {rsa, rc4_56, md5, export}; -suite_definition(?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5) -> - {rsa, rc2_cbc_56, md5, export}; -suite_definition(?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA) -> - {rsa, des_cbc, sha, export}; -suite_definition(?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA) -> - {dhe_dss, des_cbc, sha, export}; -suite_definition(?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA) -> - {rsa, rc4_56, sha, export}; -suite_definition(?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA) -> - {dhe_dss, rc4_56, sha, export}; -suite_definition(?TLS_DHE_DSS_WITH_RC4_128_SHA) -> - {dhe_dss, rc4_128, sha, export}; - -%% Export suites TLS 1.0 OR SSLv3-only servers. -suite_definition(?TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA) -> - {krb5_export, des40_cbc, sha, export}; -suite_definition(?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA) -> - {krb5_export, rc2_cbc_40, sha, export}; -suite_definition(?TLS_KRB5_EXPORT_WITH_RC4_40_SHA) -> - {krb5_export, des40_cbc, sha, export}; -suite_definition(?TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5) -> - {krb5_export, des40_cbc, md5, export}; -suite_definition(?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5) -> - {krb5_export, rc2_cbc_40, md5, export}; -suite_definition(?TLS_KRB5_EXPORT_WITH_RC4_40_MD5) -> - {krb5_export, rc2_cbc_40, md5, export}; -suite_definition(?TLS_RSA_EXPORT_WITH_RC4_40_MD5) -> % ok - {rsa, rc4_40, md5, export}; -suite_definition(?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5) -> % ok - {rsa, rc2_cbc_40, md5, export}; -suite_definition(?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA) -> - {rsa, des40_cbc, sha, export}; -suite_definition(?TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA) -> - {dh_dss, des40_cbc, sha, export}; -suite_definition(?TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA) -> - {dh_rsa, des40_cbc, sha, export}; -suite_definition(?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA) -> - {dhe_dss, des40_cbc, sha, export}; -suite_definition(?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA) -> - {dhe_rsa, des40_cbc, sha, export}; -suite_definition(?TLS_DH_anon_EXPORT_WITH_RC4_40_MD5) -> - {dh_anon, rc4_40, md5, export}; -suite_definition(?TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA) -> - {dh_anon, des40_cbc, sha, export}. +%% {krb5, idea_cbc, md5}; %% TLS v1.1 suites -suite({rsa, null, md5, ignore}) -> - ?TLS_RSA_WITH_NULL_MD5; -suite({rsa, null, sha, ignore}) -> - ?TLS_RSA_WITH_NULL_SHA; -suite({rsa, rc4_128, md5, no_export}) -> +%%suite({rsa, null, md5}) -> +%% ?TLS_RSA_WITH_NULL_MD5; +%%suite({rsa, null, sha}) -> +%% ?TLS_RSA_WITH_NULL_SHA; +suite({rsa, rc4_128, md5}) -> ?TLS_RSA_WITH_RC4_128_MD5; -suite({rsa, rc4_128, sha, no_export}) -> +suite({rsa, rc4_128, sha}) -> ?TLS_RSA_WITH_RC4_128_SHA; -%% suite({rsa, idea_cbc, sha, no_export}) -> +%% suite({rsa, idea_cbc, sha}) -> %% ?TLS_RSA_WITH_IDEA_CBC_SHA; -suite({rsa, des_cbc, sha, no_export}) -> +suite({rsa, des_cbc, sha}) -> ?TLS_RSA_WITH_DES_CBC_SHA; -suite({rsa, '3des_ede_cbc', sha, no_export}) -> +suite({rsa, '3des_ede_cbc', sha}) -> ?TLS_RSA_WITH_3DES_EDE_CBC_SHA; -suite({dh_dss, des_cbc, sha, no_export}) -> - ?TLS_DH_DSS_WITH_DES_CBC_SHA; -suite({dh_dss, '3des_ede_cbc', sha, no_export}) -> - ?TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA; -suite({dh_rsa, des_cbc, sha, no_export}) -> - ?TLS_DH_RSA_WITH_DES_CBC_SHA; -suite({dh_rsa, '3des_ede_cbc', sha, no_export}) -> - ?TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA; -suite({dhe_dss, des_cbc, sha, no_export}) -> +suite({dhe_dss, des_cbc, sha}) -> ?TLS_DHE_DSS_WITH_DES_CBC_SHA; -suite({dhe_dss, '3des_ede_cbc', sha, no_export}) -> +suite({dhe_dss, '3des_ede_cbc', sha}) -> ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA; -suite({dhe_rsa, des_cbc, sha, no_export}) -> +suite({dhe_rsa, des_cbc, sha}) -> ?TLS_DHE_RSA_WITH_DES_CBC_SHA; -suite({dhe_rsa, '3des_ede_cbc', sha, no_export}) -> +suite({dhe_rsa, '3des_ede_cbc', sha}) -> ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA; -suite({dh_anon, rc4_128, md5, no_export}) -> - ?TLS_DH_anon_WITH_RC4_128_MD5; -suite({dh_anon, des40_cbc, sha, no_export}) -> - ?TLS_DH_anon_WITH_DES_CBC_SHA; -suite({dh_anon, '3des_ede_cbc', sha, no_export}) -> - ?TLS_DH_anon_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; %%% TSL V1.1 AES suites -suite({rsa, aes_128_cbc, sha, ignore}) -> +suite({rsa, aes_128_cbc, sha}) -> ?TLS_RSA_WITH_AES_128_CBC_SHA; -suite({dh_dss, aes_128_cbc, sha, ignore}) -> - ?TLS_DH_DSS_WITH_AES_128_CBC_SHA; -suite({dh_rsa, aes_128_cbc, sha, ignore}) -> - ?TLS_DH_RSA_WITH_AES_128_CBC_SHA; -suite({dhe_dss, aes_128_cbc, sha, ignore}) -> - ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA; -suite({dhe_rsa, aes_128_cbc, sha, ignore}) -> +%% 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, ignore}) -> - ?TLS_DH_anon_WITH_AES_128_CBC_SHA; -suite({rsa, aes_256_cbc, sha, ignore}) -> +%% 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({dh_dss, aes_256_cbc, sha, ignore}) -> - ?TLS_DH_DSS_WITH_AES_256_CBC_SHA; -suite({dh_rsa, aes_256_cbc, sha, ignore}) -> - ?TLS_DH_RSA_WITH_AES_256_CBC_SHA; -suite({dhe_dss, aes_256_cbc, sha, ignore}) -> +suite({dhe_dss, aes_256_cbc, sha}) -> ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA; -suite({dhe_rsa, aes_256_cbc, sha, ignore}) -> - ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA; -suite({dh_anon, aes_256_cbc, sha, ignore}) -> - ?TLS_DH_anon_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. +%% TODO: support kerbos key exchange? %% TSL V1.1 KRB SUITES -suite({krb5, des_cbc, sha, ignore}) -> - ?TLS_KRB5_WITH_DES_CBC_SHA; -suite({krb5_cbc, '3des_ede_cbc', sha, ignore}) -> - ?TLS_KRB5_WITH_3DES_EDE_CBC_SHA; -suite({krb5, rc4_128, sha, ignore}) -> - ?TLS_KRB5_WITH_RC4_128_SHA; -%% suite({krb5_cbc, idea_cbc, sha, ignore}) -> +%% suite({krb5, des_cbc, sha}) -> +%% ?TLS_KRB5_WITH_DES_CBC_SHA; +%% suite({krb5_cbc, '3des_ede_cbc', sha}) -> +%% ?TLS_KRB5_WITH_3DES_EDE_CBC_SHA; +%% suite({krb5, rc4_128, sha}) -> +%% ?TLS_KRB5_WITH_RC4_128_SHA; +%% suite({krb5_cbc, idea_cbc, sha}) -> %% ?TLS_KRB5_WITH_IDEA_CBC_SHA; -suite({krb5_cbc, md5, ignore}) -> - ?TLS_KRB5_WITH_DES_CBC_MD5; -suite({krb5_ede_cbc, des_cbc, md5, ignore}) -> - ?TLS_KRB5_WITH_3DES_EDE_CBC_MD5; -suite({krb5_128, rc4_128, md5, ignore}) -> - ?TLS_KRB5_WITH_RC4_128_MD5; -%% suite({krb5, idea_cbc, md5, ignore}) -> +%% suite({krb5_cbc, md5}) -> +%% ?TLS_KRB5_WITH_DES_CBC_MD5; +%% suite({krb5_ede_cbc, des_cbc, md5}) -> +%% ?TLS_KRB5_WITH_3DES_EDE_CBC_MD5; +%% suite({krb5_128, rc4_128, md5}) -> +%% ?TLS_KRB5_WITH_RC4_128_MD5; +%% suite({krb5, idea_cbc, md5}) -> %% ?TLS_KRB5_WITH_IDEA_CBC_MD5; -%% Export suites TLS 1.0 OR SSLv3-only servers. -suite({rsa, rc4_40, md5, export}) -> - ?TLS_RSA_EXPORT_WITH_RC4_40_MD5; -suite({rsa, rc2_cbc_40, md5, export}) -> - ?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5; -suite({rsa, des40_cbc, sha, export}) -> - ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; -suite({rsa, rc4_56, md5, export}) -> - ?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5; -suite({rsa, rc2_cbc_56, md5, export}) -> - ?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5; -suite({rsa, des_cbc, sha, export}) -> - ?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA; -suite({dhe_dss, des_cbc, sha, export}) -> - ?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA; -suite({rsa, rc4_56, sha, export}) -> - ?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA; -suite({dhe_dss, rc4_56, sha, export}) -> - ?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA; -suite({dhe_dss, rc4_128, sha, export}) -> - ?TLS_DHE_DSS_WITH_RC4_128_SHA; -suite({krb5_export, des40_cbc, sha, export}) -> - ?TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA; -suite({krb5_export, rc2_cbc_40, sha, export}) -> - ?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA; -suite({krb5_export, rc4_cbc_40, sha, export}) -> - ?TLS_KRB5_EXPORT_WITH_RC4_40_SHA; -suite({krb5_export, des40_cbc, md5, export}) -> - ?TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5; -suite({krb5_export, rc2_cbc_40, md5, export}) -> - ?TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5; -suite({krb5_export, rc4_cbc_40, md5, export}) -> - ?TLS_KRB5_EXPORT_WITH_RC4_40_MD5; -suite({rsa_export, rc4_cbc_40, md5, export}) -> - ?TLS_RSA_EXPORT_WITH_RC4_40_MD5; -suite({rsa_export, rc2_cbc_40, md5, export}) -> - ?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5; -suite({rsa_export, des40_cbc, sha, export}) -> - ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; -suite({dh_dss_export, des40_cbc, sha, export}) -> - ?TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA; -suite({dh_rsa_export, des40_cbc, sha, export}) -> - ?TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA; -suite({dhe_dss_export, des40_cbc, sha, export}) -> - ?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; -suite({dhe_rsa_export, des40_cbc, sha, export}) -> - ?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; -suite({dh_anon_export, rc4_40, md5, export}) -> - ?TLS_DH_anon_EXPORT_WITH_RC4_40_MD5; -suite({dh_anon_export, des40_cbc, sha, export}) -> - ?TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA. - - %% translate constants <-> openssl-strings %% TODO: Is there a pattern in the nameing %% that is useable to make a nicer function defention? @@ -523,36 +372,12 @@ openssl_suite("RC4-SHA") -> ?TLS_RSA_WITH_RC4_128_SHA; openssl_suite("RC4-MD5") -> ?TLS_RSA_WITH_RC4_128_MD5; -%% TODO: Do we want to support this? -openssl_suite("EXP1024-RC4-MD5") -> - ?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5; -openssl_suite("EXP1024-RC2-CBC-MD5") -> - ?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5; -openssl_suite("EXP1024-DES-CBC-SHA") -> - ?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA; -openssl_suite("EXP1024-DHE-DSS-DES-CBC-SHA") -> - ?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA; -openssl_suite("EXP1024-RC4-SHA") -> - ?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA; -openssl_suite("EXP1024-DHE-DSS-RC4-SHA") -> - ?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA; -openssl_suite("DHE-DSS-RC4-SHA") -> - ?TLS_DHE_DSS_WITH_RC4_128_SHA; - +%% openssl_suite("DHE-DSS-RC4-SHA") -> +%% ?TLS_DHE_DSS_WITH_RC4_128_SHA; openssl_suite("EDH-RSA-DES-CBC-SHA") -> ?TLS_DHE_RSA_WITH_DES_CBC_SHA; openssl_suite("DES-CBC-SHA") -> - ?TLS_RSA_WITH_DES_CBC_SHA; -openssl_suite("EXP-EDH-RSA-DES-CBC-SHA") -> - ?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA; -openssl_suite("EXP-EDH-DSS-DES-CBC-SHA") -> - ?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA; -openssl_suite("EXP-DES-CBC-SHA") -> - ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA; -openssl_suite("EXP-RC2-CBC-MD5") -> - ?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5; -openssl_suite("EXP-RC4-MD5") -> - ?TLS_RSA_EXPORT_WITH_RC4_40_MD5. + ?TLS_RSA_WITH_DES_CBC_SHA. openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) -> "DHE-RSA-AES256-SHA"; @@ -582,31 +407,9 @@ openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) -> "EDH-RSA-DES-CBC-SHA"; openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) -> "DES-CBC-SHA"; -openssl_suite_name(?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA) -> - "EXP-EDH-RSA-DES-CBC-SHA"; -openssl_suite_name(?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA) -> - "EXP-EDH-DSS-DES-CBC-SHA"; -openssl_suite_name(?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA) -> - "EXP-DES-CBC-SHA"; -openssl_suite_name(?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5) -> - "EXP-RC2-CBC-MD5"; -openssl_suite_name(?TLS_RSA_EXPORT_WITH_RC4_40_MD5) -> - "EXP-RC4-MD5"; - -openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5) -> - "EXP1024-RC4-MD5"; -openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5) -> - "EXP1024-RC2-CBC-MD5"; -openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA) -> - "EXP1024-DES-CBC-SHA"; -openssl_suite_name(?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA) -> - "EXP1024-DHE-DSS-DES-CBC-SHA"; -openssl_suite_name(?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA) -> - "EXP1024-RC4-SHA"; -openssl_suite_name(?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA) -> - "EXP1024-DHE-DSS-RC4-SHA"; -openssl_suite_name(?TLS_DHE_DSS_WITH_RC4_128_SHA) -> - "DHE-DSS-RC4-SHA"; + +%% openssl_suite_name(?TLS_DHE_DSS_WITH_RC4_128_SHA) -> +%% "DHE-DSS-RC4-SHA"; %% No oppenssl name openssl_suite_name(Cipher) -> @@ -621,15 +424,10 @@ bulk_cipher_algorithm(null) -> %% Not supported yet %% bulk_cipher_algorithm(idea_cbc) -> %% ?IDEA; -bulk_cipher_algorithm(Cipher) when Cipher == rc2_cbc_40; - Cipher == rc2_cbc_56 -> - ?RC2; -bulk_cipher_algorithm(Cipher) when Cipher == rc4_40; - Cipher == rc4_56; - Cipher == rc4_128 -> +bulk_cipher_algorithm(rc4_128) -> ?RC4; -bulk_cipher_algorithm(des40_cbc) -> - ?DES40; +%% bulk_cipher_algorithm(des40_cbc) -> +%% ?DES40; bulk_cipher_algorithm(des_cbc) -> ?DES; bulk_cipher_algorithm('3des_ede_cbc') -> @@ -639,14 +437,10 @@ bulk_cipher_algorithm(Cipher) when Cipher == aes_128_cbc; ?AES. type(Cipher) when Cipher == null; - Cipher == rc4_40; - Cipher == rc4_56; Cipher == rc4_128 -> ?STREAM; type(Cipher) when Cipher == idea_cbc; - Cipher == rc2_cbc_40; - Cipher == rc2_cbc_56; Cipher == des40_cbc; Cipher == des_cbc; Cipher == '3des_ede_cbc'; @@ -659,13 +453,8 @@ key_material(null) -> key_material(Cipher) when Cipher == idea_cbc; Cipher == rc4_128 -> 16; -key_material(Cipher) when Cipher == rc2_cbc_56; - Cipher == rc4_56 -> - 7; -key_material(Cipher) when Cipher == rc2_cbc_40; - Cipher == rc4_40; - Cipher == des40_cbc -> - 5; +%%key_material(des40_cbc) -> +%% 5; key_material(des_cbc) -> 8; key_material('3des_ede_cbc') -> @@ -678,10 +467,6 @@ key_material(aes_256_cbc) -> expanded_key_material(null) -> 0; expanded_key_material(Cipher) when Cipher == idea_cbc; - Cipher == rc2_cbc_40; - Cipher == rc2_cbc_56; - Cipher == rc4_40; - Cipher == rc4_56; Cipher == rc4_128 -> 16; expanded_key_material(Cipher) when Cipher == des_cbc; @@ -696,13 +481,9 @@ expanded_key_material(Cipher) when Cipher == aes_128_cbc; effective_key_bits(null) -> 0; -effective_key_bits(Cipher) when Cipher == rc2_cbc_40; - Cipher == rc4_40; - Cipher == des40_cbc -> - 40; -effective_key_bits(Cipher) when Cipher == rc2_cbc_56; - Cipher == rc4_56; - Cipher == des_cbc -> +%%effective_key_bits(des40_cbc) -> +%% 40; +effective_key_bits(des_cbc) -> 56; effective_key_bits(Cipher) when Cipher == idea_cbc; Cipher == rc4_128; @@ -714,16 +495,12 @@ effective_key_bits(aes_256_cbc) -> 256. iv_size(Cipher) when Cipher == null; - Cipher == rc4_40; - Cipher == rc4_56; Cipher == rc4_128 -> 0; iv_size(Cipher) -> block_size(Cipher). block_size(Cipher) when Cipher == idea_cbc; - Cipher == rc2_cbc_40; - Cipher == rc2_cbc_56; Cipher == des40_cbc; Cipher == des_cbc; Cipher == '3des_ede_cbc' -> diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index d282cbd780..80fe527f45 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -57,7 +57,7 @@ %% TLS_NULL_WITH_NULL_NULL = { 0x00,0x00 }; -define(TLS_NULL_WITH_NULL_NULL, <<?BYTE(16#00), ?BYTE(16#00)>>). -%%% The following CipherSuite definitions require that the server +%%% The following cipher suite definitions require that the server %%% provide an RSA certificate that can be used for key exchange. The %%% server may request either an RSA or a DSS signature-capable %%% certificate in the certificate request message. @@ -68,24 +68,15 @@ %% TLS_RSA_WITH_NULL_SHA = { 0x00,0x02 }; -define(TLS_RSA_WITH_NULL_SHA, <<?BYTE(16#00), ?BYTE(16#02)>>). -%% TLS_RSA_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x03 }; --define(TLS_RSA_EXPORT_WITH_RC4_40_MD5, <<?BYTE(16#00), ?BYTE(16#03)>>). - %% TLS_RSA_WITH_RC4_128_MD5 = { 0x00,0x04 }; -define(TLS_RSA_WITH_RC4_128_MD5, <<?BYTE(16#00), ?BYTE(16#04)>>). %% TLS_RSA_WITH_RC4_128_SHA = { 0x00,0x05 }; -define(TLS_RSA_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#05)>>). -%% TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x06 }; --define(TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, <<?BYTE(16#00), ?BYTE(16#06)>>). - %% TLS_RSA_WITH_IDEA_CBC_SHA = { 0x00,0x07 }; -define(TLS_RSA_WITH_IDEA_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#07)>>). -%% TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x08 }; --define(TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#08)>>). - %% TLS_RSA_WITH_DES_CBC_SHA = { 0x00,0x09 }; -define(TLS_RSA_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#09)>>). @@ -106,51 +97,33 @@ %%% provided by the client must use the parameters (group and %%% generator) described by the server. -%% TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0B }; --define(TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#0B)>>). - %% TLS_DH_DSS_WITH_DES_CBC_SHA = { 0x00,0x0C }; -define(TLS_DH_DSS_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#0C)>>). %% TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0D }; -define(TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#0D)>>). -%% TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0E }; --define(TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#0E)>>). - %% TLS_DH_RSA_WITH_DES_CBC_SHA = { 0x00,0x0F }; -define(TLS_DH_RSA_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#0F)>>). %% TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x10 }; -define(TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#10)>>). -%% TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x11 }; --define(TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#11)>>). - %% TLS_DHE_DSS_WITH_DES_CBC_SHA = { 0x00,0x12 }; -define(TLS_DHE_DSS_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#12)>>). %% TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x13 }; -define(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#13)>>). -%% TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x14 }; --define(TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#14)>>). - %% TLS_DHE_RSA_WITH_DES_CBC_SHA = { 0x00,0x15 }; -define(TLS_DHE_RSA_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#15)>>). %% TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x16 }; -define(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#16)>>). -%% TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x17 }; --define(TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, <<?BYTE(16#00), ?BYTE(16#17)>>). - %% TLS_DH_anon_WITH_RC4_128_MD5 = { 0x00,0x18 }; -define(TLS_DH_anon_WITH_RC4_128_MD5, <<?BYTE(16#00),?BYTE(16#18)>>). -%% TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x19 }; --define(TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#19)>>). - %% TLS_DH_anon_WITH_DES_CBC_SHA = { 0x00,0x1A }; -define(TLS_DH_anon_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#1A)>>). @@ -222,35 +195,7 @@ %% TLS_KRB5_WITH_IDEA_CBC_MD5 = { 0x00,0x25 }; -define(TLS_KRB5_WITH_IDEA_CBC_MD5, <<?BYTE(16#00), ?BYTE(16#25)>>). -%% TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = { 0x00,0x26 }; --define(TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, <<?BYTE(16#00), ?BYTE(16#26)>>). - -%% TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = { 0x00,0x27 }; --define(TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA, <<?BYTE(16#00), ?BYTE(16#27)>>). - -%% TLS_KRB5_EXPORT_WITH_RC4_40_SHA = { 0x00,0x28 }; --define(TLS_KRB5_EXPORT_WITH_RC4_40_SHA, <<?BYTE(16#00), ?BYTE(16#28)>>). - -%% TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = { 0x00,0x29 }; --define(TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5, <<?BYTE(16#00), ?BYTE(16#29)>>). - -%% TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x2A }; --define(TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5, <<?BYTE(16#00), ?BYTE(16#2A)>>). - -%% TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x2B }; --define(TLS_KRB5_EXPORT_WITH_RC4_40_MD5, <<?BYTE(16#00), ?BYTE(16#2B)>>). - -%% Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt - --define(TLS_RSA_EXPORT1024_WITH_RC4_56_MD5, <<?BYTE(16#00), ?BYTE(16#60)>>). --define(TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, <<?BYTE(16#00), ?BYTE(16#61)>>). --define(TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#62)>>). --define(TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#63)>>). --define(TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, <<?BYTE(16#00), ?BYTE(16#64)>>). --define(TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, <<?BYTE(16#00), ?BYTE(16#65)>>). --define(TLS_DHE_DSS_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#66)>>). - -%% RFC 5746 - Not a real ciphersuite used to signal empty "renegotiation_info" extension +%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension %% to avoid handshake failure from old servers that do not ignore %% hello extension data as they should. -define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <<?BYTE(16#00), ?BYTE(16#FF)>>). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index a4eaf03086..6912ee8983 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -39,7 +39,7 @@ -include_lib("public_key/include/public_key.hrl"). %% Internal application API --export([send/2, send/3, recv/3, connect/7, ssl_accept/6, handshake/2, +-export([send/2, recv/3, connect/7, ssl_accept/6, handshake/2, socket_control/3, close/1, shutdown/2, new_user/2, get_opts/2, set_opts/2, info/1, session_info/1, peer_certificate/1, sockname/1, peername/1, renegotiation/1]). @@ -87,7 +87,6 @@ from, % term(), where to reply bytes_to_read, % integer(), # bytes to read in passive mode user_data_buffer, % binary() -%% tls_buffer, % Keeps a lookahead one packet if available log_alert, % boolean() renegotiation, % {boolean(), From | internal | peer} recv_during_renegotiation, %boolean() @@ -108,9 +107,9 @@ %% Description: Sends data over the ssl connection %%-------------------------------------------------------------------- send(Pid, Data) -> - sync_send_all_state_event(Pid, {application_data, erlang:iolist_to_binary(Data)}, infinity). -send(Pid, Data, Timeout) -> - sync_send_all_state_event(Pid, {application_data, erlang:iolist_to_binary(Data)}, Timeout). + sync_send_all_state_event(Pid, {application_data, + erlang:iolist_to_binary(Data)}, infinity). + %%-------------------------------------------------------------------- %% Function: recv(Socket, Length Timeout) -> {ok, Data} | {error, reason} %% @@ -211,8 +210,6 @@ peername(ConnectionPid) -> %% %% Description: Same as inet:getopts/2 %%-------------------------------------------------------------------- -get_opts({ListenSocket, {_SslOpts, SockOpts}, _}, OptTags) -> - get_socket_opts(ListenSocket, OptTags, SockOpts, []); get_opts(ConnectionPid, OptTags) -> sync_send_all_state_event(ConnectionPid, {get_opts, OptTags}). %%-------------------------------------------------------------------- @@ -361,7 +358,7 @@ hello(#server_hello{cipher_suite = CipherSuite, case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of {Version, NewId, ConnectionStates1} -> - {KeyAlgorithm, _, _, _} = + {KeyAlgorithm, _, _} = ssl_cipher:suite_definition(CipherSuite), PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), @@ -425,7 +422,7 @@ abbreviated(#hello_request{}, State0) -> {Record, State} = next_record(State0), next_state(hello, Record, State); -abbreviated(Finished = #finished{verify_data = Data}, +abbreviated(#finished{verify_data = Data} = Finished, #state{role = server, negotiated_version = Version, tls_handshake_hashes = Hashes, @@ -443,7 +440,7 @@ abbreviated(Finished = #finished{verify_data = Data}, {stop, normal, State} end; -abbreviated(Finished = #finished{verify_data = Data}, +abbreviated(#finished{verify_data = Data} = Finished, #state{role = client, tls_handshake_hashes = Hashes0, session = #session{master_secret = MasterSecret}, negotiated_version = Version, @@ -507,7 +504,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 ->%%Not imp:Alg == dh_anon;Alg == krb5 -> + when Alg == dhe_dss; Alg == dhe_rsa -> case handle_server_key(KeyExchangeMsg, State0) of #state{} = State1 -> {Record, State} = next_record(State1), @@ -518,13 +515,9 @@ certify(#server_key_exchange{} = KeyExchangeMsg, {stop, normal, State0} end; -certify(#server_key_exchange{}, - State = #state{role = client, negotiated_version = Version, - key_algorithm = Alg}) - when Alg == rsa; Alg == dh_dss; Alg == dh_rsa -> - Alert = ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE), - handle_own_alert(Alert, Version, certify_server_key_exchange, State), - {stop, normal, State}; +certify(#server_key_exchange{} = Msg, + #state{role = client, key_algorithm = rsa} = State) -> + handle_unexpected_message(Msg, certify_server_keyexchange, State); certify(#certificate_request{}, State0) -> {Record, State} = next_record(State0#state{client_certificate_requested = true}), @@ -568,17 +561,12 @@ certify(#server_hello_done{}, {stop, normal, State0} end; -certify(#client_key_exchange{}, - State = #state{role = server, - client_certificate_requested = true, - ssl_options = #ssl_options{fail_if_no_peer_cert = true}, - negotiated_version = Version}) -> +certify(#client_key_exchange{} = Msg, + #state{role = server, + client_certificate_requested = true, + ssl_options = #ssl_options{fail_if_no_peer_cert = true}} = State) -> %% We expect a certificate here - Alert = ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE), - handle_own_alert(Alert, Version, - certify_server_waiting_certificate, State), - {stop, normal, State}; - + handle_unexpected_message(Msg, certify_client_key_exchange, State); certify(#client_key_exchange{exchange_keys = #encrypted_premaster_secret{premaster_secret @@ -818,10 +806,22 @@ handle_sync_event(start, From, StateName, State) -> handle_sync_event(close, _, _StateName, State) -> {stop, normal, ok, State}; -handle_sync_event({shutdown, How}, _, StateName, - #state{transport_cb = CbModule, +handle_sync_event({shutdown, How0}, _, StateName, + #state{transport_cb = Transport, + negotiated_version = Version, + connection_states = ConnectionStates, socket = Socket} = State) -> - case CbModule:shutdown(Socket, How) of + case How0 of + How when How == write; How == both -> + Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), + {BinMsg, _} = + encode_alert(Alert, Version, ConnectionStates), + Transport:send(Socket, BinMsg); + _ -> + ok + end, + + case Transport:shutdown(Socket, How0) of ok -> {reply, ok, StateName, State}; Error -> @@ -1056,16 +1056,9 @@ init_certificates(#ssl_options{cacertfile = CACertFile, case ssl_manager:connection_init(CACertFile, Role) of {ok, CertDbRef, CacheRef} -> init_certificates(CertDbRef, CacheRef, CertFile, Role); - {error, {badmatch, _Error}} -> - Report = io_lib:format("SSL: Error ~p Initializing: ~p ~n", - [_Error, CACertFile]), - error_logger:error_report(Report), - throw(ecacertfile); - {error, _Error} -> - Report = io_lib:format("SSL: Error ~p Initializing: ~p ~n", - [_Error, CACertFile]), - error_logger:error_report(Report), - throw(ecacertfile) + {error, Reason} -> + handle_file_error(?LINE, error, Reason, CACertFile, ecacertfile, + erlang:get_stacktrace()) end. init_certificates(CertDbRef, CacheRef, CertFile, client) -> @@ -1081,59 +1074,56 @@ init_certificates(CertDbRef, CacheRef, CertFile, server) -> [OwnCert] = ssl_certificate:file_to_certificats(CertFile), {ok, CertDbRef, CacheRef, OwnCert} catch - _E:{badmatch, _R={error,_}} -> - Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n", - [?LINE, _E,_R, CertFile, - erlang:get_stacktrace()]), - error_logger:error_report(Report), - throw(ecertfile); - _E:_R -> - Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n", - [?LINE, _E,_R, CertFile, - erlang:get_stacktrace()]), - error_logger:error_report(Report), - throw(ecertfile) + Error:Reason -> + handle_file_error(?LINE, Error, Reason, CertFile, ecertfile, + erlang:get_stacktrace()) end. init_private_key(undefined, "", _Password, client) -> undefined; init_private_key(undefined, KeyFile, Password, _) -> - try - {ok, List} = ssl_manager:cache_pem_file(KeyFile), - [Der] = [Der || Der = {PKey, _ , _} <- List, - PKey =:= rsa_private_key orelse - PKey =:= dsa_private_key], - {ok, Decoded} = public_key:decode_private_key(Der,Password), - Decoded - catch - _E:{badmatch, _R={error,_}} -> - Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n", - [?LINE, _E,_R, KeyFile, - erlang:get_stacktrace()]), - error_logger:error_report(Report), - throw(ekeyfile); - _E:_R -> - Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n", - [?LINE, _E,_R, KeyFile, - erlang:get_stacktrace()]), - error_logger:error_report(Report), - throw(ekeyfile) + case ssl_manager:cache_pem_file(KeyFile) of + {ok, List} -> + [Der] = [Der || Der = {PKey, _ , _} <- List, + PKey =:= rsa_private_key orelse + PKey =:= dsa_private_key], + {ok, Decoded} = public_key:decode_private_key(Der,Password), + Decoded; + {error, Reason} -> + handle_file_error(?LINE, error, Reason, KeyFile, ekeyfile, + erlang:get_stacktrace()) end; + init_private_key(PrivateKey, _, _,_) -> PrivateKey. +handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) -> + file_error(Line, Error, Reason, File, Throw, Stack); +handle_file_error(Line, Error, Reason, File, Throw, Stack) -> + file_error(Line, Error, Reason, File, Throw, Stack). + +file_error(Line, Error, Reason, File, Throw, Stack) -> + Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n", + [Line, Error, Reason, File, Stack]), + error_logger:error_report(Report), + throw(Throw). + init_diffie_hellman(_, client) -> undefined; init_diffie_hellman(undefined, _) -> ?DEFAULT_DIFFIE_HELLMAN_PARAMS; init_diffie_hellman(DHParamFile, server) -> - {ok, List} = ssl_manager:cache_pem_file(DHParamFile), - case [Der || Der = {dh_params, _ , _} <- List] of - [Der] -> - {ok, Decoded} = public_key:decode_dhparams(Der), - Decoded; - [] -> - ?DEFAULT_DIFFIE_HELLMAN_PARAMS + case ssl_manager:cache_pem_file(DHParamFile) of + {ok, List} -> + case [Der || Der = {dh_params, _ , _} <- List] of + [Der] -> + {ok, Decoded} = public_key:decode_dhparams(Der), + Decoded; + [] -> + ?DEFAULT_DIFFIE_HELLMAN_PARAMS + end; + {error, Reason} -> + handle_file_error(?LINE, error, Reason, DHParamFile, edhfile, erlang:get_stacktrace()) end. sync_send_all_state_event(FsmPid, Event) -> @@ -1191,15 +1181,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret, Version, KeyAlg, PrivateKey, Hashes0) of - ignore -> %% No key or cert or fixed_diffie_hellman - State; - Verified -> + #certificate_verify{} = Verified -> {BinVerified, ConnectionStates1, Hashes1} = encode_handshake(Verified, KeyAlg, Version, ConnectionStates0, Hashes0), Transport:send(Socket, BinVerified), State#state{connection_states = ConnectionStates1, - tls_handshake_hashes = Hashes1} + tls_handshake_hashes = Hashes1}; + ignore -> + State; + #alert{} = Alert -> + handle_own_alert(Alert, Version, certify, State) + end; verify_client_cert(#state{client_certificate_requested = false} = State) -> State. @@ -1290,7 +1283,7 @@ server_hello(ServerHello, #state{transport_cb = Transport, connection_states = ConnectionStates0, tls_handshake_hashes = Hashes0} = State) -> CipherSuite = ServerHello#server_hello.cipher_suite, - {KeyAlgorithm, _, _, _} = ssl_cipher:suite_definition(CipherSuite), + {KeyAlgorithm, _, _} = ssl_cipher:suite_definition(CipherSuite), %% Version = ServerHello#server_hello.server_version, TODO ska kontrolleras {BinMsg, ConnectionStates1, Hashes1} = encode_handshake(ServerHello, Version, ConnectionStates0, Hashes0), @@ -1333,19 +1326,8 @@ certify_server(#state{transport_cb = Transport, throw(Alert) end. -key_exchange(#state{role = server, key_algorithm = Algo} = State) - when Algo == rsa; - Algo == dh_dss; - Algo == dh_rsa -> +key_exchange(#state{role = server, key_algorithm = rsa} = State) -> State; - -%% Remove or uncomment when we decide if to support export cipher suites -%%key_exchange(#state{role = server, key_algorithm = rsa_export} = State) -> - %% TODO when the public key in the server certificate is - %% less than or equal to 512 bits in length dont send key_exchange - %% but do it otherwise -%% State; - key_exchange(#state{role = server, key_algorithm = Algo, diffie_hellman_params = Params, private_key = PrivateKey, @@ -1396,7 +1378,6 @@ key_exchange(#state{role = client, Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates1, tls_handshake_hashes = Hashes1}; - key_exchange(#state{role = client, connection_states = ConnectionStates0, key_algorithm = Algorithm, @@ -1415,9 +1396,6 @@ key_exchange(#state{role = client, State#state{connection_states = ConnectionStates1, tls_handshake_hashes = Hashes1}. -%% key_algorithm = dh_rsa | dh_dss are not supported. If we want to -%% support it we need a key_exchange clause for it here. - rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) when Algorithm == ?rsaEncryption; Algorithm == ?md2WithRSAEncryption; @@ -1429,20 +1407,6 @@ rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) rsa_key_exchange(_, _) -> throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)). -%% Uncomment if we decide to support cipher suites with key_algorithm -%% dh_rsa and dh_dss. Could also be removed if we decide support for -%% this will not be needed. Not supported by openssl! -%% dh_key_exchange(OwnCert, DhKeys, true) -> -%% case public_key:pkix_is_fixed_dh_cert(OwnCert) of -%% true -> -%% ssl_handshake:key_exchange(client, fixed_diffie_hellman); -%% false -> -%% {DhPubKey, _} = DhKeys, -%% ssl_handshake:key_exchange(client, {dh, DhPubKey}) -%% end; -%% dh_key_exchange(_, {DhPubKey, _}, false) -> -%% ssl_handshake:key_exchange(client, {dh, DhPubKey}). - request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer}, connection_states = ConnectionStates0, cert_db_ref = CertDbRef, @@ -1749,13 +1713,7 @@ header(N, Binary) -> <<?BYTE(ByteN), NewBinary/binary>> = Binary, [ByteN | header(N-1, NewBinary)]. -%% tcp_closed -send_or_reply(false, _Pid, undefined, _Data) -> - Report = io_lib:format("SSL(debug): Unexpected Data ~p ~n",[_Data]), - error_logger:error_report(Report), - erlang:error({badarg, _Pid, undefined, _Data}), - ok; -send_or_reply(false, _Pid, From, Data) -> +send_or_reply(false, _Pid, From, Data) when From =/= undefined -> gen_fsm:reply(From, Data); send_or_reply(_, Pid, _From, Data) -> send_user(Pid, Data). @@ -2016,34 +1974,19 @@ handle_alerts(_, {stop, _, _} = Stop) -> handle_alerts([Alert | Alerts], {next_state, StateName, State}) -> handle_alerts(Alerts, handle_alert(Alert, StateName, State)). -handle_alert(#alert{level = ?FATAL} = Alert, connection, - #state{from = From, user_application = {_Mon, Pid}, - log_alert = Log, - host = Host, port = Port, session = Session, - role = Role, socket_options = Opts} = State) -> - invalidate_session(Role, Host, Port, Session), - log_alert(Log, connection, Alert), - alert_user(Opts#socket_options.active, Pid, From, Alert, Role), - {stop, normal, State}; - -handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, - connection, #state{from = From, - role = Role, - user_application = {_Mon, Pid}, - socket_options = Opts} = State) -> - alert_user(Opts#socket_options.active, Pid, From, Alert, Role), - {stop, normal, State}; - handle_alert(#alert{level = ?FATAL} = Alert, StateName, #state{from = From, host = Host, port = Port, session = Session, - log_alert = Log, role = Role} = State) -> + user_application = {_Mon, Pid}, + log_alert = Log, role = Role, socket_options = Opts} = State) -> invalidate_session(Role, Host, Port, Session), log_alert(Log, StateName, Alert), - alert_user(From, Alert, Role), + alert_user(StateName, Opts, Pid, From, Alert, Role), {stop, normal, State}; + handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, - _, #state{from = From, role = Role} = State) -> - alert_user(From, Alert, Role), + StateName, #state{from = From, role = Role, + user_application = {_Mon, Pid}, socket_options = Opts} = State) -> + alert_user(StateName, Opts, Pid, From, Alert, Role), {stop, normal, State}; handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName, @@ -2066,6 +2009,11 @@ handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, Sta {Record, State} = next_record(State0), next_state(StateName, Record, State). +alert_user(connection, Opts, Pid, From, Alert, Role) -> + alert_user(Opts#socket_options.active, Pid, From, Alert, Role); +alert_user(_, _, _, From, Alert, Role) -> + alert_user(From, Alert, Role). + alert_user(From, Alert, Role) -> alert_user(false, no_pid, From, Alert, Role). @@ -2085,13 +2033,13 @@ alert_user(Active, Pid, From, Alert, Role) -> {ssl_error, sslsocket(), ReasonCode}) end. -log_alert(true, StateName, Alert) -> +log_alert(true, Info, Alert) -> Txt = ssl_alert:alert_txt(Alert), - error_logger:format("SSL: ~p: ~s\n", [StateName, Txt]); + error_logger:format("SSL: ~p: ~s\n", [Info, Txt]); log_alert(false, _, _) -> ok. -handle_own_alert(Alert, Version, StateName, +handle_own_alert(Alert, Version, Info, #state{transport_cb = Transport, socket = Socket, from = User, @@ -2106,20 +2054,18 @@ handle_own_alert(Alert, Version, StateName, ignore end, try %% Try to tell the local user - log_alert(Log, StateName, Alert), + log_alert(Log, Info, Alert), alert_user(User, Alert, Role) catch _:_ -> ok end. -handle_unexpected_message(_Msg, StateName, #state{negotiated_version = Version} = State) -> +handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) -> Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE), - handle_own_alert(Alert, Version, StateName, State), + handle_own_alert(Alert, Version, {Info, Msg}, State), {stop, normal, State}. -make_premaster_secret({MajVer, MinVer}, Alg) when Alg == rsa; - Alg == dh_dss; - Alg == dh_rsa -> +make_premaster_secret({MajVer, MinVer}, rsa) -> Rand = crypto:rand_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2), <<?BYTE(MajVer), ?BYTE(MinVer), Rand/binary>>; make_premaster_secret(_, _) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 54938e0fbc..5f3dff8894 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -282,7 +282,7 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm, PrivateKey, {Hashes0, _}) -> case public_key:pkix_is_fixed_dh_cert(OwnCert) of true -> - ignore; + ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE); false -> Hashes = calc_certificate_verify(Version, MasterSecret, @@ -302,7 +302,6 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm, certificate_verify(Signature, {_, PublicKey, _}, Version, MasterSecret, Algorithm, {_, Hashes0}) when Algorithm == rsa; - Algorithm == dh_rsa; Algorithm == dhe_rsa -> Hashes = calc_certificate_verify(Version, MasterSecret, Algorithm, Hashes0), @@ -346,13 +345,6 @@ key_exchange(client, {premaster_secret, Secret, {_, PublicKey, _}}) -> encrypted_premaster_secret(Secret, PublicKey), #client_key_exchange{exchange_keys = EncPremasterSecret}; -%% Uncomment if dh_rsa and dh_dss cipher suites should -%% be supported. -%% key_exchange(client, fixed_diffie_hellman) -> -%% #client_key_exchange{exchange_keys = -%% #client_diffie_hellman_public{ -%% dh_public = <<>> -%% }}; key_exchange(client, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) -> #client_key_exchange{ exchange_keys = #client_diffie_hellman_public{ @@ -725,12 +717,11 @@ master_secret(Version, MasterSecret, #security_parameters{ hash_size = HashSize, key_material_length = KML, expanded_key_material_length = EKML, - iv_size = IVS, - exportable = Exportable}, + iv_size = IVS}, ConnectionStates, Role) -> {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, ServerWriteKey, ClientIV, ServerIV} = - setup_keys(Version, Exportable, MasterSecret, ServerRandom, + setup_keys(Version, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS), ?DBG_HEX(ClientWriteKey), ?DBG_HEX(ClientIV), @@ -812,14 +803,7 @@ dec_hs(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, renegotiation_info = RenegotiationInfo}; dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>, _, _) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; -%% Uncomment if support for export ciphers is added. -%% dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(ModLen), Mod:ModLen/binary, -%% ?UINT16(ExpLen), Exp:ExpLen/binary, -%% ?UINT16(_), Sig/binary>>, -%% ?KEY_EXCHANGE_RSA, _) -> -%% #server_key_exchange{params = #server_rsa_params{rsa_modulus = Mod, -%% rsa_exponent = Exp}, -%% signed_params = Sig}; + dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary, ?UINT16(GLen), G:GLen/binary, ?UINT16(YLen), Y:YLen/binary, @@ -846,8 +830,7 @@ dec_hs(?CLIENT_KEY_EXCHANGE, <<?UINT16(_), PKEPMS/binary>>, PreSecret = #encrypted_premaster_secret{premaster_secret = PKEPMS}, #client_key_exchange{exchange_keys = PreSecret}; dec_hs(?CLIENT_KEY_EXCHANGE, <<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> - %% TODO: Should check whether the cert already contains a suitable DH-key (7.4.7.2) - throw(?ALERT_REC(?FATAL, implicit_public_value_encoding)); + throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE)); dec_hs(?CLIENT_KEY_EXCHANGE, <<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) -> #client_key_exchange{exchange_keys = @@ -953,17 +936,6 @@ enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version, _) -> ASN1Certs = certs_from_list(ASN1CertList), ACLen = erlang:iolist_size(ASN1Certs), {?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>}; -%% Uncomment if support for export ciphers is added. -%% enc_hs(#server_key_exchange{params = #server_rsa_params{rsa_modulus = Mod, -%% rsa_exponent = Exp}, -%% signed_params = SignedParams}, _Version, _) -> -%% ModLen = byte_size(Mod), -%% ExpLen = byte_size(Exp), -%% SignedLen = byte_size(SignedParams), -%% {?SERVER_KEY_EXCHANGE, <<?UINT16(ModLen),Mod/binary, -%% ?UINT16(ExpLen), Exp/binary, -%% ?UINT16(SignedLen), SignedParams/binary>> -%% }; enc_hs(#server_key_exchange{params = #server_dh_params{ dh_p = P, dh_g = G, dh_y = Y}, signed_params = SignedParams}, _Version, _) -> @@ -1073,16 +1045,11 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) -> certificate_types({KeyExchange, _, _, _}) when KeyExchange == rsa; - KeyExchange == dh_dss; - KeyExchange == dh_rsa; KeyExchange == dhe_dss; KeyExchange == dhe_rsa -> <<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>; certificate_types(_) -> - %%TODO: Is this a good default, - %% is there a case where we like to request - %% a RSA_FIXED_DH or DSS_FIXED_DH <<?BYTE(?RSA_SIGN)>>. certificate_authorities(CertDbRef) -> @@ -1101,7 +1068,7 @@ certificate_authorities_from_db(CertDbRef) -> certificate_authorities_from_db(CertDbRef, no_candidate, []). certificate_authorities_from_db(CertDbRef, PrevKey, Acc) -> - case ssl_certificate_db:issuer_candidate(PrevKey) of + case ssl_manager:issuer_candidate(PrevKey) of no_more_candidates -> lists:reverse(Acc); {{CertDbRef, _, _} = Key, Cert} -> @@ -1125,20 +1092,15 @@ calc_master_secret({3,N},PremasterSecret, ClientRandom, ServerRandom) when N == 1; N == 2 -> ssl_tls1:master_secret(PremasterSecret, ClientRandom, ServerRandom). -setup_keys({3,0}, Exportable, MasterSecret, +setup_keys({3,0}, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS) -> - ssl_ssl3:setup_keys(Exportable, MasterSecret, ServerRandom, + ssl_ssl3:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KML, EKML, IVS); -setup_keys({3,1}, _Exportable, MasterSecret, +setup_keys({3,1}, MasterSecret, ServerRandom, ClientRandom, HashSize, KML, _EKML, IVS) -> ssl_tls1:setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, - KML, IVS); - -setup_keys({3,2}, _Exportable, MasterSecret, - ServerRandom, ClientRandom, HashSize, KML, _EKML, _IVS) -> - ssl_tls1:setup_keys(MasterSecret, ServerRandom, - ClientRandom, HashSize, KML). + KML, IVS). calc_finished({3, 0}, Role, MasterSecret, Hashes) -> ssl_ssl3:finished(Role, MasterSecret, Hashes); @@ -1153,7 +1115,6 @@ calc_certificate_verify({3, N}, _, Algorithm, Hashes) ssl_tls1:certificate_verify(Algorithm, Hashes). server_key_exchange_hash(Algorithm, Value) when Algorithm == rsa; - Algorithm == dh_rsa; Algorithm == dhe_rsa -> MD5Context = crypto:md5_init(), NewMD5Context = crypto:md5_update(MD5Context, Value), @@ -1165,9 +1126,7 @@ server_key_exchange_hash(Algorithm, Value) when Algorithm == rsa; <<MD5/binary, SHA/binary>>; -server_key_exchange_hash(Algorithm, Value) when Algorithm == dh_dss; - Algorithm == dhe_dss -> - +server_key_exchange_hash(dhe_dss, Value) -> SHAContext = crypto:sha_init(), NewSHAContext = crypto:sha_update(SHAContext, Value), crypto:sha_final(NewSHAContext). @@ -1175,9 +1134,9 @@ server_key_exchange_hash(Algorithm, Value) when Algorithm == dh_dss; sig_alg(dh_anon) -> ?SIGNATURE_ANONYMOUS; -sig_alg(Alg) when Alg == dhe_rsa; Alg == rsa; Alg == dh_rsa -> +sig_alg(Alg) when Alg == dhe_rsa; Alg == rsa -> ?SIGNATURE_RSA; -sig_alg(Alg) when Alg == dh_dss; Alg == dhe_dss -> +sig_alg(dhe_dss) -> ?SIGNATURE_DSA; sig_alg(_) -> ?NULL. diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 0151426d43..7a0192a80f 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -27,7 +27,7 @@ %% Internal application API -export([start_link/0, start_link/1, connection_init/2, cache_pem_file/1, - lookup_trusted_cert/3, client_session_id/3, server_session_id/3, + lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3, server_session_id/3, register_session/2, register_session/3, invalidate_session/2, invalidate_session/3]). @@ -85,13 +85,20 @@ cache_pem_file(File) -> %% Function: %% Description: %%-------------------------------------------------------------------- -lookup_trusted_cert(SerialNumber, Issuer, Ref) -> +lookup_trusted_cert(Ref, SerialNumber, Issuer) -> ssl_certificate_db:lookup_trusted_cert(Ref, SerialNumber, Issuer). %%-------------------------------------------------------------------- %% Function: %% Description: %%-------------------------------------------------------------------- +issuer_candidate(PrevCandidateKey) -> + ssl_certificate_db:issuer_candidate(PrevCandidateKey). + +%%-------------------------------------------------------------------- +%% Function: +%% Description: +%%-------------------------------------------------------------------- client_session_id(Host, Port, SslOpts) -> call({client_session_id, Host, Port, SslOpts}). @@ -172,10 +179,8 @@ handle_call({{connection_init, TrustedcertsFile, _Role}, Pid}, _From, {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, TrustedcertsFile, Db), {ok, Ref, Cache} catch - _:{badmatch, Error} -> - {error, Error}; - _E:_R -> - {error, {_R,erlang:get_stacktrace()}} + _:Reason -> + {error, Reason} end, {reply, Result, State}; @@ -197,14 +202,10 @@ handle_call({{cache_pem, File},Pid}, _, State = #state{certificate_db = Db}) -> try ssl_certificate_db:cache_pem_file(Pid,File,Db) of Result -> {reply, Result, State} - catch _:{badmatch, Reason} -> - {reply, Reason, State}; - _:Reason -> + catch + _:Reason -> {reply, {error, Reason}, State} - end; - -handle_call(_,_, State) -> - {reply, ok, State}. + end. %%-------------------------------------------------------------------- %% Function: handle_cast(Msg, State) -> {noreply, State} | %% {noreply, State, Timeout} | @@ -332,7 +333,7 @@ init_session_validator([Cache, CacheCb, LifeTime]) -> CacheCb:foldl(fun session_validation/2, LifeTime, Cache). -session_validation({{Host, Port, _}, Session}, LifeTime) -> +session_validation({{{Host, Port}, _}, Session}, LifeTime) -> validate_session(Host, Port, Session, LifeTime), LifeTime; session_validation({{Port, _}, Session}, LifeTime) -> diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index f9f915f13d..43f18d95a0 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -29,6 +29,7 @@ -include("ssl_internal.hrl"). -include("ssl_alert.hrl"). -include("ssl_handshake.hrl"). +-include("ssl_cipher.hrl"). -include("ssl_debug.hrl"). %% Connection state handling @@ -410,16 +411,14 @@ protocol_version(tlsv1) -> {3, 1}; protocol_version(sslv3) -> {3, 0}; -protocol_version(sslv2) -> +protocol_version(sslv2) -> %% Backwards compatibility {2, 0}; protocol_version({3, 2}) -> 'tlsv1.1'; protocol_version({3, 1}) -> tlsv1; protocol_version({3, 0}) -> - sslv3; -protocol_version({2, 0}) -> - sslv2. + sslv3. %%-------------------------------------------------------------------- %% Function: protocol_version(Version1, Version2) -> #protocol_version{} %% Version1 = Version2 = #protocol_version{} @@ -467,7 +466,7 @@ highest_protocol_version(_, [Version | Rest]) -> %%-------------------------------------------------------------------- supported_protocol_versions() -> Fun = fun(Version) -> - protocol_version(Version) + protocol_version(Version) end, case application:get_env(ssl, protocol_version) of undefined -> @@ -475,11 +474,18 @@ supported_protocol_versions() -> {ok, []} -> lists:map(Fun, ?DEFAULT_SUPPORTED_VERSIONS); {ok, Vsns} when is_list(Vsns) -> - lists:map(Fun, Vsns); + Versions = lists:filter(fun is_acceptable_version/1, lists:map(Fun, Vsns)), + supported_protocol_versions(Versions); {ok, Vsn} -> - [Fun(Vsn)] + Versions = lists:filter(fun is_acceptable_version/1, [Fun(Vsn)]), + supported_protocol_versions(Versions) end. +supported_protocol_versions([]) -> + ?DEFAULT_SUPPORTED_VERSIONS; +supported_protocol_versions([_|_] = Vsns) -> + Vsns. + %%-------------------------------------------------------------------- %% Function: is_acceptable_version(Version) -> true | false %% Version = #protocol_version{} @@ -532,12 +538,10 @@ initial_connection_state(ConnectionEnd) -> }. initial_security_params(ConnectionEnd) -> - #security_parameters{connection_end = ConnectionEnd, - bulk_cipher_algorithm = ?NULL, - mac_algorithm = ?NULL, - compression_algorithm = ?NULL, - cipher_type = ?NULL - }. + SecParams = #security_parameters{connection_end = ConnectionEnd, + compression_algorithm = ?NULL}, + ssl_cipher:security_parameters(?TLS_NULL_WITH_NULL_NULL, + SecParams). empty_connection_state(ConnectionEnd) -> SecParams = empty_security_params(ConnectionEnd), @@ -689,7 +693,7 @@ hash_and_bump_seqno(#connection_state{sequence_number = SeqNo, check_hash(_, _) -> ok. %% TODO check this -mac_hash(?NULL, {_,_}, _MacSecret, _SeqNo, _Type, +mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type, _Length, _Fragment) -> <<>>; mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) -> diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index df809ce275..1bf8c2b458 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -30,7 +30,7 @@ -include("ssl_record.hrl"). % MD5 and SHA -export([master_secret/3, finished/3, certificate_verify/3, - mac_hash/6, setup_keys/8, + mac_hash/6, setup_keys/7, suites/0]). -compile(inline). @@ -76,7 +76,7 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> <<MD5/binary, SHA/binary>>. certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash}) - when Algorithm == rsa; Algorithm == dh_rsa; Algorithm == dhe_rsa -> + when Algorithm == rsa; Algorithm == dhe_rsa -> %% md5_hash %% MD5(master_secret + pad_2 + %% MD5(handshake_messages + master_secret + pad_1)); @@ -88,8 +88,7 @@ certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash}) SHA = handshake_hash(?SHA, MasterSecret, undefined, SHAHash), <<MD5/binary, SHA/binary>>; -certificate_verify(Algorithm, MasterSecret, {_, SHAHash}) - when Algorithm == dh_dss; Algorithm == dhe_dss -> +certificate_verify(dhe_dss, MasterSecret, {_, SHAHash}) -> %% sha_hash %% SHA(master_secret + pad_2 + %% SHA(handshake_messages + master_secret + pad_1)); @@ -114,9 +113,7 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) -> ?DBG_HEX(Mac), Mac. -setup_keys(Exportable, MasterSecret, ServerRandom, ClientRandom, - HS, KML, _EKML, IVS) - when Exportable == no_export; Exportable == ignore -> +setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) -> KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom, 2*(HS+KML+IVS)), %% draft-ietf-tls-ssl-version3-00 - 6.2.2 @@ -137,47 +134,7 @@ setup_keys(Exportable, MasterSecret, ServerRandom, ClientRandom, ?DBG_HEX(ClientIV), ?DBG_HEX(ServerIV), {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, - ServerWriteKey, ClientIV, ServerIV}; - -setup_keys(export, MasterSecret, ServerRandom, ClientRandom, - HS, KML, EKML, IVS) -> - KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom, - 2*(HS+KML)), - %% draft-ietf-tls-ssl-version3-00 - 6.2.2 - %% Exportable encryption algorithms (for which - %% CipherSpec.is_exportable is true) require additional processing as - %% follows to derive their final write keys: - - %% final_client_write_key = MD5(client_write_key + - %% ClientHello.random + - %% ServerHello.random); - %% final_server_write_key = MD5(server_write_key + - %% ServerHello.random + - %% ClientHello.random); - - %% Exportable encryption algorithms derive their IVs from the random - %% messages: - %% client_write_IV = MD5(ClientHello.random + ServerHello.random); - %% server_write_IV = MD5(ServerHello.random + ClientHello.random); - - <<ClientWriteMacSecret:HS/binary, ServerWriteMacSecret:HS/binary, - ClientWriteKey:KML/binary, ServerWriteKey:KML/binary>> = KeyBlock, - <<ClientIV:IVS/binary, _/binary>> = - hash(?MD5, [ClientRandom, ServerRandom]), - <<ServerIV:IVS/binary, _/binary>> = - hash(?MD5, [ServerRandom, ClientRandom]), - <<FinalClientWriteKey:EKML/binary, _/binary>> = - hash(?MD5, [ClientWriteKey, ClientRandom, ServerRandom]), - <<FinalServerWriteKey:EKML/binary, _/binary>> = - hash(?MD5, [ServerWriteKey, ServerRandom, ClientRandom]), - ?DBG_HEX(ClientWriteMacSecret), - ?DBG_HEX(ServerWriteMacSecret), - ?DBG_HEX(FinalClientWriteKey), - ?DBG_HEX(FinalServerWriteKey), - ?DBG_HEX(ClientIV), - ?DBG_HEX(ServerIV), - {ClientWriteMacSecret, ServerWriteMacSecret, FinalClientWriteKey, - FinalServerWriteKey, ClientIV, ServerIV}. + ServerWriteKey, ClientIV, ServerIV}. suites() -> [ @@ -191,25 +148,12 @@ suites() -> ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, %% ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_DHE_DSS_WITH_RC4_128_SHA, TODO: Support this? + %%?TLS_DHE_DSS_WITH_RC4_128_SHA, %% ?TLS_RSA_WITH_IDEA_CBC_SHA, Not supported: in later openssl version than OTP requires - ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, - %%?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5, - %%?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, - %%?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, - %%?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, - %%?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, - %%?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, %%?TLS_DHE_DSS_WITH_RC4_128_SHA, - ?TLS_RSA_WITH_DES_CBC_SHA - %% ?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, - %% ?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, - %% ?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, - %%?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, - %%?TLS_RSA_EXPORT_WITH_RC4_40_MD5 ]. %%-------------------------------------------------------------------- @@ -269,8 +213,7 @@ handshake_hash(Method, MasterSecret, Sender, HandshakeHash) -> hash(Method, [MasterSecret, pad_2(Method), InnerHash]). get_sender(client) -> "CLNT"; -get_sender(server) -> "SRVR"; -get_sender(none) -> "". +get_sender(server) -> "SRVR". generate_keyblock(MasterSecret, ServerRandom, ClientRandom, WantedLength) -> gen(MasterSecret, [MasterSecret, ServerRandom, ClientRandom], diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl index ce9a135168..900b8e166d 100644 --- a/lib/ssl/src/ssl_tls1.erl +++ b/lib/ssl/src/ssl_tls1.erl @@ -30,7 +30,7 @@ -include("ssl_debug.hrl"). -export([master_secret/3, finished/3, certificate_verify/2, mac_hash/7, - setup_keys/5, setup_keys/6, suites/0]). + setup_keys/6, suites/0]). %%==================================================================== %% Internal application API @@ -58,14 +58,12 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) -> certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa; - Algorithm == dh_rsa; Algorithm == dhe_rsa -> MD5 = hash_final(?MD5, MD5Hash), SHA = hash_final(?SHA, SHAHash), <<MD5/binary, SHA/binary>>; -certificate_verify(Algorithm, {_, SHAHash}) when Algorithm == dh_dss; - Algorithm == dhe_dss -> +certificate_verify(dhe_dss, {_, SHAHash}) -> hash_final(?SHA, SHAHash). setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, @@ -92,26 +90,27 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, ServerWriteKey, ClientIV, ServerIV}. -setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KeyMatLen) -> - %% RFC 4346 - 6.3. Key calculation - %% key_block = PRF(SecurityParameters.master_secret, - %% "key expansion", - %% SecurityParameters.server_random + - %% SecurityParameters.client_random); - %% Then the key_block is partitioned as follows: - %% client_write_MAC_secret[SecurityParameters.hash_size] - %% server_write_MAC_secret[SecurityParameters.hash_size] - %% client_write_key[SecurityParameters.key_material_length] - %% server_write_key[SecurityParameters.key_material_length] - WantedLength = 2 * (HashSize + KeyMatLen), - KeyBlock = prf(MasterSecret, "key expansion", - [ServerRandom, ClientRandom], WantedLength), - <<ClientWriteMacSecret:HashSize/binary, - ServerWriteMacSecret:HashSize/binary, - ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary>> - = KeyBlock, - {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, - ServerWriteKey, undefined, undefined}. +%% TLS v1.1 uncomment when supported. +%% setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize, KeyMatLen) -> +%% %% RFC 4346 - 6.3. Key calculation +%% %% key_block = PRF(SecurityParameters.master_secret, +%% %% "key expansion", +%% %% SecurityParameters.server_random + +%% %% SecurityParameters.client_random); +%% %% Then the key_block is partitioned as follows: +%% %% client_write_MAC_secret[SecurityParameters.hash_size] +%% %% server_write_MAC_secret[SecurityParameters.hash_size] +%% %% client_write_key[SecurityParameters.key_material_length] +%% %% server_write_key[SecurityParameters.key_material_length] +%% WantedLength = 2 * (HashSize + KeyMatLen), +%% KeyBlock = prf(MasterSecret, "key expansion", +%% [ServerRandom, ClientRandom], WantedLength), +%% <<ClientWriteMacSecret:HashSize/binary, +%% ServerWriteMacSecret:HashSize/binary, +%% ClientWriteKey:KeyMatLen/binary, ServerWriteKey:KeyMatLen/binary>> +%% = KeyBlock, +%% {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey, +%% ServerWriteKey, undefined, undefined}. mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor}, Length, Fragment) -> @@ -140,30 +139,18 @@ suites() -> %%?TLS_DHE_DSS_WITH_AES_256_CBC_SHA, ?TLS_RSA_WITH_AES_256_CBC_SHA, ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - %% ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + %%?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, ?TLS_RSA_WITH_3DES_EDE_CBC_SHA, ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - %% ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + %%?TLS_DHE_DSS_WITH_AES_128_CBC_SHA, ?TLS_RSA_WITH_AES_128_CBC_SHA, - %%?TLS_DHE_DSS_WITH_RC4_128_SHA, TODO: Support this? - %% ?TLS_RSA_WITH_IDEA_CBC_SHA, + %%?TLS_DHE_DSS_WITH_RC4_128_SHA, + %%?TLS_RSA_WITH_IDEA_CBC_SHA, ?TLS_RSA_WITH_RC4_128_SHA, ?TLS_RSA_WITH_RC4_128_MD5, - %%?TLS_RSA_EXPORT1024_WITH_RC4_56_MD5, - %%?TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, - %%?TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, - %%?TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, - %%?TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, - %%?TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, - %%?TLS_DHE_DSS_WITH_RC4_128_SHA, - %%?TLS_DHE_RSA_WITH_DES_CBC_SHA, - %% EDH-DSS-DES-CBC-SHA TODO: ?? + ?TLS_DHE_RSA_WITH_DES_CBC_SHA, + %%TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA ?TLS_RSA_WITH_DES_CBC_SHA - %% ?TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, - %% ?TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, - %%?TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, - %%?TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, - %%?TLS_RSA_EXPORT_WITH_RC4_40_MD5 ]. %%-------------------------------------------------------------------- @@ -245,7 +232,3 @@ hash_final(?MD5, Conntext) -> crypto:md5_final(Conntext); hash_final(?SHA, Conntext) -> crypto:sha_final(Conntext). - - - - diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 9afcbd9113..ab0a394f93 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -27,13 +27,13 @@ -include("test_server.hrl"). -include("test_server_line.hrl"). -include_lib("public_key/include/public_key.hrl"). +-include("ssl_alert.hrl"). -define('24H_in_sec', 86400). -define(TIMEOUT, 60000). -define(EXPIRE, 10). -define(SLEEP, 500). - -behaviour(ssl_session_cache_api). %% For the session cache tests @@ -98,6 +98,37 @@ init_per_testcase(reuse_session_expired, Config0) -> ssl:start(), [{watchdog, Dog} | Config]; +init_per_testcase(no_authority_key_identifier, Config) -> + %% Clear cach so that root cert will not + %% be found. + ssl:stop(), + ssl:start(), + Config; + +init_per_testcase(TestCase, Config) when TestCase == ciphers_ssl3; + TestCase == ciphers_ssl3_openssl_names -> + ssl:stop(), + application:load(ssl), + application:set_env(ssl, protocol_version, sslv3), + ssl:start(), + Config; + +init_per_testcase(protocol_versions, Config) -> + ssl:stop(), + application:load(ssl), + %% For backwards compatibility sslv2 should be filtered out. + application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]), + ssl:start(), + Config; + +init_per_testcase(empty_protocol_versions, Config) -> + ssl:stop(), + application:load(ssl), + %% For backwards compatibility sslv2 should be filtered out. + application:set_env(ssl, protocol_version, []), + ssl:start(), + Config; + init_per_testcase(_TestCase, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), Dog = test_server:timetrap(?TIMEOUT), @@ -130,6 +161,12 @@ end_per_testcase(session_cache_process_mnesia, Config) -> end_per_testcase(reuse_session_expired, Config) -> application:unset_env(ssl, session_lifetime), end_per_testcase(default_action, Config); +end_per_testcase(TestCase, Config) when TestCase == ciphers_ssl3; + TestCase == ciphers_ssl3_openssl_names; + TestCase == protocol_versions; + TestCase == empty_protocol_versions-> + application:unset_env(ssl, protocol_version), + end_per_testcase(default_action, Config); end_per_testcase(_TestCase, Config) -> Dog = ?config(watchdog, Config), case Dog of @@ -151,30 +188,31 @@ all(doc) -> ["Test the basic ssl functionality"]; all(suite) -> - [app, connection_info, controlling_process, controller_dies, - client_closes_socket, - peercert, connect_dist, - peername, sockname, socket_options, misc_ssl_options, versions, cipher_suites, - upgrade, upgrade_with_timeout, tcp_connect, - ipv6, ekeyfile, ecertfile, ecacertfile, eoptions, shutdown, - shutdown_write, shutdown_both, shutdown_error, ciphers, - send_close, close_transport_accept, dh_params, - server_verify_peer_passive, - server_verify_peer_active, server_verify_peer_active_once, - server_verify_none_passive, server_verify_none_active, - server_verify_none_active_once, server_verify_no_cacerts, - server_require_peer_cert_ok, server_require_peer_cert_fail, - server_verify_client_once_passive, - server_verify_client_once_active, - server_verify_client_once_active_once, - client_verify_none_passive, - client_verify_none_active, client_verify_none_active_once - %%, session_cache_process_list, session_cache_process_mnesia - ,reuse_session, reuse_session_expired, server_does_not_want_to_reuse_session, - client_renegotiate, server_renegotiate, client_renegotiate_reused_session, - server_renegotiate_reused_session, - client_no_wrap_sequence_number, server_no_wrap_sequence_number, - extended_key_usage, validate_extensions_fun + [app, alerts, connection_info, protocol_versions, + empty_protocol_versions, controlling_process, controller_dies, + client_closes_socket, peercert, connect_dist, peername, sockname, + socket_options, misc_ssl_options, versions, cipher_suites, + upgrade, upgrade_with_timeout, tcp_connect, ipv6, ekeyfile, + ecertfile, ecacertfile, eoptions, shutdown, shutdown_write, + shutdown_both, shutdown_error, ciphers, ciphers_ssl3, + ciphers_openssl_names, ciphers_ssl3_openssl_names, send_close, + close_transport_accept, dh_params, server_verify_peer_passive, + server_verify_peer_active, server_verify_peer_active_once, + server_verify_none_passive, server_verify_none_active, + server_verify_none_active_once, server_verify_no_cacerts, + server_require_peer_cert_ok, server_require_peer_cert_fail, + server_verify_client_once_passive, + server_verify_client_once_active, + server_verify_client_once_active_once, client_verify_none_passive, + client_verify_none_active, client_verify_none_active_once, + %session_cache_process_list, session_cache_process_mnesia, + reuse_session, reuse_session_expired, + server_does_not_want_to_reuse_session, client_renegotiate, + server_renegotiate, client_renegotiate_reused_session, + server_renegotiate_reused_session, client_no_wrap_sequence_number, + server_no_wrap_sequence_number, extended_key_usage, + validate_extensions_fun, no_authority_key_identifier, + invalid_signature_client, invalid_signature_server, cert_expired ]. %% Test cases starts here. @@ -185,7 +223,31 @@ app(suite) -> []; app(Config) when is_list(Config) -> ok = test_server:app_test(ssl). - +%%-------------------------------------------------------------------- +alerts(doc) -> + "Test ssl_alert:alert_txt/1"; +alerts(suite) -> + []; +alerts(Config) when is_list(Config) -> + Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC, + ?DECRYPTION_FAILED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE, + ?HANDSHAKE_FAILURE, ?BAD_CERTIFICATE, ?UNSUPPORTED_CERTIFICATE, + ?CERTIFICATE_REVOKED,?CERTIFICATE_EXPIRED, ?CERTIFICATE_UNKNOWN, + ?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR, + ?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION, + ?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED, + ?NO_RENEGOTIATION], + Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) | + [?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]], + lists:foreach(fun(Alert) -> + case ssl_alert:alert_txt(Alert) of + Txt when is_list(Txt) -> + ok; + Other -> + test_server:fail({unexpected, Other}) + end + end, Alerts). +%%-------------------------------------------------------------------- connection_info(doc) -> ["Test the API function ssl:connection_info/1"]; connection_info(suite) -> @@ -214,7 +276,7 @@ connection_info(Config) when is_list(Config) -> Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])), - ServerMsg = ClientMsg = {ok, {Version, {rsa,rc4_128,sha,no_export}}}, + ServerMsg = ClientMsg = {ok, {Version, {rsa,rc4_128,sha}}}, ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg), @@ -226,6 +288,49 @@ connection_info_result(Socket) -> %%-------------------------------------------------------------------- +protocol_versions(doc) -> + ["Test to set a list of protocol versions in app environment."]; + +protocol_versions(suite) -> + []; + +protocol_versions(Config) when is_list(Config) -> + basic_test(Config). + +empty_protocol_versions(doc) -> + ["Test to set an empty list of protocol versions in app environment."]; + +empty_protocol_versions(suite) -> + []; + +empty_protocol_versions(Config) when is_list(Config) -> + basic_test(Config). + + +basic_test(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, ClientOpts}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + controlling_process(doc) -> ["Test API function controlling_process/2"]; @@ -283,7 +388,7 @@ controlling_process_result(Socket, Pid, Msg) -> ssl:send(Socket, Msg), no_result_msg. - +%%-------------------------------------------------------------------- controller_dies(doc) -> ["Test that the socket is closed after controlling process dies"]; controller_dies(suite) -> []; @@ -598,9 +703,12 @@ cipher_suites(suite) -> []; cipher_suites(Config) when is_list(Config) -> - MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha,no_export}, + MandatoryCipherSuite = {rsa,'3des_ede_cbc',sha}, [_|_] = Suites = ssl:cipher_suites(), - true = lists:member(MandatoryCipherSuite, Suites). + true = lists:member(MandatoryCipherSuite, Suites), + Suites = ssl:cipher_suites(erlang), + [_|_] =ssl:cipher_suites(openssl). + %%-------------------------------------------------------------------- socket_options(doc) -> ["Test API function getopts/2 and setopts/2"]; @@ -635,9 +743,16 @@ socket_options(Config) when is_list(Config) -> {options, ClientOpts}]), ssl_test_lib:check_result(Server, ok, Client, ok), - + ssl_test_lib:close(Server), - ssl_test_lib:close(Client). + ssl_test_lib:close(Client), + + {ok, Listen} = ssl:listen(0, ServerOpts), + {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]), + ok = ssl:setopts(Listen, [{mode, binary}]), + {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]), + {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]), + ssl:close(Listen). socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> %% Test get/set emulated opts @@ -646,6 +761,8 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) -> {ok, NewValues} = ssl:getopts(Socket, NewOptions), %% Test get/set inet opts {ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]), + ssl:setopts(Socket, [{nodelay, true}]), + {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]), ok. %%-------------------------------------------------------------------- @@ -1272,9 +1389,9 @@ shutdown_error(Config) when is_list(Config) -> ok = ssl:close(Listen), {error, closed} = ssl:shutdown(Listen, read_write). -%%-------------------------------------------------------------------- +%%------------------------------------------------------------------- ciphers(doc) -> - [""]; + ["Test all ssl cipher suites in highest support ssl/tls version"]; ciphers(suite) -> []; @@ -1284,6 +1401,7 @@ ciphers(Config) when is_list(Config) -> ssl_record:protocol_version(ssl_record:highest_protocol_version([])), Ciphers = ssl:cipher_suites(), + test_server:format("tls1 erlang cipher suites ~p~n", [Ciphers]), Result = lists:map(fun(Cipher) -> cipher(Cipher, Version, Config) end, Ciphers), @@ -1294,7 +1412,74 @@ ciphers(Config) when is_list(Config) -> test_server:format("Cipher suite errors: ~p~n", [Error]), test_server:fail(cipher_suite_failed_see_test_case_log) end. - + +ciphers_ssl3(doc) -> + ["Test all ssl cipher suites in ssl3"]; + +ciphers_ssl3(suite) -> + []; + +ciphers_ssl3(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version({3,0}), + + Ciphers = ssl:cipher_suites(), + test_server:format("ssl3 erlang cipher suites ~p~n", [Ciphers]), + Result = lists:map(fun(Cipher) -> + cipher(Cipher, Version, Config) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + test_server:format("Cipher suite errors: ~p~n", [Error]), + test_server:fail(cipher_suite_failed_see_test_case_log) + end. + +ciphers_openssl_names(doc) -> + ["Test all ssl cipher suites in highest support ssl/tls version"]; + +ciphers_openssl_names(suite) -> + []; + +ciphers_openssl_names(Config) when is_list(Config) -> + Version = + ssl_record:protocol_version(ssl_record:highest_protocol_version([])), + + Ciphers = ssl:cipher_suites(openssl), + test_server:format("tls1 openssl cipher suites ~p~n", [Ciphers]), + Result = lists:map(fun(Cipher) -> + cipher(Cipher, Version, Config) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + test_server:format("Cipher suite errors: ~p~n", [Error]), + test_server:fail(cipher_suite_failed_see_test_case_log) + end. + + +ciphers_ssl3_openssl_names(doc) -> + ["Test all ssl cipher suites in ssl3"]; + +ciphers_ssl3_openssl_names(suite) -> + []; + +ciphers_ssl3_openssl_names(Config) when is_list(Config) -> + Version = ssl_record:protocol_version({3,0}), + Ciphers = ssl:cipher_suites(openssl), + Result = lists:map(fun(Cipher) -> + cipher(Cipher, Version, Config) end, + Ciphers), + case lists:flatten(Result) of + [] -> + ok; + Error -> + test_server:format("Cipher suite errors: ~p~n", [Error]), + test_server:fail(cipher_suite_failed_see_test_case_log) + end. + cipher(CipherSuite, Version, Config) -> process_flag(trap_exit, true), test_server:format("Testing CipherSuite ~p~n", [CipherSuite]), @@ -1314,7 +1499,9 @@ cipher(CipherSuite, Version, Config) -> [{ciphers,[CipherSuite]} | ClientOpts]}]), - ServerMsg = ClientMsg = {ok, {Version, CipherSuite}}, + ErlangCipherSuite = erlang_cipher_suite(CipherSuite), + + ServerMsg = ClientMsg = {ok, {Version, ErlangCipherSuite}}, Result = ssl_test_lib:wait_for_result(Server, ServerMsg, Client, ClientMsg), @@ -1333,9 +1520,14 @@ cipher(CipherSuite, Version, Config) -> ok -> []; Error -> - [{CipherSuite, Error}] + [{ErlangCipherSuite, Error}] end. +erlang_cipher_suite(Suite) when is_list(Suite)-> + ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite)); +erlang_cipher_suite(Suite) -> + Suite. + %%-------------------------------------------------------------------- reuse_session(doc) -> ["Test reuse of sessions (short handshake)"]; @@ -2269,48 +2461,54 @@ extended_key_usage(suite) -> []; extended_key_usage(Config) when is_list(Config) -> - ClientOpts = ?config(client_opts, Config), - ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), PrivDir = ?config(priv_dir, Config), - CertFile = proplists:get_value(certfile, ServerOpts), - KeyFile = proplists:get_value(keyfile, ServerOpts), - NewCertFile = filename:join(PrivDir, "cert.pem"), - - {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(CertFile), - + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), - {ok, Key} = public_key:decode_private_key(KeyInfo), - {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp), - - ExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, - - OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, - - Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, - - NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = [ExtKeyUsageExt |Extensions]}, - - NewDerCert = public_key:sign(NewOTPTbsCert, Key), - - public_key:der_to_pem(NewCertFile, [{cert, NewDerCert}]), - - NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)], + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"), + {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile), + {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']}, + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions, + NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions = + [ServerExtKeyUsageExt | + ServerExtensions]}, + NewServerDerCert = public_key:sign(NewServerOTPTbsCert, Key), + public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"), + {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile), + {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']}, + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions, + NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions = + [ClientExtKeyUsageExt | + ClientExtensions]}, + NewClientDerCert = public_key:sign(NewClientOTPTbsCert, Key), + public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert}]), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, {from, self()}, {mfa, {?MODULE, send_recv_result_active, []}}, - {options, NewServerOpts}]), + {options, [{verify, verify_peer} | NewServerOpts]}]), Port = ssl_test_lib:inet_port(Server), Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {?MODULE, send_recv_result_active, []}}, - {options, ClientOpts}]), + {options, [{verify, verify_peer} | NewClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -2353,6 +2551,217 @@ validate_extensions_fun(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +no_authority_key_identifier(doc) -> + ["Test cert that does not have authorityKeyIdentifier extension"]; + +no_authority_key_identifier(suite) -> + []; +no_authority_key_identifier(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), + {ok, Key} = public_key:decode_private_key(KeyInfo), + + CertFile = proplists:get_value(certfile, ServerOpts), + NewCertFile = filename:join(PrivDir, "server/new_cert.pem"), + {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(CertFile), + {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp), + OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, + Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, + NewExtensions = delete_authority_key_extension(Extensions, []), + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions}, + + test_server:format("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]), + + NewDerCert = public_key:sign(NewOTPTbsCert, Key), + public_key:der_to_pem(NewCertFile, [{cert, NewDerCert}]), + NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, NewServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result_active, []}}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +delete_authority_key_extension([], Acc) -> + lists:reverse(Acc); +delete_authority_key_extension([#'Extension'{extnID = ?'id-ce-authorityKeyIdentifier'} | Rest], + Acc) -> + delete_authority_key_extension(Rest, Acc); +delete_authority_key_extension([Head | Rest], Acc) -> + delete_authority_key_extension(Rest, [Head | Acc]). + +%%-------------------------------------------------------------------- + +invalid_signature_server(doc) -> + ["Test server with invalid signature"]; + +invalid_signature_server(suite) -> + []; + +invalid_signature_server(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "server/key.pem"), + {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), + {ok, Key} = public_key:decode_private_key(KeyInfo), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"), + {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile), + {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp), + ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate, + NewServerDerCert = public_key:sign(ServerOTPTbsCert, Key), + public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, NewServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, "bad certificate"}, + Client, {error,"bad certificate"}), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- + +invalid_signature_client(doc) -> + ["Test server with invalid signature"]; + +invalid_signature_client(suite) -> + []; + +invalid_signature_client(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "client/key.pem"), + {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), + {ok, Key} = public_key:decode_private_key(KeyInfo), + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"), + {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile), + {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp), + ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate, + NewClientDerCert = public_key:sign(ClientOTPTbsCert, Key), + public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert}]), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, [{verify, verify_peer} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, NewClientOpts}]), + + ssl_test_lib:check_result(Server, {error, "bad certificate"}, + Client, {error,"bad certificate"}), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +cert_expired(doc) -> + ["Test server with invalid signature"]; + +cert_expired(suite) -> + []; + +cert_expired(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile), + {ok, Key} = public_key:decode_private_key(KeyInfo), + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"), + {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(ServerCertFile), + {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp), + OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, + + {Year, Month, Day} = date(), + {Hours, Min, Sec} = time(), + NotBeforeStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-2, + two_digits_str(Month), + two_digits_str(Day), + two_digits_str(Hours), + two_digits_str(Min), + two_digits_str(Sec)])), + NotAfterStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-1, + two_digits_str(Month), + two_digits_str(Day), + two_digits_str(Hours), + two_digits_str(Min), + two_digits_str(Sec)])), + NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}}, + + test_server:format("Validity: ~p ~n NewValidity: ~p ~n", + [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]), + + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity}, + NewServerDerCert = public_key:sign(NewOTPTbsCert, Key), + public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert}]), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, NewServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, [{verify, verify_peer} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, {error, "certificate expired"}, + Client, {error, "certificate expired"}), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +two_digits_str(N) when N < 10 -> + lists:flatten(io_lib:format("0~p", [N])); +two_digits_str(N) -> + lists:flatten(io_lib:format("~p", [N])). + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- send_recv_result(Socket) -> diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 03466aec6f..82073c0735 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -33,6 +33,7 @@ -define(OPENSSL_RENEGOTIATE, "r\n"). -define(OPENSSL_QUIT, "Q\n"). -define(OPENSSL_GARBAGE, "P\n"). +-define(EXPIRE, 10). %% Test server callback functions %%-------------------------------------------------------------------- @@ -81,6 +82,15 @@ end_per_suite(_Config) -> %% variable, but should NOT alter/remove any existing entries. %% Description: Initialization before each test case %%-------------------------------------------------------------------- +init_per_testcase(expired_session, Config0) -> + Config = lists:keydelete(watchdog, 1, Config0), + Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5), + ssl:stop(), + application:load(ssl), + application:set_env(ssl, session_lifetime, ?EXPIRE), + ssl:start(), + [{watchdog, Dog} | Config]; + init_per_testcase(TestCase, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), Dog = ssl_test_lib:timetrap(?TIMEOUT), @@ -103,14 +113,20 @@ special_init(_, Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- -end_per_testcase(_TestCase, Config) -> +end_per_testcase(reuse_session_expired, Config) -> + application:unset_env(ssl, session_lifetime), + end_per_testcase(default_action, Config); + +end_per_testcase(default_action, Config) -> Dog = ?config(watchdog, Config), case Dog of undefined -> ok; _ -> test_server:timetrap_cancel(Dog) - end. + end; +end_per_testcase(_, Config) -> + end_per_testcase(default_action, Config). %%-------------------------------------------------------------------- %% Function: all(Clause) -> TestCases @@ -142,7 +158,9 @@ all(suite) -> tls1_erlang_server_openssl_client_client_cert, tls1_erlang_server_erlang_client_client_cert, ciphers, - erlang_client_bad_openssl_server + erlang_client_bad_openssl_server, + expired_session, + ssl2_erlang_server_openssl_client ]. %% Test cases starts here. @@ -991,6 +1009,100 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) -> close_port(OpensslPort), process_flag(trap_exit, false), ok. + +%%-------------------------------------------------------------------- + +expired_session(doc) -> + ["Test our ssl client handling of expired sessions. Will make" + "better code coverage of the ssl_manager module"]; + +expired_session(suite) -> + []; + +expired_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config), + + Port = ssl_test_lib:inet_port(node()), + CertFile = proplists:get_value(certfile, ServerOpts), + KeyFile = proplists:get_value(keyfile, ServerOpts), + + Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ + " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + + wait_for_openssl_server(), + + Client0 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + + ssl_test_lib:close(Client0), + + %% Make sure session is registered + test_server:sleep(?SLEEP), + + Client1 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + + ssl_test_lib:close(Client1), + %% Make sure session is unregistered due to expiration + test_server:sleep((?EXPIRE+1) * 1000), + + Client2 = + ssl_test_lib:start_client([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, no_result, []}}, + {from, self()}, {options, ClientOpts}]), + + close_port(OpensslPort), + ssl_test_lib:close(Client2), + process_flag(trap_exit, false). + +%%-------------------------------------------------------------------- +ssl2_erlang_server_openssl_client(doc) -> + ["Test that ssl v2 clients are rejected"]; +ssl2_erlang_server_openssl_client(suite) -> + []; +ssl2_erlang_server_openssl_client(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + + {_, ServerNode, _} = ssl_test_lib:run_where(Config), + + Data = "From openssl to erlang", + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ + " -host localhost -ssl2 -msg", + + test_server:format("openssl cmd: ~p~n", [Cmd]), + + OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]), + port_command(OpenSslPort, Data), + + ssl_test_lib:check_result(Server, {error,"protocol version"}), + + ssl_test_lib:close(Server), + + close_port(OpenSslPort), + process_flag(trap_exit, false), + ok. + %%-------------------------------------------------------------------- erlang_ssl_receive(Socket, Data) -> |