aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/doc/src/notes.xml42
-rw-r--r--lib/ssl/doc/src/ssl.xml48
-rw-r--r--lib/ssl/src/ssl.appup.src27
-rw-r--r--lib/ssl/src/ssl.erl198
-rw-r--r--lib/ssl/src/ssl_certificate.erl24
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl18
-rw-r--r--lib/ssl/src/ssl_cipher.erl138
-rw-r--r--lib/ssl/src/ssl_connection.erl173
-rw-r--r--lib/ssl/src/ssl_handshake.erl228
-rw-r--r--lib/ssl/src/ssl_handshake.hrl7
-rw-r--r--lib/ssl/src/ssl_internal.hrl40
-rw-r--r--lib/ssl/src/ssl_manager.erl2
-rw-r--r--lib/ssl/src/ssl_record.erl100
-rw-r--r--lib/ssl/src/ssl_ssl3.erl25
-rw-r--r--lib/ssl/src/ssl_tls1.erl11
-rw-r--r--lib/ssl/test/Makefile1
-rw-r--r--lib/ssl/test/erl_make_certs.erl4
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl263
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl306
-rw-r--r--lib/ssl/test/ssl_test_lib.erl10
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl19
-rw-r--r--lib/ssl/vsn.mk3
22 files changed, 974 insertions, 713 deletions
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 5f9e436348..756c0d1b1f 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -31,7 +31,47 @@
<p>This document describes the changes made to the SSL application.
</p>
- <section><title>SSL 4.0.1</title>
+ <section><title>SSL 4.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Updated ssl to ignore CA certs that violate the asn1-spec
+ for a certificate, and updated public key asn1 spec to
+ handle inherited DSS-params.</p>
+ <p>
+ Own Id: OTP-7884</p>
+ </item>
+ <item>
+ <p>
+ Changed ssl implementation to retain backwards
+ compatibility for old option {verify, 0} that shall be
+ equivalent to {verify, verify_none}, also separate the
+ cases unknown ca and selfsigned peer cert, and restored
+ return value of deprecated function
+ public_key:pem_to_der/1.</p>
+ <p>
+ Own Id: OTP-8858</p>
+ </item>
+ <item>
+ <p>
+ Changed the verify fun so that it differentiate between
+ the peer certificate and CA certificates by using
+ valid_peer or valid as the second argument to the verify
+ fun. It may not always be trivial or even possible to
+ know when the peer certificate is reached otherwise.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-8873</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 4.0.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index d5b7253ef3..ec272379bb 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -114,7 +114,7 @@
<p><c>ciphersuite() =
{key_exchange(), cipher(), hash()}</c></p>
- <p><c>key_exchange() = rsa | dhe_dss | dhe_rsa
+ <p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -170,8 +170,13 @@
<tag>{ciphers, ciphers()}</tag>
<item>The cipher suites that should be supported. The function
- <c>ciphers_suites/0</c> can be used to find all available
- ciphers.
+ <c>cipher_suites/0</c> can be used to find all available
+ ciphers. Additionally some anonymous cipher suites ({dh_anon,
+ rc4_128, md5}, {dh_anon, des_cbc, sha}, {dh_anon,
+ '3des_ede_cbc', sha}, {dh_anon, aes_128_cbc, sha}, {dh_anon,
+ aes_256_cbc, sha}) are supported for testing purposes and will
+ only work if explicitly enabled by this option and they are supported/enabled
+ by the peer also.
</item>
<tag>{ssl_imp, ssl_imp()}</tag>
@@ -202,10 +207,10 @@
<p>The verification fun should be defined as:</p>
<code>
-fun(OtpCert :: #'OtpCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
+fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
{extension, #'Extension'{}}, InitialUserState :: term()) ->
- {valid, UserState :: term()} | {fail, Reason :: term()} |
- {unknown, UserState :: term()}.
+ {valid, UserState :: term()} | {valid_peer, UserState :: term()} |
+ {fail, Reason :: term()} | {unknown, UserState :: term()}.
</code>
<p>The verify fun will be called during the X509-path
@@ -213,10 +218,12 @@ fun(OtpCert :: #'OtpCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
application is encountered. Additionally it will be called
when a certificate is considered valid by the path validation
to allow access to each certificate in the path to the user
- application.
- See
- <seealso marker="public_key:application">public_key(3)</seealso>
- for definition of #'OtpCertificate'{} and #'Extension'{}.</p>
+ application. Note that the it will differentiate between the
+ peer certificate and CA certificates by using valid_peer or
+ valid as the second argument to the verify fun. See <seealso
+ marker="public_key:cert_records">the public_key User's
+ Guide</seealso> for definition of #'OTPCertificate'{} and
+ #'Extension'{}.</p>
<p>If the verify callback fun returns {fail, Reason}, the
verification process is immediately stopped and an alert is
@@ -237,21 +244,23 @@ fun(OtpCert :: #'OtpCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
(_,{extension, _}, UserState) ->
{unknown, UserState};
(_, valid, UserState) ->
- {valid, UserState}
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
end, []}
</code>
<p>The default verify_fun option in verify_none mode:</p>
<code>
-{fun(_,{bad_cert, unknown_ca}, UserState) ->
+{fun(_,{bad_cert, _}, UserState) ->
{valid, UserState};
- (_,{bad_cert, _} = Reason, _) ->
- {fail, Reason};
(_,{extension, _}, UserState) ->
{unknown, UserState};
(_, valid, UserState) ->
- {valid, UserState}
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
end, []}
</code>
@@ -267,13 +276,14 @@ fun(OtpCert :: #'OtpCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<section>
<title>SSL OPTION DESCRIPTIONS - CLIENT SIDE</title>
- <p>Option described here are client specific or has a slightly different
+ <p>Options described here are client specific or has a slightly different
meaning in the client than in the server.</p>
<taglist>
<tag>{verify, verify_type()}</tag>
- <item> In verify_none mode the x509-path validation error {bad_cert, unknown_ca}
- will automatically be accepted. See also the verify_fun option.
+ <item> In verify_none mode the default behavior will be to
+ allow all x509-path validation errors. See also the verify_fun
+ option.
</item>
<tag>{reuse_sessions, boolean()}</tag>
<item>Specifies if client should try to reuse sessions
@@ -286,7 +296,7 @@ fun(OtpCert :: #'OtpCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<section>
<title>SSL OPTION DESCRIPTIONS - SERVER SIDE</title>
- <p>Option described here are server specific or has a slightly different
+ <p>Options described here are server specific or has a slightly different
meaning in the server than in the client.</p>
<taglist>
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index 88cd73be74..f4e6b59b6d 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,32 +1,9 @@
%% -*- erlang -*-
{"%VSN%",
[
- {"4.0", [{restart_application, ssl}]},
- {"3.11.1", [{restart_application, ssl}]},
- {"3.11", [{restart_application, ssl}]},
- {"3.10", [{restart_application, ssl}]},
- {"3.10.1", [{restart_application, ssl}]},
- {"3.10.2", [{restart_application, ssl}]},
- {"3.10.3", [{restart_application, ssl}]},
- {"3.10.4", [{restart_application, ssl}]},
- {"3.10.5", [{restart_application, ssl}]},
- {"3.10.6", [{restart_application, ssl}]},
- {"3.10.7", [{restart_application, ssl}]},
- {"3.10.8", [{restart_application, ssl}]},
- {"3.10.9", [{restart_application, ssl}]}
+ {"4.0.1", [{restart_application, ssl}]}
],
[
- {"4.0", [{restart_application, ssl}]},
- {"3.11.1", [{restart_application, ssl}]},
- {"3.11", [{restart_application, ssl}]},
- {"3.10", [{restart_application, ssl}]},
- {"3.10.1", [{restart_application, ssl}]},
- {"3.10.2", [{restart_application, ssl}]},
- {"3.10.3", [{restart_application, ssl}]},
- {"3.10.4", [{restart_application, ssl}]},
- {"3.10.5", [{restart_application, ssl}]},
- {"3.10.6", [{restart_application, ssl}]},
- {"3.10.8", [{restart_application, ssl}]},
- {"3.10.9", [{restart_application, ssl}]}
+ {"4.0.1", [{restart_application, ssl}]}
]}.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 12dffb413c..7e5929d708 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -190,7 +190,8 @@ transport_accept(#sslsocket{} = ListenSocket, Timeout) ->
%%--------------------------------------------------------------------
-spec ssl_accept(#sslsocket{}) -> {ok, #sslsocket{}} | {error, reason()}.
--spec ssl_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} | {error, reason()}.
+-spec ssl_accept(#sslsocket{}, list() | timeout()) -> {ok, #sslsocket{}} | {error, reason()}.
+-spec ssl_accept(port(), list(), timeout()) -> {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on a ssl listen socket. e.i. performs
%% ssl handshake.
@@ -463,11 +464,102 @@ versions() ->
%%---------------------------------------------------------------
-spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
%%
-%% Description:
+%% Description: Initiates a renegotiation.
%%--------------------------------------------------------------------
renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) ->
ssl_connection:renegotiation(Pid).
+%%---------------------------------------------------------------
+-spec format_error({error, term()}) -> list().
+%%
+%% Description: Creates error string.
+%%--------------------------------------------------------------------
+format_error({error, Reason}) ->
+ format_error(Reason);
+format_error(Reason) when is_list(Reason) ->
+ Reason;
+format_error(closed) ->
+ "The connection is closed";
+format_error(ecacertfile) ->
+ "Own CA certificate file is invalid.";
+format_error(ecertfile) ->
+ "Own certificate file is invalid.";
+format_error(ekeyfile) ->
+ "Own private key file is invalid.";
+format_error(esslaccept) ->
+ "Server SSL handshake procedure between client and server failed.";
+format_error(esslconnect) ->
+ "Client SSL handshake procedure between client and server failed.";
+format_error({eoptions, Options}) ->
+ lists:flatten(io_lib:format("Error in options list: ~p~n", [Options]));
+
+%%%%%%%%%%%% START OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+format_error(ebadsocket) ->
+ "Connection not found (internal error).";
+format_error(ebadstate) ->
+ "Connection not in connect state (internal error).";
+format_error(ebrokertype) ->
+ "Wrong broker type (internal error).";
+format_error(echaintoolong) ->
+ "The chain of certificates provided by peer is too long.";
+format_error(ecipher) ->
+ "Own list of specified ciphers is invalid.";
+format_error(ekeymismatch) ->
+ "Own private key does not match own certificate.";
+format_error(enoissuercert) ->
+ "Cannot find certificate of issuer of certificate provided by peer.";
+format_error(enoservercert) ->
+ "Attempt to do accept without having set own certificate.";
+format_error(enotlistener) ->
+ "Attempt to accept on a non-listening socket.";
+format_error(enoproxysocket) ->
+ "No proxy socket found (internal error or max number of file "
+ "descriptors exceeded).";
+format_error(enooptions) ->
+ "List of options is empty.";
+format_error(enotstarted) ->
+ "The SSL application has not been started.";
+format_error(eoptions) ->
+ "Invalid list of options.";
+format_error(epeercert) ->
+ "Certificate provided by peer is in error.";
+format_error(epeercertexpired) ->
+ "Certificate provided by peer has expired.";
+format_error(epeercertinvalid) ->
+ "Certificate provided by peer is invalid.";
+format_error(eselfsignedcert) ->
+ "Certificate provided by peer is self signed.";
+format_error(esslerrssl) ->
+ "SSL protocol failure. Typically because of a fatal alert from peer.";
+format_error(ewantconnect) ->
+ "Protocol wants to connect, which is not supported in this "
+ "version of the SSL application.";
+format_error(ex509lookup) ->
+ "Protocol wants X.509 lookup, which is not supported in this "
+ "version of the SSL application.";
+format_error({badcall, _Call}) ->
+ "Call not recognized for current mode (active or passive) and state "
+ "of socket.";
+format_error({badcast, _Cast}) ->
+ "Call not recognized for current mode (active or passive) and state "
+ "of socket.";
+
+format_error({badinfo, _Info}) ->
+ "Call not recognized for current mode (active or passive) and state "
+ "of socket.";
+
+%%%%%%%%%%%%%%%%%% END OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+format_error(Error) ->
+ case (catch inet:format_error(Error)) of
+ "unkknown POSIX" ++ _ ->
+ no_format(Error);
+ {'EXIT', _} ->
+ no_format(Error);
+ Other ->
+ Other
+ end.
+
%%%--------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
@@ -529,17 +621,19 @@ handle_options(Opts0, _Role) ->
ReuseSessionFun = fun(_, _, _, _) -> true end,
- VerifyNoneFun =
- {fun(_,{bad_cert, unknown_ca}, UserState) ->
+ DefaultVerifyNoneFun =
+ {fun(_,{bad_cert, _}, UserState) ->
{valid, UserState};
- (_,{bad_cert, _} = Reason, _) ->
- {fail, Reason};
(_,{extension, _}, UserState) ->
{unknown, UserState};
(_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
{valid, UserState}
end, []},
+ VerifyNoneFun = handle_option(verify_fun, Opts, DefaultVerifyNoneFun),
+
UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false),
UserVerifyFun = handle_option(verify_fun, Opts, undefined),
CaCerts = handle_option(cacerts, Opts, undefined),
@@ -635,6 +729,8 @@ validate_option(verify_fun, Fun) when is_function(Fun) ->
(_,{extension, _}, UserState) ->
{unknown, UserState};
(_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
{valid, UserState}
end, Fun};
validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) ->
@@ -651,7 +747,7 @@ validate_option(depth, Value) when is_integer(Value),
validate_option(cert, Value) when Value == undefined;
is_binary(Value) ->
Value;
-validate_option(certfile, Value) when is_list(Value) ->
+validate_option(certfile, Value) when Value == undefined; is_list(Value) ->
Value;
validate_option(key, undefined) ->
@@ -794,7 +890,7 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
cipher_suites(Version, Ciphers);
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version),
+ Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(),
case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
[] ->
Supported;
@@ -810,92 +906,6 @@ cipher_suites(Version, Ciphers0) ->
Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:tokens(Ciphers0, ":")],
cipher_suites(Version, Ciphers).
-format_error({error, Reason}) ->
- format_error(Reason);
-format_error(Reason) when is_list(Reason) ->
- Reason;
-format_error(closed) ->
- "The connection is closed";
-format_error(ecacertfile) ->
- "Own CA certificate file is invalid.";
-format_error(ecertfile) ->
- "Own certificate file is invalid.";
-format_error(ekeyfile) ->
- "Own private key file is invalid.";
-format_error(esslaccept) ->
- "Server SSL handshake procedure between client and server failed.";
-format_error(esslconnect) ->
- "Client SSL handshake procedure between client and server failed.";
-format_error({eoptions, Options}) ->
- lists:flatten(io_lib:format("Error in options list: ~p~n", [Options]));
-
-%%%%%%%%%%%% START OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-format_error(ebadsocket) ->
- "Connection not found (internal error).";
-format_error(ebadstate) ->
- "Connection not in connect state (internal error).";
-format_error(ebrokertype) ->
- "Wrong broker type (internal error).";
-format_error(echaintoolong) ->
- "The chain of certificates provided by peer is too long.";
-format_error(ecipher) ->
- "Own list of specified ciphers is invalid.";
-format_error(ekeymismatch) ->
- "Own private key does not match own certificate.";
-format_error(enoissuercert) ->
- "Cannot find certificate of issuer of certificate provided by peer.";
-format_error(enoservercert) ->
- "Attempt to do accept without having set own certificate.";
-format_error(enotlistener) ->
- "Attempt to accept on a non-listening socket.";
-format_error(enoproxysocket) ->
- "No proxy socket found (internal error or max number of file "
- "descriptors exceeded).";
-format_error(enooptions) ->
- "List of options is empty.";
-format_error(enotstarted) ->
- "The SSL application has not been started.";
-format_error(eoptions) ->
- "Invalid list of options.";
-format_error(epeercert) ->
- "Certificate provided by peer is in error.";
-format_error(epeercertexpired) ->
- "Certificate provided by peer has expired.";
-format_error(epeercertinvalid) ->
- "Certificate provided by peer is invalid.";
-format_error(eselfsignedcert) ->
- "Certificate provided by peer is self signed.";
-format_error(esslerrssl) ->
- "SSL protocol failure. Typically because of a fatal alert from peer.";
-format_error(ewantconnect) ->
- "Protocol wants to connect, which is not supported in this "
- "version of the SSL application.";
-format_error(ex509lookup) ->
- "Protocol wants X.509 lookup, which is not supported in this "
- "version of the SSL application.";
-format_error({badcall, _Call}) ->
- "Call not recognized for current mode (active or passive) and state "
- "of socket.";
-format_error({badcast, _Cast}) ->
- "Call not recognized for current mode (active or passive) and state "
- "of socket.";
-
-format_error({badinfo, _Info}) ->
- "Call not recognized for current mode (active or passive) and state "
- "of socket.";
-
-%%%%%%%%%%%%%%%%%% END OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-format_error(Error) ->
- case (catch inet:format_error(Error)) of
- "unkknown POSIX" ++ _ ->
- no_format(Error);
- {'EXIT', _} ->
- no_format(Error);
- Other ->
- Other
- end.
-
no_format(Error) ->
lists:flatten(io_lib:format("No format string for error: \"~p\" available.", [Error])).
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 206024315e..8c0c2bfa5d 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -28,7 +28,6 @@
-include("ssl_handshake.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
--include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([trusted_cert_and_path/2,
@@ -57,30 +56,32 @@
trusted_cert_and_path(CertChain, CertDbRef) ->
Path = [Cert | _] = lists:reverse(CertChain),
OtpCert = public_key:pkix_decode_cert(Cert, otp),
- IssuerID =
+ SignedAndIssuerID =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
{ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self),
- IssuerId;
+ {self, IssuerId};
false ->
case public_key:pkix_issuer_id(OtpCert, other) of
{ok, IssuerId} ->
- IssuerId;
+ {other, IssuerId};
{error, issuer_not_found} ->
case find_issuer(OtpCert, no_candidate) of
{ok, IssuerId} ->
- IssuerId;
+ {other, IssuerId};
Other ->
Other
end
end
end,
- case IssuerID of
+ case SignedAndIssuerID of
{error, issuer_not_found} ->
%% The root CA was not sent and can not be found.
{unknown_ca, Path};
- {SerialNr, Issuer} ->
+ {self, _} when length(Path) == 1 ->
+ {selfsigned_peer, Path};
+ {_ ,{SerialNr, Issuer}} ->
case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of
{ok, {BinCert,_}} ->
{BinCert, Path};
@@ -110,9 +111,10 @@ file_to_certificats(File) ->
{ok, List} = ssl_manager:cache_pem_file(File),
[Bin || {'Certificate', Bin, not_encrypted} <- List].
%%--------------------------------------------------------------------
--spec validate_extension(term(), #'Extension'{}, term()) -> {valid, term()} |
- {fail, tuple()} |
- {unknown, term()}.
+-spec validate_extension(term(), #'Extension'{} | {bad_cert, atom()} | valid,
+ term()) -> {valid, term()} |
+ {fail, tuple()} |
+ {unknown, term()}.
%%
%% Description: Validates ssl/tls specific extensions
%%--------------------------------------------------------------------
@@ -129,6 +131,8 @@ validate_extension(_, {bad_cert, _} = Reason, _) ->
validate_extension(_, {extension, _}, Role) ->
{unknown, Role};
validate_extension(_, valid, Role) ->
+ {valid, Role};
+validate_extension(_, valid_peer, Role) ->
{valid, Role}.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index 86477f369d..2a5a7f3394 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -216,9 +216,15 @@ add_certs_from_file(File, Ref, CertsDb) ->
[Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries].
add_certs(Cert, Ref, CertsDb) ->
- ErlCert = public_key:pkix_decode_cert(Cert, otp),
- TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
- SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
- Issuer = public_key:pkix_normalize_name(
- TBSCertificate#'OTPTBSCertificate'.issuer),
- insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb).
+ try ErlCert = public_key:pkix_decode_cert(Cert, otp),
+ TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
+ SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
+ Issuer = public_key:pkix_normalize_name(
+ TBSCertificate#'OTPTBSCertificate'.issuer),
+ insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb)
+ catch
+ error:_ ->
+ Report = io_lib:format("SSL WARNING: Ignoring a CA cert as "
+ "it could not be correctly decoded.~n", []),
+ error_logger:info_report(Report)
+ end.
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 8230149304..72f02a4362 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -29,12 +29,11 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
--include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([security_parameters/2, suite_definition/1,
decipher/5, cipher/4,
- suite/1, suites/1,
+ suite/1, suites/1, anonymous_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2]).
-compile(inline).
@@ -75,20 +74,12 @@ cipher(?RC4, CipherState, Mac, Fragment) ->
S -> S
end,
GenStreamCipherList = [Fragment, Mac],
-
- ?DBG_HEX(GenStreamCipherList),
- ?DBG_HEX(State0),
{State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList),
- ?DBG_HEX(T),
{T, CipherState#cipher_state{state = State1}};
cipher(?DES, CipherState, Mac, Fragment) ->
block_cipher(fun(Key, IV, T) ->
crypto:des_cbc_encrypt(Key, IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment);
-%% cipher(?DES40, CipherState, Mac, Fragment) ->
-%% block_cipher(fun(Key, IV, T) ->
-%% crypto:des_cbc_encrypt(Key, IV, T)
-%% end, block_size(des_cbc), CipherState, Mac, Fragment);
cipher(?'3DES', CipherState, Mac, Fragment) ->
block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
crypto:des3_cbc_encrypt(K1, K2, K3, IV, T)
@@ -109,11 +100,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1,
{PaddingLength, Padding} = get_padding(TotSz, BlockSz),
L = [Fragment, Mac, PaddingLength, Padding],
- ?DBG_HEX(Key),
- ?DBG_HEX(IV),
- ?DBG_HEX(L),
T = Fun(Key, IV, L),
- ?DBG_HEX(T),
NextIV = next_iv(T, IV),
{T, CS0#cipher_state{iv=NextIV}}.
@@ -127,26 +114,29 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
decipher(?RC4, HashSz, CipherState, Fragment, _) ->
- ?DBG_TERM(CipherState#cipher_state.key),
State0 = case CipherState#cipher_state.state of
undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
S -> S
end,
- ?DBG_HEX(State0),
- ?DBG_HEX(Fragment),
- {State1, T} = crypto:rc4_encrypt_with_state(State0, Fragment),
- ?DBG_HEX(T),
- GSC = generic_stream_cipher_from_bin(T, HashSz),
- #generic_stream_cipher{content=Content, mac=Mac} = GSC,
- {Content, Mac, CipherState#cipher_state{state=State1}};
+ try crypto:rc4_encrypt_with_state(State0, Fragment) of
+ {State, Text} ->
+ GSC = generic_stream_cipher_from_bin(Text, HashSz),
+ #generic_stream_cipher{content = Content, mac = Mac} = GSC,
+ {Content, Mac, CipherState#cipher_state{state = State}}
+ catch
+ _:_ ->
+ %% This is a DECRYPTION_FAILED but
+ %% "differentiating between bad_record_mac and decryption_failed
+ %% alerts may permit certain attacks against CBC mode as used in
+ %% TLS [CBCATT]. It is preferable to uniformly use the
+ %% bad_record_mac alert to hide the specific type of the error."
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+
decipher(?DES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) ->
crypto:des_cbc_decrypt(Key, IV, T)
end, CipherState, HashSz, Fragment, Version);
-%% decipher(?DES40, HashSz, CipherState, Fragment, Version) ->
-%% block_decipher(fun(Key, IV, T) ->
-%% crypto:des_cbc_decrypt(Key, IV, T)
-%% end, CipherState, HashSz, Fragment, Version);
decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
crypto:des3_cbc_decrypt(K1, K2, K3, IV, T)
@@ -164,22 +154,27 @@ decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
HashSz, Fragment, Version) ->
- ?DBG_HEX(Key),
- ?DBG_HEX(IV),
- ?DBG_HEX(Fragment),
- T = Fun(Key, IV, Fragment),
- ?DBG_HEX(T),
- GBC = generic_block_cipher_from_bin(T, HashSz),
- case is_correct_padding(GBC, Version) of
- true ->
- Content = GBC#generic_block_cipher.content,
- Mac = GBC#generic_block_cipher.mac,
- CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)},
- {Content, Mac, CipherState1};
- false ->
+ try Fun(Key, IV, Fragment) of
+ Text ->
+ GBC = generic_block_cipher_from_bin(Text, HashSz),
+ case is_correct_padding(GBC, Version) of
+ true ->
+ Content = GBC#generic_block_cipher.content,
+ Mac = GBC#generic_block_cipher.mac,
+ CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)},
+ {Content, Mac, CipherState1};
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end
+ catch
+ _:_ ->
+ %% This is a DECRYPTION_FAILED but
+ %% "differentiating between bad_record_mac and decryption_failed
+ %% alerts may permit certain attacks against CBC mode as used in
+ %% TLS [CBCATT]. It is preferable to uniformly use the
+ %% bad_record_mac alert to hide the specific type of the error."
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end.
-
%%--------------------------------------------------------------------
-spec suites(tls_version()) -> [cipher_suite()].
%%
@@ -191,6 +186,19 @@ suites({3, N}) when N == 1; N == 2 ->
ssl_tls1:suites().
%%--------------------------------------------------------------------
+-spec anonymous_suites() -> [cipher_suite()].
+%%
+%% Description: Returns a list of the anonymous cipher suites, only supported
+%% if explicitly set by user. Intended only for testing.
+%%--------------------------------------------------------------------
+anonymous_suites() ->
+ [?TLS_DH_anon_WITH_RC4_128_MD5,
+ ?TLS_DH_anon_WITH_DES_CBC_SHA,
+ ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA].
+
+%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
%%
%% Description: Return erlang cipher suite definition.
@@ -235,7 +243,20 @@ suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
{dhe_dss, aes_256_cbc, sha};
suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
- {dhe_rsa, aes_256_cbc, sha}.
+ {dhe_rsa, aes_256_cbc, sha};
+
+%%% DH-ANON deprecated by TLS spec and not available
+%%% by default, but good for testing purposes.
+suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) ->
+ {dh_anon, rc4_128, md5};
+suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) ->
+ {dh_anon, des_cbc, sha};
+suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ {dh_anon, '3des_ede_cbc', sha};
+suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) ->
+ {dh_anon, aes_128_cbc, sha};
+suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
+ {dh_anon, aes_256_cbc, sha}.
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -266,12 +287,12 @@ suite({dhe_rsa, des_cbc, sha}) ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
suite({dhe_rsa, '3des_ede_cbc', sha}) ->
?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
-%% suite({dh_anon, rc4_128, md5}) ->
-%% ?TLS_DH_anon_WITH_RC4_128_MD5;
-%% suite({dh_anon, des40_cbc, sha}) ->
-%% ?TLS_DH_anon_WITH_DES_CBC_SHA;
-%% suite({dh_anon, '3des_ede_cbc', sha}) ->
-%% ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+suite({dh_anon, rc4_128, md5}) ->
+ ?TLS_DH_anon_WITH_RC4_128_MD5;
+suite({dh_anon, des_cbc, sha}) ->
+ ?TLS_DH_anon_WITH_DES_CBC_SHA;
+suite({dh_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
%%% TSL V1.1 AES suites
suite({rsa, aes_128_cbc, sha}) ->
@@ -280,16 +301,16 @@ suite({dhe_dss, aes_128_cbc, sha}) ->
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
suite({dhe_rsa, aes_128_cbc, sha}) ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
-%% suite({dh_anon, aes_128_cbc, sha}) ->
-%% ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
+suite({dh_anon, aes_128_cbc, sha}) ->
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
suite({rsa, aes_256_cbc, sha}) ->
?TLS_RSA_WITH_AES_256_CBC_SHA;
suite({dhe_dss, aes_256_cbc, sha}) ->
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
suite({dhe_rsa, aes_256_cbc, sha}) ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA.
-%% suite({dh_anon, aes_256_cbc, sha}) ->
-%% ?TLS_DH_anon_WITH_AES_256_CBC_SHA.
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+suite({dh_anon, aes_256_cbc, sha}) ->
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -390,8 +411,6 @@ bulk_cipher_algorithm(null) ->
%% ?IDEA;
bulk_cipher_algorithm(rc4_128) ->
?RC4;
-%% bulk_cipher_algorithm(des40_cbc) ->
-%% ?DES40;
bulk_cipher_algorithm(des_cbc) ->
?DES;
bulk_cipher_algorithm('3des_ede_cbc') ->
@@ -405,7 +424,6 @@ type(Cipher) when Cipher == null;
?STREAM;
type(Cipher) when Cipher == idea_cbc;
- Cipher == des40_cbc;
Cipher == des_cbc;
Cipher == '3des_ede_cbc';
Cipher == aes_128_cbc;
@@ -417,8 +435,6 @@ key_material(null) ->
key_material(Cipher) when Cipher == idea_cbc;
Cipher == rc4_128 ->
16;
-%%key_material(des40_cbc) ->
-%% 5;
key_material(des_cbc) ->
8;
key_material('3des_ede_cbc') ->
@@ -433,8 +449,7 @@ expanded_key_material(null) ->
expanded_key_material(Cipher) when Cipher == idea_cbc;
Cipher == rc4_128 ->
16;
-expanded_key_material(Cipher) when Cipher == des_cbc;
- Cipher == des40_cbc ->
+expanded_key_material(Cipher) when Cipher == des_cbc ->
8;
expanded_key_material('3des_ede_cbc') ->
24;
@@ -445,8 +460,6 @@ expanded_key_material(Cipher) when Cipher == aes_128_cbc;
effective_key_bits(null) ->
0;
-%%effective_key_bits(des40_cbc) ->
-%% 40;
effective_key_bits(des_cbc) ->
56;
effective_key_bits(Cipher) when Cipher == idea_cbc;
@@ -465,7 +478,6 @@ iv_size(Cipher) ->
block_size(Cipher).
block_size(Cipher) when Cipher == idea_cbc;
- Cipher == des40_cbc;
Cipher == des_cbc;
Cipher == '3des_ede_cbc' ->
8;
@@ -580,5 +592,3 @@ filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) ->
false ->
CipherSuits -- RsaSuites
end.
-
-
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index c94199c336..6c9ac65b64 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -29,7 +29,6 @@
-behaviour(gen_fsm).
--include("ssl_debug.hrl").
-include("ssl_handshake.hrl").
-include("ssl_alert.hrl").
-include("ssl_record.hrl").
@@ -75,7 +74,7 @@
session, % #session{} from ssl_handshake.hrl
session_cache, %
session_cache_cb, %
- negotiated_version, % #protocol_version{}
+ negotiated_version, % tls_version()
supported_protocol_versions, % [atom()]
client_certificate_requested = false,
key_algorithm, % atom as defined by cipher_suite
@@ -374,7 +373,7 @@ hello(#server_hello{cipher_suite = CipherSuite,
case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
{Version, NewId, ConnectionStates} ->
- {KeyAlgorithm, _, _} =
+ {KeyAlgorithm, _, _} =
ssl_cipher:suite_definition(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
@@ -512,7 +511,7 @@ certify(#certificate{} = Cert,
certify(#server_key_exchange{} = KeyExchangeMsg,
#state{role = client, negotiated_version = Version,
key_algorithm = Alg} = State0)
- when Alg == dhe_dss; Alg == dhe_rsa ->
+ when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -613,25 +612,10 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
#state{negotiated_version = Version,
diffie_hellman_params = #'DHParameter'{prime = P,
base = G},
- diffie_hellman_keys = {_, ServerDhPrivateKey},
- role = Role,
- session = Session,
- connection_states = ConnectionStates0} = State0) ->
-
- PMpint = crypto:mpint(P),
- GMpint = crypto:mpint(G),
- PremasterSecret = crypto:dh_compute_key(mpint_binary(ClientPublicDhKey),
- ServerDhPrivateKey,
- [PMpint, GMpint]),
-
- case ssl_handshake:master_secret(Version, PremasterSecret,
- ConnectionStates0, Role) of
- {MasterSecret, ConnectionStates} ->
- State1 = State0#state{session =
- Session#session{master_secret
- = MasterSecret},
- connection_states = ConnectionStates},
+ diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
+ case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
{Record, State} = next_record(State1),
next_state(cipher, Record, State);
#alert{} = Alert ->
@@ -653,12 +637,10 @@ cipher(#certificate_verify{signature = Signature},
public_key_info = PublicKeyInfo,
negotiated_version = Version,
session = #session{master_secret = MasterSecret},
- key_algorithm = Algorithm,
tls_handshake_hashes = Hashes
} = State0) ->
case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
- Version, MasterSecret,
- Algorithm, Hashes) of
+ Version, MasterSecret, Hashes) of
valid ->
{Record, State} = next_record(State0),
next_state(cipher, Record, State);
@@ -984,15 +966,14 @@ handle_info(Msg, StateName, State) ->
%% necessary cleaning up. When it returns, the gen_fsm terminates with
%% Reason. The return value is ignored.
%%--------------------------------------------------------------------
-terminate(_Reason, connection, #state{negotiated_version = Version,
+terminate(Reason, connection, #state{negotiated_version = Version,
connection_states = ConnectionStates,
transport_cb = Transport,
socket = Socket, send_queue = SendQueue,
renegotiation = Renegotiate}) ->
notify_senders(SendQueue),
notify_renegotiater(Renegotiate),
- {BinAlert, _} = encode_alert(?ALERT_REC(?WARNING,?CLOSE_NOTIFY),
- Version, ConnectionStates),
+ BinAlert = terminate_alert(Reason, Version, ConnectionStates),
Transport:send(Socket, BinAlert),
workaround_transport_delivery_problems(Socket, Transport),
Transport:close(Socket);
@@ -1058,6 +1039,8 @@ init_certificates(#ssl_options{cacerts = CaCerts,
end,
init_certificates(Cert, CertDbRef, CacheRef, CertFile, Role).
+init_certificates(undefined, CertDbRef, CacheRef, "", _) ->
+ {ok, CertDbRef, CacheRef, undefined};
init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) ->
try
@@ -1068,18 +1051,18 @@ init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) ->
end;
init_certificates(undefined, CertDbRef, CacheRef, CertFile, server) ->
- try
+ try
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
{ok, CertDbRef, CacheRef, OwnCert}
- catch
- Error:Reason ->
- handle_file_error(?LINE, Error, Reason, CertFile, ecertfile,
- erlang:get_stacktrace())
- end;
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason, CertFile, ecertfile,
+ erlang:get_stacktrace())
+ end;
init_certificates(Cert, CertDbRef, CacheRef, _, _) ->
{ok, CertDbRef, CacheRef, Cert}.
-init_private_key(undefined, "", _Password, client) ->
+init_private_key(undefined, "", _Password, _Client) ->
undefined;
init_private_key(undefined, KeyFile, Password, _) ->
try
@@ -1182,16 +1165,15 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
negotiated_version = Version,
own_cert = OwnCert,
socket = Socket,
- key_algorithm = KeyAlg,
private_key = PrivateKey,
session = #session{master_secret = MasterSecret},
tls_handshake_hashes = Hashes0} = State) ->
+
case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
- Version, KeyAlg,
- PrivateKey, Hashes0) of
+ Version, PrivateKey, Hashes0) of
#certificate_verify{} = Verified ->
{BinVerified, ConnectionStates1, Hashes1} =
- encode_handshake(Verified, KeyAlg, Version,
+ encode_handshake(Verified, Version,
ConnectionStates0, Hashes0),
Transport:send(Socket, BinVerified),
State#state{connection_states = ConnectionStates1,
@@ -1340,15 +1322,17 @@ server_hello_done(#state{transport_cb = Transport,
Transport:send(Socket, BinHelloDone),
State#state{connection_states = NewConnectionStates,
tls_handshake_hashes = NewHashes}.
-
-certify_server(#state{transport_cb = Transport,
- socket = Socket,
- negotiated_version = Version,
- connection_states = ConnectionStates,
- tls_handshake_hashes = Hashes,
- cert_db_ref = CertDbRef,
- own_cert = OwnCert} = State) ->
+certify_server(#state{key_algorithm = dh_anon} = State) ->
+ State;
+
+certify_server(#state{transport_cb = Transport,
+ socket = Socket,
+ negotiated_version = Version,
+ connection_states = ConnectionStates,
+ tls_handshake_hashes = Hashes,
+ cert_db_ref = CertDbRef,
+ own_cert = OwnCert} = State) ->
case ssl_handshake:certificate(OwnCert, CertDbRef, server) of
CertMsg = #certificate{} ->
{BinCertMsg, NewConnectionStates, NewHashes} =
@@ -1373,7 +1357,8 @@ key_exchange(#state{role = server, key_algorithm = Algo,
transport_cb = Transport
} = State)
when Algo == dhe_dss;
- Algo == dhe_rsa ->
+ Algo == dhe_rsa;
+ Algo == dh_anon ->
Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
ConnectionState =
@@ -1392,11 +1377,6 @@ key_exchange(#state{role = server, key_algorithm = Algo,
diffie_hellman_keys = Keys,
tls_handshake_hashes = Hashes1};
-
-%% key_algorithm = dh_anon is not supported. Should be by default disabled
-%% if support is implemented and then we need a key_exchange clause for it
-%% here.
-
key_exchange(#state{role = client,
connection_states = ConnectionStates0,
key_algorithm = rsa,
@@ -1419,7 +1399,8 @@ key_exchange(#state{role = client,
socket = Socket, transport_cb = Transport,
tls_handshake_hashes = Hashes0} = State)
when Algorithm == dhe_dss;
- Algorithm == dhe_rsa ->
+ Algorithm == dhe_rsa;
+ Algorithm == dh_anon ->
Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}),
{BinMsg, ConnectionStates1, Hashes1} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
@@ -1497,23 +1478,30 @@ save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbrev
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
ssl_record:set_server_verify_data(current_write, Data, ConnectionStates).
+handle_server_key(#server_key_exchange{params =
+ #server_dh_params{dh_p = P,
+ dh_g = G,
+ dh_y = ServerPublicDhKey},
+ signed_params = <<>>},
+ #state{key_algorithm = dh_anon} = State) ->
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+
handle_server_key(
#server_key_exchange{params =
#server_dh_params{dh_p = P,
dh_g = G,
dh_y = ServerPublicDhKey},
signed_params = Signed},
- #state{session = Session, negotiated_version = Version, role = Role,
- public_key_info = PubKeyInfo,
+ #state{public_key_info = PubKeyInfo,
key_algorithm = KeyAlgo,
- connection_states = ConnectionStates0} = State) ->
+ connection_states = ConnectionStates} = State) ->
PLen = size(P),
GLen = size(G),
YLen = size(ServerPublicDhKey),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
@@ -1527,29 +1515,11 @@ handle_server_key(
case verify_dh_params(Signed, Hash, PubKeyInfo) of
true ->
- PMpint = mpint_binary(P),
- GMpint = mpint_binary(G),
- Keys = {_, ClientDhPrivateKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- PremasterSecret =
- crypto:dh_compute_key(mpint_binary(ServerPublicDhKey),
- ClientDhPrivateKey, [PMpint, GMpint]),
- case ssl_handshake:master_secret(Version, PremasterSecret,
- ConnectionStates0, Role) of
- {MasterSecret, ConnectionStates} ->
- State#state{diffie_hellman_keys = Keys,
- session =
- Session#session{master_secret
- = MasterSecret},
- connection_states = ConnectionStates};
- #alert{} = Alert ->
- Alert
- end;
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
false ->
- ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)
+ ?ALERT_REC(?FATAL, ?DECRYPT_ERROR)
end.
-
verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) ->
case public_key:decrypt_public(Signed, PubKey,
[{rsa_pad, rsa_pkcs1_padding}]) of
@@ -1561,6 +1531,30 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) ->
verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) ->
public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}).
+dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
+ PMpint = mpint_binary(Prime),
+ GMpint = mpint_binary(Base),
+ Keys = {_, PrivateDhKey} =
+ crypto:dh_generate_key([PMpint,GMpint]),
+ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+
+dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ #state{session = Session,
+ negotiated_version = Version, role = Role,
+ connection_states = ConnectionStates0} = State) ->
+ PremasterSecret =
+ crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
+ [PMpint, GMpint]),
+ case ssl_handshake:master_secret(Version, PremasterSecret,
+ ConnectionStates0, Role) of
+ {MasterSecret, ConnectionStates} ->
+ State#state{
+ session =
+ Session#session{master_secret = MasterSecret},
+ connection_states = ConnectionStates};
+ #alert{} = Alert ->
+ Alert
+ end.
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
@@ -1578,20 +1572,13 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0
tls_handshake_hashes =
Hashes})).
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
- ?DBG_TERM(Alert),
ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
- ?DBG_TERM(#change_cipher_spec{}),
ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
-encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) ->
- encode_handshake(HandshakeRec, null, Version,
- ConnectionStates, Hashes).
-
-encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) ->
- ?DBG_TERM(HandshakeRec),
- Frag = ssl_handshake:encode_handshake(HandshakeRec, Version, SigAlg),
+encode_handshake(HandshakeRec, Version, ConnectionStates0, Hashes0) ->
+ Frag = ssl_handshake:encode_handshake(HandshakeRec, Version),
Hashes1 = ssl_handshake:update_hashes(Hashes0, Frag),
{E, ConnectionStates1} =
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
@@ -1848,7 +1835,6 @@ next_state(StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State
next_state(StateName, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
_ChangeCipher,
#state{connection_states = ConnectionStates0} = State0) ->
- ?DBG_TERM(_ChangeCipher),
ConnectionStates1 =
ssl_record:activate_pending_connection_state(ConnectionStates0, read),
{Record, State} = next_record(State0#state{connection_states = ConnectionStates1}),
@@ -2179,7 +2165,7 @@ renegotiate(#state{role = server,
negotiated_version = Version,
connection_states = ConnectionStates0} = State0) ->
HelloRequest = ssl_handshake:hello_request(),
- Frag = ssl_handshake:encode_handshake(HelloRequest, Version, null),
+ Frag = ssl_handshake:encode_handshake(HelloRequest, Version),
Hs0 = ssl_handshake:init_hashes(),
{BinMsg, ConnectionStates} =
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
@@ -2199,6 +2185,15 @@ notify_renegotiater({true, From}) when not is_atom(From) ->
notify_renegotiater(_) ->
ok.
+terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown ->
+ {BinAlert, _} = encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+ Version, ConnectionStates),
+ BinAlert;
+terminate_alert(_, Version, ConnectionStates) ->
+ {BinAlert, _} = encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
+ Version, ConnectionStates),
+ BinAlert.
+
workaround_transport_delivery_problems(Socket, Transport) ->
%% Standard trick to try to make sure all
%% data sent to to tcp port is really sent
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 99bc47f04b..c7a1c4965d 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -28,16 +28,15 @@
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
--include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([master_secret/4, client_hello/5, server_hello/4, hello/4,
hello_request/0, certify/6, certificate/3,
- client_certificate_verify/6, certificate_verify/6,
+ client_certificate_verify/5, certificate_verify/5,
certificate_request/2, key_exchange/2, server_key_exchange_hash/2,
finished/4, verify_connection/5, get_tls_handshake/2,
- decode_client_key/3, server_hello_done/0, sig_alg/1,
- encode_handshake/3, init_hashes/0, update_hashes/2,
+ decode_client_key/3, server_hello_done/0,
+ encode_handshake/2, init_hashes/0, update_hashes/2,
decrypt_premaster_secret/2]).
-type tls_handshake() :: #client_hello{} | #server_hello{} |
@@ -237,7 +236,7 @@ certificate(OwnCert, CertDbRef, client) ->
{error, _} ->
%% If no suitable certificate is available, the client
%% SHOULD send a certificate message containing no
- %% certificates. (chapter 7.4.6. rfc 4346)
+ %% certificates. (chapter 7.4.6. RFC 4346)
[]
end,
#certificate{asn1_certificates = Chain};
@@ -252,17 +251,17 @@ certificate(OwnCert, CertDbRef, server) ->
%%--------------------------------------------------------------------
-spec client_certificate_verify(undefined | der_cert(), binary(),
- tls_version(), key_algo(), private_key(),
+ tls_version(), private_key(),
{{binary(), binary()},{binary(), binary()}}) ->
#certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
%%--------------------------------------------------------------------
-client_certificate_verify(undefined, _, _, _, _, _) ->
+client_certificate_verify(undefined, _, _, _, _) ->
ignore;
-client_certificate_verify(_, _, _, _, undefined, _) ->
+client_certificate_verify(_, _, _, undefined, _) ->
ignore;
-client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm,
+client_certificate_verify(OwnCert, MasterSecret, Version,
PrivateKey, {Hashes0, _}) ->
case public_key:pkix_is_fixed_dh_cert(OwnCert) of
true ->
@@ -270,33 +269,30 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm,
false ->
Hashes =
calc_certificate_verify(Version, MasterSecret,
- Algorithm, Hashes0),
+ alg_oid(PrivateKey), Hashes0),
Signed = digitally_signed(Hashes, PrivateKey),
#certificate_verify{signature = Signed}
end.
%%--------------------------------------------------------------------
-%% -spec certificate_verify(binary(), public_key_info(), tls_version(),
-%% binary(), key_algo(),
-%% {_, {binary(), binary()}}) -> valid | #alert{}.
+-spec certificate_verify(binary(), public_key_info(), tls_version(),
+ binary(), {_, {binary(), binary()}}) -> valid | #alert{}.
%%
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
-certificate_verify(Signature, {_, PublicKey, _}, Version,
- MasterSecret, Algorithm, {_, Hashes0})
- when Algorithm == rsa;
- Algorithm == dhe_rsa ->
+certificate_verify(Signature, {?'rsaEncryption'= Algorithm, PublicKey, _}, Version,
+ MasterSecret, {_, Hashes0}) ->
Hashes = calc_certificate_verify(Version, MasterSecret,
Algorithm, Hashes0),
- case public_key:decrypt_public(Signature, PublicKey,
+ case public_key:decrypt_public(Signature, PublicKey,
[{rsa_pad, rsa_pkcs1_padding}]) of
Hashes ->
valid;
_ ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
end;
-certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version,
- MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) ->
+certificate_verify(Signature, {?'id-dsa' = Algorithm, PublicKey, PublicKeyParams}, Version,
+ MasterSecret, {_, Hashes0}) ->
Hashes = calc_certificate_verify(Version, MasterSecret,
Algorithm, Hashes0),
case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of
@@ -355,15 +351,22 @@ key_exchange(server, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
YLen = byte_size(PublicKey),
ServerDHParams = #server_dh_params{dh_p = PBin,
dh_g = GBin, dh_y = PublicKey},
- Hash =
- server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary,
- ServerRandom/binary,
- ?UINT16(PLen), PBin/binary,
- ?UINT16(GLen), GBin/binary,
- ?UINT16(YLen), PublicKey/binary>>),
- Signed = digitally_signed(Hash, PrivateKey),
- #server_key_exchange{params = ServerDHParams,
- signed_params = Signed}.
+
+ case KeyAlgo of
+ dh_anon ->
+ #server_key_exchange{params = ServerDHParams,
+ signed_params = <<>>};
+ _ ->
+ Hash =
+ server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary,
+ ServerRandom/binary,
+ ?UINT16(PLen), PBin/binary,
+ ?UINT16(GLen), GBin/binary,
+ ?UINT16(YLen), PublicKey/binary>>),
+ Signed = digitally_signed(Hash, PrivateKey),
+ #server_key_exchange{params = ServerDHParams,
+ signed_params = Signed}
+ end.
%%--------------------------------------------------------------------
-spec master_secret(tls_version(), #session{} | binary(), #connection_states{},
@@ -424,13 +427,11 @@ finished(Version, Role, MasterSecret, {Hashes, _}) -> % use the current hashes
verify_connection(Version, #finished{verify_data = Data},
Role, MasterSecret, {_, {MD5, SHA}}) ->
%% use the previous hashes
- ?DBG_HEX(crypto:md5_final(MD5)),
- ?DBG_HEX(crypto:sha_final(SHA)),
case calc_finished(Version, Role, MasterSecret, {MD5, SHA}) of
Data ->
verified;
- _E ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+ _ ->
+ ?ALERT_REC(?FATAL, ?DECRYPT_ERROR)
end.
%%--------------------------------------------------------------------
-spec server_hello_done() -> #server_hello_done{}.
@@ -441,13 +442,12 @@ server_hello_done() ->
#server_hello_done{}.
%%--------------------------------------------------------------------
--spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> iolist().
+-spec encode_handshake(tls_handshake(), tls_version()) -> iolist().
%%
%% Description: Encode a handshake packet to binary
%%--------------------------------------------------------------------
-encode_handshake(Package, Version, KeyAlg) ->
- SigAlg = sig_alg(KeyAlg),
- {MsgType, Bin} = enc_hs(Package, Version, SigAlg),
+encode_handshake(Package, Version) ->
+ {MsgType, Bin} = enc_hs(Package, Version),
Len = byte_size(Bin),
[MsgType, ?uint24(Len), Bin].
@@ -474,6 +474,70 @@ decode_client_key(ClientKey, Type, Version) ->
dec_client_key(ClientKey, key_exchange_alg(Type), Version).
%%--------------------------------------------------------------------
+-spec init_hashes() ->{{binary(), binary()}, {binary(), binary()}}.
+
+%%
+%% Description: Calls crypto hash (md5 and sha) init functions to
+%% initalize the hash context.
+%%--------------------------------------------------------------------
+init_hashes() ->
+ T = {crypto:md5_init(), crypto:sha_init()},
+ {T, T}.
+
+%%--------------------------------------------------------------------
+-spec update_hashes({{binary(), binary()}, {binary(), binary()}}, Data ::term()) ->
+ {{binary(), binary()}, {binary(), binary()}}.
+%%
+%% Description: Calls crypto hash (md5 and sha) update functions to
+%% update the hash context with Data.
+%%--------------------------------------------------------------------
+update_hashes(Hashes, % special-case SSL2 client hello
+ <<?CLIENT_HELLO, ?UINT24(_), ?BYTE(Major), ?BYTE(Minor),
+ ?UINT16(CSLength), ?UINT16(0),
+ ?UINT16(CDLength),
+ CipherSuites:CSLength/binary,
+ ChallengeData:CDLength/binary>>) ->
+ update_hashes(Hashes,
+ <<?CLIENT_HELLO, ?BYTE(Major), ?BYTE(Minor),
+ ?UINT16(CSLength), ?UINT16(0),
+ ?UINT16(CDLength),
+ CipherSuites:CSLength/binary,
+ ChallengeData:CDLength/binary>>);
+update_hashes({{MD50, SHA0}, _Prev}, Data) ->
+ {MD51, SHA1} = {crypto:md5_update(MD50, Data),
+ crypto:sha_update(SHA0, Data)},
+ {{MD51, SHA1}, {MD50, SHA0}}.
+
+%%--------------------------------------------------------------------
+-spec decrypt_premaster_secret(binary(), #'RSAPrivateKey'{}) -> binary().
+
+%%
+%% Description: Public key decryption using the private key.
+%%--------------------------------------------------------------------
+decrypt_premaster_secret(Secret, RSAPrivateKey) ->
+ try public_key:decrypt_private(Secret, RSAPrivateKey,
+ [{rsa_pad, rsa_pkcs1_padding}])
+ catch
+ _:_ ->
+ throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR))
+ end.
+
+%%--------------------------------------------------------------------
+-spec server_key_exchange_hash(rsa | dhe_rsa| dhe_dss | dh_anon, binary()) -> binary().
+
+%%
+%% Description: Calculate server key exchange hash
+%%--------------------------------------------------------------------
+server_key_exchange_hash(Algorithm, Value) when Algorithm == rsa;
+ Algorithm == dhe_rsa ->
+ MD5 = crypto:md5(Value),
+ SHA = crypto:sha(Value),
+ <<MD5/binary, SHA/binary>>;
+
+server_key_exchange_hash(dhe_dss, Value) ->
+ crypto:sha(Value).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
@@ -496,6 +560,8 @@ path_validation_alert({bad_cert, unknown_critical_extension}) ->
?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE);
path_validation_alert({bad_cert, cert_revoked}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED);
+path_validation_alert({bad_cert, selfsigned_peer}) ->
+ ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
path_validation_alert({bad_cert, unknown_ca}) ->
?ALERT_REC(?FATAL, ?UNKNOWN_CA);
path_validation_alert(_) ->
@@ -710,8 +776,7 @@ master_secret(Version, MasterSecret, #security_parameters{
ServerWriteKey, ClientIV, ServerIV} =
setup_keys(Version, MasterSecret, ServerRandom,
ClientRandom, HashSize, KML, EKML, IVS),
- ?DBG_HEX(ClientWriteKey),
- ?DBG_HEX(ClientIV),
+
ConnStates1 = ssl_record:set_master_secret(MasterSecret, ConnectionStates),
ConnStates2 =
ssl_record:set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret,
@@ -735,8 +800,6 @@ dec_hs(?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor),
?UINT16(CDLength),
CipherSuites:CSLength/binary,
ChallengeData:CDLength/binary>>) ->
- ?DBG_HEX(CipherSuites),
- ?DBG_HEX(CipherSuites),
#client_hello{client_version = {Major, Minor},
random = ssl_ssl2:client_random(ChallengeData, CDLength),
session_id = 0,
@@ -792,6 +855,13 @@ dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
?UINT16(GLen), G:GLen/binary,
?UINT16(YLen), Y:YLen/binary,
+ ?UINT16(0)>>) -> %% May happen if key_algorithm is dh_anon
+ #server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
+ dh_y = Y},
+ signed_params = <<>>};
+dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?UINT16(YLen), Y:YLen/binary,
?UINT16(Len), Sig:Len/binary>>) ->
#server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
dh_y = Y},
@@ -859,14 +929,6 @@ encrypted_premaster_secret(Secret, RSAPublicKey) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE))
end.
-decrypt_premaster_secret(Secret, RSAPrivateKey) ->
- try public_key:decrypt_private(Secret, RSAPrivateKey,
- [{rsa_pad, rsa_pkcs1_padding}])
- catch
- _:_ ->
- throw(?ALERT_REC(?FATAL, ?DECRYPTION_FAILED))
- end.
-
%% encode/decode stream of certificate data to/from list of certificate data
certs_to_list(ASN1Certs) ->
certs_to_list(ASN1Certs, []).
@@ -882,14 +944,14 @@ certs_from_list(ACList) ->
<<?UINT24(CertLen), Cert/binary>>
end || Cert <- ACList]).
-enc_hs(#hello_request{}, _Version, _) ->
+enc_hs(#hello_request{}, _Version) ->
{?HELLO_REQUEST, <<>>};
enc_hs(#client_hello{client_version = {Major, Minor},
random = Random,
session_id = SessionID,
cipher_suites = CipherSuites,
compression_methods = CompMethods,
- renegotiation_info = RenegotiationInfo}, _Version, _) ->
+ renegotiation_info = RenegotiationInfo}, _Version) ->
SIDLength = byte_size(SessionID),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
@@ -907,20 +969,20 @@ enc_hs(#server_hello{server_version = {Major, Minor},
session_id = Session_ID,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
- renegotiation_info = RenegotiationInfo}, _Version, _) ->
+ renegotiation_info = RenegotiationInfo}, _Version) ->
SID_length = byte_size(Session_ID),
Extensions = hello_extensions(RenegotiationInfo),
ExtensionsBin = enc_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
-enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version, _) ->
+enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
{?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>};
enc_hs(#server_key_exchange{params = #server_dh_params{
dh_p = P, dh_g = G, dh_y = Y},
- signed_params = SignedParams}, _Version, _) ->
+ signed_params = SignedParams}, _Version) ->
PLen = byte_size(P),
GLen = byte_size(G),
YLen = byte_size(Y),
@@ -932,21 +994,21 @@ enc_hs(#server_key_exchange{params = #server_dh_params{
};
enc_hs(#certificate_request{certificate_types = CertTypes,
certificate_authorities = CertAuths},
- _Version, _) ->
+ _Version) ->
CertTypesLen = byte_size(CertTypes),
CertAuthsLen = byte_size(CertAuths),
{?CERTIFICATE_REQUEST,
<<?BYTE(CertTypesLen), CertTypes/binary,
?UINT16(CertAuthsLen), CertAuths/binary>>
};
-enc_hs(#server_hello_done{}, _Version, _) ->
+enc_hs(#server_hello_done{}, _Version) ->
{?SERVER_HELLO_DONE, <<>>};
-enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version, _) ->
+enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version) ->
{?CLIENT_KEY_EXCHANGE, enc_cke(ExchangeKeys, Version)};
-enc_hs(#certificate_verify{signature = BinSig}, _, _) ->
+enc_hs(#certificate_verify{signature = BinSig}, _) ->
EncSig = enc_bin_sig(BinSig),
{?CERTIFICATE_VERIFY, EncSig};
-enc_hs(#finished{verify_data = VerifyData}, _Version, _) ->
+enc_hs(#finished{verify_data = VerifyData}, _Version) ->
{?FINISHED, VerifyData}.
enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS},{3, 0}) ->
@@ -985,29 +1047,6 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>).
-init_hashes() ->
- T = {crypto:md5_init(), crypto:sha_init()},
- {T, T}.
-
-update_hashes(Hashes, % special-case SSL2 client hello
- <<?CLIENT_HELLO, ?UINT24(_), ?BYTE(Major), ?BYTE(Minor),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>) ->
- update_hashes(Hashes,
- <<?CLIENT_HELLO, ?BYTE(Major), ?BYTE(Minor),
- ?UINT16(CSLength), ?UINT16(0),
- ?UINT16(CDLength),
- CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>);
-update_hashes({{MD50, SHA0}, _Prev}, Data) ->
- ?DBG_HEX(Data),
- {MD51, SHA1} = {crypto:md5_update(MD50, Data),
- crypto:sha_update(SHA0, Data)},
- ?DBG_HEX(crypto:md5_final(MD51)),
- ?DBG_HEX(crypto:sha_final(SHA1)),
- {{MD51, SHA1}, {MD50, SHA0}}.
from_3bytes(Bin3) ->
from_3bytes(Bin3, []).
@@ -1096,28 +1135,10 @@ calc_certificate_verify({3, N}, _, Algorithm, Hashes)
when N == 1; N == 2 ->
ssl_tls1:certificate_verify(Algorithm, Hashes).
-server_key_exchange_hash(Algorithm, Value) when Algorithm == rsa;
- Algorithm == dhe_rsa ->
- MD5 = crypto:md5(Value),
- SHA = crypto:sha(Value),
- <<MD5/binary, SHA/binary>>;
-
-server_key_exchange_hash(dhe_dss, Value) ->
- crypto:sha(Value).
-
-sig_alg(dh_anon) ->
- ?SIGNATURE_ANONYMOUS;
-sig_alg(Alg) when Alg == dhe_rsa; Alg == rsa ->
- ?SIGNATURE_RSA;
-sig_alg(dhe_dss) ->
- ?SIGNATURE_DSA;
-sig_alg(_) ->
- ?NULL.
-
key_exchange_alg(rsa) ->
?KEY_EXCHANGE_RSA;
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
- Alg == dh_dss; Alg == dh_rsa ->
+ Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
key_exchange_alg(_) ->
?NULL.
@@ -1131,3 +1152,8 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
{unknown, UserState} ->
{unknown, {SslState, UserState}}
end.
+
+alg_oid(#'RSAPrivateKey'{}) ->
+ ?'rsaEncryption';
+alg_oid(#'DSAPrivateKey'{}) ->
+ ?'id-dsa'.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 74fba3786c..68a7802ef2 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -26,6 +26,13 @@
-ifndef(ssl_handshake).
-define(ssl_handshake, true).
+-include_lib("public_key/include/public_key.hrl").
+
+-type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
+-type public_key() :: #'RSAPublicKey'{} | integer().
+-type public_key_params() :: #'Dss-Parms'{} | term().
+-type public_key_info() :: {algo_oid(), public_key(), public_key_params()}.
+
-record(session, {
session_id,
peer_certificate,
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index ddb05e70f6..43a85c2d9d 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -25,6 +25,24 @@
-include_lib("public_key/include/public_key.hrl").
+-type reason() :: term().
+-type reply() :: term().
+-type msg() :: term().
+-type from() :: term().
+-type host() :: string() | tuple().
+-type port_num() :: integer().
+-type session_id() :: 0 | binary().
+-type tls_version() :: {integer(), integer()}.
+-type tls_atom_version() :: sslv3 | tlsv1.
+-type cache_ref() :: term().
+-type certdb_ref() :: term().
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type der_cert() :: binary().
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type issuer() :: tuple().
+-type serialnumber() :: integer().
+-type cert_key() :: {reference(), integer(), issuer()}.
+
%% basic binary constructors
-define(BOOLEAN(X), X:8/unsigned-big-integer).
-define(BYTE(X), X:8/unsigned-big-integer).
@@ -93,28 +111,6 @@
active = true
}).
--type reason() :: term().
--type reply() :: term().
--type msg() :: term().
--type from() :: term().
--type host() :: string() | tuple().
--type port_num() :: integer().
--type session_id() :: 0 | binary().
--type tls_version() :: {integer(), integer()}.
--type tls_atom_version() :: sslv3 | tlsv1.
--type cache_ref() :: term().
--type certdb_ref() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss.
--type enum_algo() :: integer().
--type public_key() :: #'RSAPublicKey'{} | integer().
--type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {enum_algo(), public_key(), public_key_params()}.
--type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
--type issuer() :: tuple().
--type serialnumber() :: integer().
--type cert_key() :: {reference(), integer(), issuer()}.
-
-endif. % -ifdef(ssl_internal).
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 0116466677..3b02d96562 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -122,6 +122,7 @@ server_session_id(Port, SuggestedSessionId, SslOpts) ->
call({server_session_id, Port, SuggestedSessionId, SslOpts}).
%%--------------------------------------------------------------------
+-spec register_session(port_num(), #session{}) -> ok.
-spec register_session(host(), port_num(), #session{}) -> ok.
%%
%% Description: Make the session available for reuse.
@@ -132,6 +133,7 @@ register_session(Host, Port, Session) ->
register_session(Port, Session) ->
cast({register_session, Port, Session}).
%%--------------------------------------------------------------------
+-spec invalidate_session(port_num(), #session{}) -> ok.
-spec invalidate_session(host(), port_num(), #session{}) -> ok.
%%
%% Description: Make the session unavilable for reuse.
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index acd0d49c19..f1c0073965 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -30,7 +30,6 @@
-include("ssl_alert.hrl").
-include("ssl_handshake.hrl").
-include("ssl_cipher.hrl").
--include("ssl_debug.hrl").
%% Connection state handling
-export([init_connection_states/1,
@@ -497,6 +496,66 @@ decode_cipher_text(CipherText, ConnnectionStates0) ->
#alert{} = Alert ->
Alert
end.
+%%--------------------------------------------------------------------
+-spec encode_data(iolist(), tls_version(), #connection_states{}, integer()) ->
+ {iolist(), iolist(), #connection_states{}}.
+%%
+%% Description: Encodes data to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_data(Frag, Version, ConnectionStates, RenegotiateAt)
+ when byte_size(Frag) < (?MAX_PLAIN_TEXT_LENGTH - 2048) ->
+ case encode_plain_text(?APPLICATION_DATA,Version,Frag,ConnectionStates, RenegotiateAt) of
+ {renegotiate, Data} ->
+ {[], Data, ConnectionStates};
+ {Msg, CS} ->
+ {Msg, [], CS}
+ end;
+
+encode_data(Frag, Version, ConnectionStates, RenegotiateAt) when is_binary(Frag) ->
+ Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH - 2048),
+ encode_data(Data, Version, ConnectionStates, RenegotiateAt);
+
+encode_data(Data, Version, ConnectionStates0, RenegotiateAt) when is_list(Data) ->
+ {ConnectionStates, EncodedMsg, NotEncdedData} =
+ lists:foldl(fun(B, {CS0, Encoded, Rest}) ->
+ case encode_plain_text(?APPLICATION_DATA,
+ Version, B, CS0, RenegotiateAt) of
+ {renegotiate, NotEnc} ->
+ {CS0, Encoded, [NotEnc | Rest]};
+ {Enc, CS1} ->
+ {CS1, [Enc | Encoded], Rest}
+ end
+ end, {ConnectionStates0, [], []}, Data),
+ {lists:reverse(EncodedMsg), lists:reverse(NotEncdedData), ConnectionStates}.
+
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), tls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
+%%
+%% Description: Encodes a handshake message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, Version, ConnectionStates) ->
+ encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
+
+%%--------------------------------------------------------------------
+-spec encode_alert_record(#alert{}, tls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
+%%
+%% Description: Encodes an alert message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_alert_record(#alert{level = Level, description = Description},
+ Version, ConnectionStates) ->
+ encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
+ ConnectionStates).
+
+%%--------------------------------------------------------------------
+-spec encode_change_cipher_spec(tls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
+%%
+%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
+%%--------------------------------------------------------------------
+encode_change_cipher_spec(Version, ConnectionStates) ->
+ encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
%%--------------------------------------------------------------------
%%% Internal functions
@@ -550,43 +609,6 @@ split_bin(Bin, ChunkSize, Acc) ->
lists:reverse(Acc, [Bin])
end.
-encode_data(Frag, Version, ConnectionStates, RenegotiateAt)
- when byte_size(Frag) < (?MAX_PLAIN_TEXT_LENGTH - 2048) ->
- case encode_plain_text(?APPLICATION_DATA,Version,Frag,ConnectionStates, RenegotiateAt) of
- {renegotiate, Data} ->
- {[], Data, ConnectionStates};
- {Msg, CS} ->
- {Msg, [], CS}
- end;
-
-encode_data(Frag, Version, ConnectionStates, RenegotiateAt) when is_binary(Frag) ->
- Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH - 2048),
- encode_data(Data, Version, ConnectionStates, RenegotiateAt);
-
-encode_data(Data, Version, ConnectionStates0, RenegotiateAt) when is_list(Data) ->
- {ConnectionStates, EncodedMsg, NotEncdedData} =
- lists:foldl(fun(B, {CS0, Encoded, Rest}) ->
- case encode_plain_text(?APPLICATION_DATA,
- Version, B, CS0, RenegotiateAt) of
- {renegotiate, NotEnc} ->
- {CS0, Encoded, [NotEnc | Rest]};
- {Enc, CS1} ->
- {CS1, [Enc | Encoded], Rest}
- end
- end, {ConnectionStates0, [], []}, Data),
- {lists:reverse(EncodedMsg), lists:reverse(NotEncdedData), ConnectionStates}.
-
-encode_handshake(Frag, Version, ConnectionStates) ->
- encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
-
-encode_alert_record(#alert{level = Level, description = Description},
- Version, ConnectionStates) ->
- encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
- ConnectionStates).
-
-encode_change_cipher_spec(Version, ConnectionStates) ->
- encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
-
encode_plain_text(Type, Version, Data, ConnectionStates, RenegotiateAt) ->
#connection_states{current_write =
#connection_state{sequence_number = Num}} = ConnectionStates,
@@ -626,9 +648,7 @@ cipher(Type, Version, Fragment, CS0) ->
BCA}
}} =
hash_and_bump_seqno(CS0, Type, Version, Length, Fragment),
- ?DBG_HEX(Fragment),
{Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, MacHash, Fragment),
- ?DBG_HEX(Ciphered),
CS2 = CS1#connection_state{cipher_state=CipherS1},
{Ciphered, CS2}.
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index 1add203fb0..c49f9f1e6d 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -25,7 +25,6 @@
-module(ssl_ssl3).
-include("ssl_cipher.hrl").
--include("ssl_debug.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl"). % MD5 and SHA
@@ -41,9 +40,6 @@
-spec master_secret(binary(), binary(), binary()) -> binary().
master_secret(PremasterSecret, ClientRandom, ServerRandom) ->
- ?DBG_HEX(PremasterSecret),
- ?DBG_HEX(ClientRandom),
- ?DBG_HEX(ServerRandom),
%% draft-ietf-tls-ssl-version3-00 - 6.2.2
%% key_block =
%% MD5(master_secret + SHA(`A' + master_secret +
@@ -55,9 +51,8 @@ master_secret(PremasterSecret, ClientRandom, ServerRandom) ->
%% MD5(master_secret + SHA(`CCC' + master_secret +
%% ServerHello.random +
%% ClientHello.random)) + [...];
- B = generate_keyblock(PremasterSecret, ClientRandom, ServerRandom, 48),
- ?DBG_HEX(B),
- B.
+ Block = generate_keyblock(PremasterSecret, ClientRandom, ServerRandom, 48),
+ Block.
-spec finished(client | server, binary(), {binary(), binary()}) -> binary().
@@ -79,10 +74,9 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = handshake_hash(?SHA, MasterSecret, Sender, SHAHash),
<<MD5/binary, SHA/binary>>.
--spec certificate_verify(key_algo(), binary(), {binary(), binary()}) -> binary().
+-spec certificate_verify(OID::tuple(), binary(), {binary(), binary()}) -> binary().
-certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash})
- when Algorithm == rsa; Algorithm == dhe_rsa ->
+certificate_verify(?'rsaEncryption', MasterSecret, {MD5Hash, SHAHash}) ->
%% md5_hash
%% MD5(master_secret + pad_2 +
%% MD5(handshake_messages + master_secret + pad_1));
@@ -94,7 +88,7 @@ certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash})
SHA = handshake_hash(?SHA, MasterSecret, undefined, SHAHash),
<<MD5/binary, SHA/binary>>;
-certificate_verify(dhe_dss, MasterSecret, {_, SHAHash}) ->
+certificate_verify(?'id-dsa', MasterSecret, {_, SHAHash}) ->
%% sha_hash
%% SHA(master_secret + pad_2 +
%% SHA(handshake_messages + master_secret + pad_1));
@@ -111,14 +105,11 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) ->
case Method of
?NULL -> ok;
_ ->
- ?DBG_HEX(Mac_write_secret),
- ?DBG_HEX(hash(Method, Fragment)),
ok
end,
Mac = mac_hash(Method, Mac_write_secret,
[<<?UINT64(Seq_num), ?BYTE(Type),
?UINT16(Length)>>, Fragment]),
- ?DBG_HEX(Mac),
Mac.
-spec setup_keys(binary(), binary(), binary(),
@@ -140,12 +131,6 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
<<ClientWriteMacSecret:HS/binary, ServerWriteMacSecret:HS/binary,
ClientWriteKey:KML/binary, ServerWriteKey:KML/binary,
ClientIV:IVS/binary, ServerIV:IVS/binary>> = KeyBlock,
- ?DBG_HEX(ClientWriteMacSecret),
- ?DBG_HEX(ServerWriteMacSecret),
- ?DBG_HEX(ClientWriteKey),
- ?DBG_HEX(ServerWriteKey),
- ?DBG_HEX(ClientIV),
- ?DBG_HEX(ServerIV),
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index d1bc0730ba..3784483e9c 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -27,7 +27,6 @@
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
--include("ssl_debug.hrl").
-export([master_secret/3, finished/3, certificate_verify/2, mac_hash/7,
setup_keys/6, suites/0]).
@@ -60,15 +59,14 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = hash_final(?SHA, SHAHash),
prf(MasterSecret, finished_label(Role), [MD5, SHA], 12).
--spec certificate_verify(key_algo(), {binary(), binary()}) -> binary().
+-spec certificate_verify(OID::tuple(), {binary(), binary()}) -> binary().
-certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa;
- Algorithm == dhe_rsa ->
+certificate_verify(?'rsaEncryption', {MD5Hash, SHAHash}) ->
MD5 = hash_final(?MD5, MD5Hash),
SHA = hash_final(?SHA, SHAHash),
<<MD5/binary, SHA/binary>>;
-certificate_verify(dhe_dss, {_, SHAHash}) ->
+certificate_verify(?'id-dsa', {_, SHAHash}) ->
hash_final(?SHA, SHAHash).
-spec setup_keys(binary(), binary(), binary(), integer(),
@@ -133,15 +131,12 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
case Method of
?NULL -> ok;
_ ->
- ?DBG_HEX(Mac_write_secret),
- ?DBG_HEX(hash(Method, Fragment)),
ok
end,
Mac = hmac_hash(Method, Mac_write_secret,
[<<?UINT64(Seq_num), ?BYTE(Type),
?BYTE(Major), ?BYTE(Minor), ?UINT16(Length)>>,
Fragment]),
- ?DBG_HEX(Mac),
Mac.
-spec suites() -> [cipher_suite()].
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 9e4aecac45..c0a7f8d257 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -40,6 +40,7 @@ MODULES = \
ssl_packet_SUITE \
ssl_payload_SUITE \
ssl_to_openssl_SUITE \
+ ssl_session_cache_SUITE \
ssl_test_MACHINE \
old_ssl_active_SUITE \
old_ssl_active_once_SUITE \
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index f8aef55754..8b01ca3ad4 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -268,7 +268,7 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
subjectPublicKey = Public};
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
- parameters=#'Dss-Parms'{p=P, q=Q, g=G}},
+ parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
#'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
validity(Opts) ->
@@ -290,7 +290,7 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', #'Dss-Parms'{p=P, q=Q, g=G}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 3cb9337775..8f9554f3ce 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -31,15 +31,10 @@
-define('24H_in_sec', 86400).
-define(TIMEOUT, 60000).
+-define(LONG_TIMEOUT, 600000).
-define(EXPIRE, 10).
-define(SLEEP, 500).
--behaviour(ssl_session_cache_api).
-
-%% For the session cache tests
--export([init/1, terminate/1, lookup/2, update/3,
- delete/2, foldl/3, select_session/2]).
-
%% Test server callback functions
%%--------------------------------------------------------------------
%% Function: init_per_suite(Config) -> Config
@@ -51,7 +46,7 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?TIMEOUT *2),
+ Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
crypto:start(),
application:start(public_key),
ssl:start(),
@@ -89,13 +84,6 @@ end_per_suite(_Config) ->
%% variable, but should NOT alter/remove any existing entries.
%% Description: Initialization before each test case
%%--------------------------------------------------------------------
-init_per_testcase(session_cache_process_list, Config) ->
- init_customized_session_cache(list, Config);
-
-init_per_testcase(session_cache_process_mnesia, Config) ->
- mnesia:start(),
- init_customized_session_cache(mnesia, Config);
-
init_per_testcase(reuse_session_expired, Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5),
@@ -142,16 +130,6 @@ init_per_testcase(_TestCase, Config0) ->
Dog = test_server:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
-init_customized_session_cache(Type, Config0) ->
- Config = lists:keydelete(watchdog, 1, Config0),
- Dog = test_server:timetrap(?TIMEOUT),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, session_cb, ?MODULE),
- application:set_env(ssl, session_cb_init_args, [Type]),
- ssl:start(),
- [{watchdog, Dog} | Config].
-
%%--------------------------------------------------------------------
%% Function: end_per_testcase(TestCase, Config) -> _
%% Case - atom()
@@ -160,16 +138,6 @@ init_customized_session_cache(Type, Config0) ->
%% A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------
-end_per_testcase(session_cache_process_list, Config) ->
- application:unset_env(ssl, session_cb),
- end_per_testcase(default_action, Config);
-end_per_testcase(session_cache_process_mnesia, Config) ->
- application:unset_env(ssl, session_cb),
- application:unset_env(ssl, session_cb_init_args),
- mnesia:stop(),
- ssl:stop(),
- ssl:start(),
- end_per_testcase(default_action, Config);
end_per_testcase(reuse_session_expired, Config) ->
application:unset_env(ssl, session_lifetime),
end_per_testcase(default_action, Config);
@@ -216,6 +184,8 @@ all(suite) ->
ciphers_dsa_signed_certs_ssl3,
ciphers_dsa_signed_certs_openssl_names,
ciphers_dsa_signed_certs_openssl_names_ssl3,
+ anonymous_cipher_suites,
+ default_reject_anonymous,
send_close,
close_transport_accept, dh_params, server_verify_peer_passive,
server_verify_peer_active, server_verify_peer_active_once,
@@ -226,7 +196,6 @@ all(suite) ->
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,
@@ -1165,13 +1134,13 @@ ecertfile(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
- {options, ServerBadOpts}]),
+ {options, ServerBadOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
+ {port, Port}, {host, Hostname},
{from, self()},
{options, ClientOpts}]),
@@ -1522,6 +1491,14 @@ ciphers_dsa_signed_certs_openssl_names_ssl3(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:openssl_dsa_suites(),
run_suites(Ciphers, Version, Config, dsa).
+anonymous_cipher_suites(doc)->
+ ["Test the anonymous ciphersuites"];
+anonymous_cipher_suites(suite) ->
+ [];
+anonymous_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:anonymous_suites(),
+ run_suites(Ciphers, Version, Config, anonymous).
run_suites(Ciphers, Version, Config, Type) ->
{ClientOpts, ServerOpts} =
@@ -1531,8 +1508,12 @@ run_suites(Ciphers, Version, Config, Type) ->
?config(server_opts, Config)};
dsa ->
{?config(client_opts, Config),
- ?config(server_dsa_opts, Config)}
- end,
+ ?config(server_dsa_opts, Config)};
+ anonymous ->
+ %% No certs in opts!
+ {?config(client_opts, Config),
+ ?config(server_anon, Config)}
+ end,
Result = lists:map(fun(Cipher) ->
cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
@@ -1593,6 +1574,32 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
end.
%%--------------------------------------------------------------------
+default_reject_anonymous(doc)->
+ ["Test that by default anonymous cipher suites are rejected "];
+default_reject_anonymous(suite) ->
+ [];
+default_reject_anonymous(Config) when is_list(Config) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ [Cipher | _] = ssl_test_lib:anonymous_suites(),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options,
+ [{ciphers,[Cipher]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error, "insufficient security"},
+ Client, {error, "insufficient security"}).
+
+%%--------------------------------------------------------------------
reuse_session(doc) ->
["Test reuse of sessions (short handshake)"];
@@ -2857,11 +2864,13 @@ unknown_server_ca_fail(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- FunAndState = {fun(_,{bad_cert, _} = Reason, _) ->
+ FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) ->
{fail, Reason};
(_,{extension, _}, UserState) ->
{unknown, UserState};
(_, valid, UserState) ->
+ {valid, [test_to_update_user_state | UserState]};
+ (_, valid_peer, UserState) ->
{valid, UserState}
end, []},
@@ -2930,6 +2939,8 @@ unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
(_,{extension, _}, UserState) ->
{unknown, UserState};
(_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
{valid, UserState}
end, []},
@@ -2948,7 +2959,7 @@ unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
unknown_server_ca_accept_backwardscompatibilty(doc) ->
- ["Test that the client succeds if the ca is unknown in verify_none mode"];
+ ["Test that old style verify_funs will work"];
unknown_server_ca_accept_backwardscompatibilty(suite) ->
[];
unknown_server_ca_accept_backwardscompatibilty(Config) when is_list(Config) ->
@@ -3043,6 +3054,17 @@ der_input_opts(Opts) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+erlang_ssl_receive(Socket, Data) ->
+ receive
+ {ssl, Socket, Data} ->
+ io:format("Received ~p~n",[Data]),
+ ok;
+ Other ->
+ test_server:fail({unexpected_message, Other})
+ after ?SLEEP * 3 ->
+ test_server:fail({did_not_get, Data})
+ end.
+
send_recv_result(Socket) ->
ssl:send(Socket, "Hello world"),
{ok,"Hello world"} = ssl:recv(Socket, 11),
@@ -3082,162 +3104,3 @@ renegotiate_reuse_session(Socket, Data) ->
%% Make sure session is registerd
test_server:sleep(?SLEEP),
renegotiate(Socket, Data).
-
-session_cache_process_list(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_list(suite) ->
- [];
-session_cache_process_list(Config) when is_list(Config) ->
- session_cache_process(list,Config).
-
-session_cache_process_mnesia(doc) ->
- ["Test reuse of sessions (short handshake)"];
-
-session_cache_process_mnesia(suite) ->
- [];
-session_cache_process_mnesia(Config) when is_list(Config) ->
- session_cache_process(mnesia,Config).
-
-session_cache_process(_Type,Config) when is_list(Config) ->
- reuse_session(Config).
-
-init([Type]) ->
- ets:new(ssl_test, [named_table, public, set]),
- ets:insert(ssl_test, {type, Type}),
- case Type of
- list ->
- spawn(fun() -> session_loop([]) end);
- mnesia ->
- mnesia:start(),
- {atomic,ok} = mnesia:create_table(sess_cache, []),
- sess_cache
- end.
-
-session_cb() ->
- [{type, Type}] = ets:lookup(ssl_test, type),
- Type.
-
-terminate(Cache) ->
- case session_cb() of
- list ->
- Cache ! terminate;
- mnesia ->
- catch {atomic,ok} =
- mnesia:delete_table(sess_cache)
- end.
-
-lookup(Cache, Key) ->
- case session_cb() of
- list ->
- Cache ! {self(), lookup, Key},
- receive {Cache, Res} -> Res end;
- mnesia ->
- case mnesia:transaction(fun() ->
- mnesia:read(sess_cache,
- Key, read)
- end) of
- {atomic, [{sess_cache, Key, Value}]} ->
- Value;
- _ ->
- undefined
- end
- end.
-
-update(Cache, Key, Value) ->
- case session_cb() of
- list ->
- Cache ! {update, Key, Value};
- mnesia ->
- {atomic, ok} =
- mnesia:transaction(fun() ->
- mnesia:write(sess_cache,
- {sess_cache, Key, Value}, write)
- end)
- end.
-
-delete(Cache, Key) ->
- case session_cb() of
- list ->
- Cache ! {delete, Key};
- mnesia ->
- {atomic, ok} =
- mnesia:transaction(fun() ->
- mnesia:delete(sess_cache, Key)
- end)
- end.
-
-foldl(Fun, Acc, Cache) ->
- case session_cb() of
- list ->
- Cache ! {self(),foldl,Fun,Acc},
- receive {Cache, Res} -> Res end;
- mnesia ->
- Foldl = fun() ->
- mnesia:foldl(Fun, Acc, sess_cache)
- end,
- {atomic, Res} = mnesia:transaction(Foldl),
- Res
- end.
-
-select_session(Cache, PartialKey) ->
- case session_cb() of
- list ->
- Cache ! {self(),select_session, PartialKey},
- receive
- {Cache, Res} ->
- Res
- end;
- mnesia ->
- Sel = fun() ->
- mnesia:select(Cache,
- [{{sess_cache,{PartialKey,'$1'}, '$2'},
- [],['$$']}])
- end,
- {atomic, Res} = mnesia:transaction(Sel),
- Res
- end.
-
-session_loop(Sess) ->
- receive
- terminate ->
- ok;
- {Pid, lookup, Key} ->
- case lists:keysearch(Key,1,Sess) of
- {value, {Key,Value}} ->
- Pid ! {self(), Value};
- _ ->
- Pid ! {self(), undefined}
- end,
- session_loop(Sess);
- {update, Key, Value} ->
- NewSess = [{Key,Value}| lists:keydelete(Key,1,Sess)],
- session_loop(NewSess);
- {delete, Key} ->
- session_loop(lists:keydelete(Key,1,Sess));
- {Pid,foldl,Fun,Acc} ->
- Res = lists:foldl(Fun, Acc,Sess),
- Pid ! {self(), Res},
- session_loop(Sess);
- {Pid,select_session,PKey} ->
- Sel = fun({{PKey0, Id},Session}, Acc) when PKey == PKey0 ->
- [[Id, Session]|Acc];
- (_,Acc) ->
- Acc
- end,
- Sessions = lists:foldl(Sel, [], Sess),
- Pid ! {self(), Sessions},
- session_loop(Sess)
- end.
-
-
-erlang_ssl_receive(Socket, Data) ->
- receive
- {ssl, Socket, Data} ->
- io:format("Received ~p~n",[Data]),
- ok;
- Other ->
- test_server:fail({unexpected_message, Other})
- after ?SLEEP * 3 ->
- test_server:fail({did_not_get, Data})
- end.
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
new file mode 100644
index 0000000000..0f39759d97
--- /dev/null
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -0,0 +1,306 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-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/.2
+%%
+%% 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%
+%%
+
+%%
+
+-module(ssl_session_cache_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("test_server.hrl").
+
+-define(SLEEP, 500).
+-define(TIMEOUT, 60000).
+-define(LONG_TIMEOUT, 600000).
+-behaviour(ssl_session_cache_api).
+
+%% For the session cache tests
+-export([init/1, terminate/1, lookup/2, update/3,
+ delete/2, foldl/3, select_session/2]).
+
+%% Test server callback functions
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config) -> Config
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Initialization before the whole suite
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config0) ->
+ Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
+ crypto:start(),
+ application:start(public_key),
+ ssl:start(),
+
+ %% make rsa certs using oppenssl
+ Result =
+ (catch make_certs:all(?config(data_dir, Config0),
+ ?config(priv_dir, Config0))),
+ test_server:format("Make certs ~p~n", [Result]),
+
+ Config1 = ssl_test_lib:make_dsa_cert(Config0),
+ Config = ssl_test_lib:cert_options(Config1),
+ [{watchdog, Dog} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config) -> _
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after the whole suite
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ssl:stop(),
+ crypto:stop().
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config) -> Config
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Initialization before each test case
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%% Description: Initialization before each test case
+%%--------------------------------------------------------------------
+init_per_testcase(session_cache_process_list, Config) ->
+ init_customized_session_cache(list, Config);
+
+init_per_testcase(session_cache_process_mnesia, Config) ->
+ mnesia:start(),
+ init_customized_session_cache(mnesia, Config);
+
+init_per_testcase(_TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = test_server:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
+
+init_customized_session_cache(Type, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = test_server:timetrap(?TIMEOUT),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, session_cb, ?MODULE),
+ application:set_env(ssl, session_cb_init_args, [Type]),
+ ssl:start(),
+ [{watchdog, Dog} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config) -> _
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after each test case
+%%--------------------------------------------------------------------
+end_per_testcase(session_cache_process_list, Config) ->
+ application:unset_env(ssl, session_cb),
+ end_per_testcase(default_action, Config);
+end_per_testcase(session_cache_process_mnesia, Config) ->
+ application:unset_env(ssl, session_cb),
+ application:unset_env(ssl, session_cb_init_args),
+ mnesia:kill(),
+ ssl:stop(),
+ ssl:start(),
+ end_per_testcase(default_action, Config);
+end_per_testcase(_TestCase, Config) ->
+ Dog = ?config(watchdog, Config),
+ case Dog of
+ undefined ->
+ ok;
+ _ ->
+ test_server:timetrap_cancel(Dog)
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: all(Clause) -> TestCases
+%% Clause - atom() - suite | doc
+%% TestCases - [Case]
+%% Case - atom()
+%% Name of a test case.
+%% Description: Returns a list of all test cases in this test suite
+%%--------------------------------------------------------------------
+all(doc) ->
+ ["Test session cach API"];
+
+all(suite) ->
+ [
+ session_cache_process_list, session_cache_process_mnesia
+ ].
+
+session_cache_process_list(doc) ->
+ ["Test reuse of sessions (short handshake)"];
+
+session_cache_process_list(suite) ->
+ [];
+session_cache_process_list(Config) when is_list(Config) ->
+ session_cache_process(list,Config).
+%%--------------------------------------------------------------------
+session_cache_process_mnesia(doc) ->
+ ["Test reuse of sessions (short handshake)"];
+
+session_cache_process_mnesia(suite) ->
+ [];
+session_cache_process_mnesia(Config) when is_list(Config) ->
+ session_cache_process(mnesia,Config).
+
+
+%%--------------------------------------------------------------------
+%%% Session cache API callbacks
+%%--------------------------------------------------------------------
+
+init([Type]) ->
+ ets:new(ssl_test, [named_table, public, set]),
+ ets:insert(ssl_test, {type, Type}),
+ case Type of
+ list ->
+ spawn(fun() -> session_loop([]) end);
+ mnesia ->
+ mnesia:start(),
+ {atomic,ok} = mnesia:create_table(sess_cache, []),
+ sess_cache
+ end.
+
+session_cb() ->
+ [{type, Type}] = ets:lookup(ssl_test, type),
+ Type.
+
+terminate(Cache) ->
+ case session_cb() of
+ list ->
+ Cache ! terminate;
+ mnesia ->
+ catch {atomic,ok} =
+ mnesia:delete_table(sess_cache)
+ end.
+
+lookup(Cache, Key) ->
+ case session_cb() of
+ list ->
+ Cache ! {self(), lookup, Key},
+ receive {Cache, Res} -> Res end;
+ mnesia ->
+ case mnesia:transaction(fun() ->
+ mnesia:read(sess_cache,
+ Key, read)
+ end) of
+ {atomic, [{sess_cache, Key, Value}]} ->
+ Value;
+ _ ->
+ undefined
+ end
+ end.
+
+update(Cache, Key, Value) ->
+ case session_cb() of
+ list ->
+ Cache ! {update, Key, Value};
+ mnesia ->
+ {atomic, ok} =
+ mnesia:transaction(fun() ->
+ mnesia:write(sess_cache,
+ {sess_cache, Key, Value}, write)
+ end)
+ end.
+
+delete(Cache, Key) ->
+ case session_cb() of
+ list ->
+ Cache ! {delete, Key};
+ mnesia ->
+ {atomic, ok} =
+ mnesia:transaction(fun() ->
+ mnesia:delete(sess_cache, Key)
+ end)
+ end.
+
+foldl(Fun, Acc, Cache) ->
+ case session_cb() of
+ list ->
+ Cache ! {self(),foldl,Fun,Acc},
+ receive {Cache, Res} -> Res end;
+ mnesia ->
+ Foldl = fun() ->
+ mnesia:foldl(Fun, Acc, sess_cache)
+ end,
+ {atomic, Res} = mnesia:transaction(Foldl),
+ Res
+ end.
+
+select_session(Cache, PartialKey) ->
+ case session_cb() of
+ list ->
+ Cache ! {self(),select_session, PartialKey},
+ receive
+ {Cache, Res} ->
+ Res
+ end;
+ mnesia ->
+ Sel = fun() ->
+ mnesia:select(Cache,
+ [{{sess_cache,{PartialKey,'$1'}, '$2'},
+ [],['$$']}])
+ end,
+ {atomic, Res} = mnesia:transaction(Sel),
+ Res
+ end.
+
+session_loop(Sess) ->
+ receive
+ terminate ->
+ ok;
+ {Pid, lookup, Key} ->
+ case lists:keysearch(Key,1,Sess) of
+ {value, {Key,Value}} ->
+ Pid ! {self(), Value};
+ _ ->
+ Pid ! {self(), undefined}
+ end,
+ session_loop(Sess);
+ {update, Key, Value} ->
+ NewSess = [{Key,Value}| lists:keydelete(Key,1,Sess)],
+ session_loop(NewSess);
+ {delete, Key} ->
+ session_loop(lists:keydelete(Key,1,Sess));
+ {Pid,foldl,Fun,Acc} ->
+ Res = lists:foldl(Fun, Acc,Sess),
+ Pid ! {self(), Res},
+ session_loop(Sess);
+ {Pid,select_session,PKey} ->
+ Sel = fun({{PKey0, Id},Session}, Acc) when PKey == PKey0 ->
+ [[Id, Session]|Acc];
+ (_,Acc) ->
+ Acc
+ end,
+ Sessions = lists:foldl(Sel, [], Sess),
+ Pid ! {self(), Sessions},
+ session_loop(Sess)
+ end.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+session_cache_process(_Type,Config) when is_list(Config) ->
+ ssl_basic_SUITE:reuse_session(Config).
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index ce164f7e4c..e1e8214ed6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -300,6 +300,7 @@ cert_options(Config) ->
{ssl_imp, new}]},
{server_opts, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -616,6 +617,13 @@ openssl_dsa_suites() ->
end
end, Ciphers).
+anonymous_suites() ->
+ [{dh_anon, rc4_128, md5},
+ {dh_anon, des_cbc, sha},
+ {dh_anon, '3des_ede_cbc', sha},
+ {dh_anon, aes_128_cbc, sha},
+ {dh_anon, aes_256_cbc, sha}].
+
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
public_key:pem_decode(PemBin).
@@ -633,7 +641,7 @@ cipher_result(Socket, Result) ->
receive
{ssl, Socket, "Hello\n"} ->
ssl:send(Socket, " world\n"),
- receive
+ receive
{ssl, Socket, " world\n"} ->
ok
end;
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 7f512f2ab9..afedeaf099 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -27,6 +27,7 @@
-include("test_server.hrl").
-define(TIMEOUT, 120000).
+-define(LONG_TIMEOUT, 600000).
-define(SLEEP, 1000).
-define(OPENSSL_RENEGOTIATE, "r\n").
-define(OPENSSL_QUIT, "Q\n").
@@ -44,7 +45,7 @@
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
- Dog = ssl_test_lib:timetrap(?TIMEOUT *2),
+ Dog = ssl_test_lib:timetrap(?LONG_TIMEOUT *2),
case os:find_executable("openssl") of
false ->
{skip, "Openssl not found"};
@@ -1116,8 +1117,6 @@ run_suites(Ciphers, Version, Config, Type) ->
test_server:fail(cipher_suite_failed_see_test_case_log)
end.
-
-
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, true),
test_server:format("Testing CipherSuite ~p~n", [CipherSuite]),
@@ -1128,8 +1127,8 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
KeyFile = proplists:get_value(keyfile, ServerOpts),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
- " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
-
+ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
+
test_server:format("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1140,11 +1139,11 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
port_command(OpenSslPort, "Hello\n"),
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 709a089892..30a0a3b3f7 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1,2 @@
-SSL_VSN = 4.0.1
+
+SSL_VSN = 4.1