aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/doc/src/ssl.xml6
-rw-r--r--lib/ssl/src/ssl_cipher.erl21
-rw-r--r--lib/ssl/src/ssl_manager.erl24
-rw-r--r--lib/ssl/src/tls_connection.erl125
-rw-r--r--lib/ssl/src/tls_handshake.erl130
-rw-r--r--lib/ssl/test/Makefile1
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl225
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/CA.pem14
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/ec1.crt11
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/ec1.key8
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/ec2.crt11
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/ec2.key8
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/rsa1.crt20
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/rsa1.key51
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/rsa2.crt20
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE_data/rsa2.key51
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl13
-rw-r--r--lib/ssl/test/ssl_test_lib.erl42
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl94
19 files changed, 696 insertions, 179 deletions
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 1645eb15f3..6029a09730 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -86,7 +86,8 @@
{user_lookup_fun, {fun(), term()}}, {psk_identity, string()}, {srp_identity, {string(), string()}} |
{ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}
{next_protocols_advertised, [binary()]} |
- {client_preferred_next_protocols, client | server, [binary()]}
+ {client_preferred_next_protocols, client | server, [binary()]} |
+ {log_alert, boolean()}
</c></p>
<p><c>transportoption() = {cb_info, {CallbackModule::atom(), DataTag::atom(), ClosedTag::atom(), ErrTag:atom()}}
@@ -446,7 +447,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
<tag>{psk_identity, string()}</tag>
<item>Specifies the server identity hint the server presents to the client.
</item>
-
+ <tag>{log_alert, boolean()}</tag>
+ <item>If false, error reports will not be displayed.</item>
</taglist>
</section>
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index ec5d793d65..09aad8e414 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -36,7 +36,7 @@
decipher/5, cipher/5,
suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
- hash_algorithm/1, sign_algorithm/1]).
+ hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]).
-compile(inline).
@@ -1009,6 +1009,7 @@ filter(DerCert, Ciphers) ->
filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(),
[], ecdhe_ecdsa_suites())
end,
+
case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of
{_, rsa} ->
Ciphers1 -- ecdsa_signed_suites();
@@ -1191,15 +1192,15 @@ hash_size(md5) ->
hash_size(sha) ->
20;
%% Uncomment when adding cipher suite that needs it
-%% hash_size(sha224) ->
-%% 28;
+hash_size(sha224) ->
+ 28;
hash_size(sha256) ->
32;
hash_size(sha384) ->
- 48.
+ 48;
%% Uncomment when adding cipher suite that needs it
-%% hash_size(sha512) ->
-%% 64.
+hash_size(sha512) ->
+ 64.
%% RFC 5246: 6.2.3.2. CBC Block Cipher
%%
@@ -1259,15 +1260,15 @@ generic_stream_cipher_from_bin(T, HashSz) ->
%% SSL 3.0 and TLS 1.0 as it is not strictly required and breaks
%% interopability with for instance Google.
is_correct_padding(#generic_block_cipher{padding_length = Len,
- padding = Padding}, {3, N})
+ padding = Padding}, {3, N})
when N == 0; N == 1 ->
Len == byte_size(Padding);
%% Padding must be check in TLS 1.1 and after
is_correct_padding(#generic_block_cipher{padding_length = Len,
- padding = Padding}, _) ->
+ padding = Padding}, _) ->
Len == byte_size(Padding) andalso
list_to_binary(lists:duplicate(Len, Len)) == Padding.
-
+
get_padding(Length, BlockSize) ->
get_padding_aux(BlockSize, Length rem BlockSize).
@@ -1291,7 +1292,7 @@ next_iv(Bin, IV) ->
rsa_signed_suites() ->
dhe_rsa_suites() ++ rsa_suites() ++
psk_rsa_suites() ++ srp_rsa_suites() ++
- ecdh_rsa_suites().
+ ecdh_rsa_suites() ++ ecdhe_rsa_suites().
rsa_keyed_suites() ->
dhe_rsa_suites() ++ rsa_suites() ++
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 7af4a68461..4d5eaeb607 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -30,7 +30,7 @@
lookup_trusted_cert/4,
new_session_id/1, clean_cert_db/2,
register_session/2, register_session/3, invalidate_session/2,
- invalidate_session/3, clear_pem_cache/0]).
+ invalidate_session/3, clear_pem_cache/0, manager_name/1]).
% Spawn export
-export([init_session_validator/1]).
@@ -64,6 +64,18 @@
%%====================================================================
%% API
%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec manager_name(normal | dist) -> atom().
+%%
+%% Description: Returns the registered name of the ssl manager process
+%% in the operation modes 'normal' and 'dist'.
+%%--------------------------------------------------------------------
+manager_name(normal) ->
+ ?MODULE;
+manager_name(dist) ->
+ list_to_atom(atom_to_list(?MODULE) ++ "dist").
+
%%--------------------------------------------------------------------
-spec start_link(list()) -> {ok, pid()} | ignore | {error, term()}.
%%
@@ -71,7 +83,8 @@
%% and certificate caching.
%%--------------------------------------------------------------------
start_link(Opts) ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [?MODULE, Opts], []).
+ DistMangerName = manager_name(normal),
+ gen_server:start_link({local, DistMangerName}, ?MODULE, [DistMangerName, Opts], []).
%%--------------------------------------------------------------------
-spec start_link_dist(list()) -> {ok, pid()} | ignore | {error, term()}.
@@ -80,7 +93,8 @@ start_link(Opts) ->
%% be used by the erlang distribution. Note disables soft upgrade!
%%--------------------------------------------------------------------
start_link_dist(Opts) ->
- gen_server:start_link({local, ssl_manager_dist}, ?MODULE, [ssl_manager_dist, Opts], []).
+ DistMangerName = manager_name(dist),
+ gen_server:start_link({local, DistMangerName}, ?MODULE, [DistMangerName, Opts], []).
%%--------------------------------------------------------------------
-spec connection_init(binary()| {der, list()}, client | server) ->
@@ -100,7 +114,7 @@ connection_init(Trustedcerts, Role) ->
%%--------------------------------------------------------------------
-spec cache_pem_file(binary(), term()) -> {ok, term()} | {error, reason()}.
%%
-%% Description: Cach a pem file and return its content.
+%% Description: Cache a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
MD5 = crypto:hash(md5, File),
@@ -120,7 +134,7 @@ cache_pem_file(File, DbHandle) ->
%%--------------------------------------------------------------------
clear_pem_cache() ->
%% Not supported for distribution at the moement, should it be?
- put(ssl_manager, ssl_manager),
+ put(ssl_manager, manager_name(normal)),
call(unconditionally_clear_pem_cache).
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 159ba406d3..0415ea6ecc 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -76,7 +76,8 @@
negotiated_version, % tls_version()
client_certificate_requested = false,
key_algorithm, % atom as defined by cipher_suite
- hashsign_algorithm, % atom as defined by cipher_suite
+ hashsign_algorithm = {undefined, undefined},
+ cert_hashsign_algorithm,
public_key_info, % PKIX: {Algorithm, PublicKey, PublicKeyParams}
private_key, % PKIX: #'RSAPrivateKey'{}
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
@@ -366,6 +367,7 @@ hello(#hello_request{}, #state{role = client} = State0) ->
next_state(hello, hello, Record, State);
hello(#server_hello{cipher_suite = CipherSuite,
+ hash_signs = HashSign,
compression_method = Compression} = Hello,
#state{session = #session{session_id = OldId},
connection_states = ConnectionStates0,
@@ -388,9 +390,10 @@ hello(#server_hello{cipher_suite = CipherSuite,
_ ->
NextProtocol
end,
-
+
State = State0#state{key_algorithm = KeyAlgorithm,
- hashsign_algorithm = default_hashsign(Version, KeyAlgorithm),
+ hashsign_algorithm =
+ negotiated_hashsign(HashSign, KeyAlgorithm, Version),
negotiated_version = Version,
connection_states = ConnectionStates,
premaster_secret = PremasterSecret,
@@ -406,22 +409,28 @@ hello(#server_hello{cipher_suite = CipherSuite,
end
end;
-hello(Hello = #client_hello{client_version = ClientVersion},
+hello(Hello = #client_hello{client_version = ClientVersion,
+ hash_signs = HashSigns},
State = #state{connection_states = ConnectionStates0,
port = Port, session = #session{own_certificate = Cert} = Session0,
renegotiation = {Renegotiation, _},
session_cache = Cache,
session_cache_cb = CacheCb,
ssl_options = SslOpts}) ->
+
+ HashSign = tls_handshake:select_hashsign(HashSigns, Cert),
case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
+ {Version, {Type, #session{cipher_suite = CipherSuite} = Session}, ConnectionStates, ProtocolsToAdvertise,
EcPointFormats, EllipticCurves} ->
+ {KeyAlgorithm, _, _, _} = ssl_cipher:suite_definition(CipherSuite),
+ NH = negotiated_hashsign(HashSign, KeyAlgorithm, Version),
do_server_hello(Type, ProtocolsToAdvertise,
EcPointFormats, EllipticCurves,
State#state{connection_states = ConnectionStates,
negotiated_version = Version,
session = Session,
+ hashsign_algorithm = NH,
client_ecc = {EllipticCurves, EcPointFormats}});
#alert{} = Alert ->
handle_own_alert(Alert, ClientVersion, hello, State)
@@ -526,7 +535,7 @@ certify(#certificate{} = Cert,
Opts#ssl_options.verify,
Opts#ssl_options.verify_fun, Role) of
{PeerCert, PublicKeyInfo} ->
- handle_peer_cert(PeerCert, PublicKeyInfo,
+ handle_peer_cert(Role, PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false});
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State)
@@ -552,9 +561,11 @@ certify(#server_key_exchange{} = Msg,
#state{role = client, key_algorithm = rsa} = State) ->
handle_unexpected_message(Msg, certify_server_keyexchange, State);
-certify(#certificate_request{}, State0) ->
+certify(#certificate_request{hashsign_algorithms = HashSigns},
+ #state{session = #session{own_certificate = Cert}} = State0) ->
+ HashSign = tls_handshake:select_hashsign(HashSigns, Cert),
{Record, State} = next_record(State0#state{client_certificate_requested = true}),
- next_state(certify, certify, Record, State);
+ next_state(certify, certify, Record, State#state{cert_hashsign_algorithm = HashSign});
%% PSK and RSA_PSK might bypass the Server-Key-Exchange
certify(#server_hello_done{},
@@ -757,21 +768,18 @@ cipher(#hello_request{}, State0) ->
cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashSign},
#state{role = server,
- public_key_info = PublicKeyInfo,
+ public_key_info = {Algo, _, _} =PublicKeyInfo,
negotiated_version = Version,
session = #session{master_secret = MasterSecret},
- hashsign_algorithm = ConnectionHashSign,
tls_handshake_history = Handshake
} = State0) ->
- HashSign = case CertHashSign of
- {_, _} -> CertHashSign;
- _ -> ConnectionHashSign
- end,
+
+ HashSign = tls_handshake:select_cert_hashsign(CertHashSign, Algo, Version),
case tls_handshake:certificate_verify(Signature, PublicKeyInfo,
Version, HashSign, MasterSecret, Handshake) of
valid ->
{Record, State} = next_record(State0),
- next_state(cipher, cipher, Record, State);
+ next_state(cipher, cipher, Record, State#state{cert_hashsign_algorithm = HashSign});
#alert{} = Alert ->
handle_own_alert(Alert, Version, cipher, State0)
end;
@@ -1239,9 +1247,9 @@ ssl_init(SslOpts, Role) ->
{ok, CertDbRef, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, PrivateKey, DHParams}.
init_manager_name(false) ->
- put(ssl_manager, ssl_manager);
+ put(ssl_manager, ssl_manager:manager_name(normal));
init_manager_name(true) ->
- put(ssl_manager, ssl_manager_dist).
+ put(ssl_manager, ssl_manager:manager_name(dist)).
init_certificates(#ssl_options{cacerts = CaCerts,
cacertfile = CACertFile,
@@ -1369,25 +1377,34 @@ sync_send_all_state_event(FsmPid, Event) ->
{error, closed}
end.
-%% We do currently not support cipher suites that use fixed DH.
-%% If we want to implement that we should add a code
-%% here to extract DH parameters form cert.
-handle_peer_cert(PeerCert, PublicKeyInfo,
- #state{session = Session} = State0) ->
+handle_peer_cert(Role, PeerCert, PublicKeyInfo,
+ #state{session = #session{cipher_suite = CipherSuite} = Session} = State0) ->
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
- State2 = case PublicKeyInfo of
- {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} ->
- ECDHKey = public_key:generate_key(PublicKeyParams),
- State3 = State1#state{diffie_hellman_keys = ECDHKey},
- ec_dh_master_secret(ECDHKey, PublicKey, State3);
-
- _ -> State1
- end,
+ {KeyAlg,_,_,_} = ssl_cipher:suite_definition(CipherSuite),
+ State2 = handle_peer_cert_key(Role, PeerCert, PublicKeyInfo, KeyAlg, State1),
+
{Record, State} = next_record(State2),
next_state(certify, certify, Record, State).
+handle_peer_cert_key(client, _,
+ {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams},
+ KeyAlg, State) when KeyAlg == ecdh_rsa;
+ KeyAlg == ecdh_ecdsa ->
+ ECDHKey = public_key:generate_key(PublicKeyParams),
+ ec_dh_master_secret(ECDHKey, PublicKey, State#state{diffie_hellman_keys = ECDHKey});
+
+%% We do currently not support cipher suites that use fixed DH.
+%% If we want to implement that the following clause can be used
+%% to extract DH parameters form cert.
+%% handle_peer_cert_key(client, _PeerCert, {?dhpublicnumber, PublicKey, PublicKeyParams}, {_,SignAlg},
+%% #state{diffie_hellman_keys = {_, MyPrivatKey}} = State) when SignAlg == dh_rsa;
+%% SignAlg == dh_dss ->
+%% dh_master_secret(PublicKeyParams, PublicKey, MyPrivatKey, State);
+handle_peer_cert_key(_, _, _, _, State) ->
+ State.
+
certify_client(#state{client_certificate_requested = true, role = client,
connection_states = ConnectionStates0,
transport_cb = Transport,
@@ -1414,10 +1431,9 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
private_key = PrivateKey,
session = #session{master_secret = MasterSecret,
own_certificate = OwnCert},
- hashsign_algorithm = HashSign,
+ cert_hashsign_algorithm = HashSign,
tls_handshake_history = Handshake0} = State) ->
- %%TODO: for TLS 1.2 we can choose a different/stronger HashSign combination for this.
case tls_handshake:client_certificate_verify(OwnCert, MasterSecret,
Version, HashSign, PrivateKey, Handshake0) of
#certificate_verify{} = Verified ->
@@ -1560,8 +1576,7 @@ server_hello(ServerHello, #state{transport_cb = Transport,
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates1,
tls_handshake_history = Handshake1,
- key_algorithm = KeyAlgorithm,
- hashsign_algorithm = default_hashsign(Version, KeyAlgorithm)}.
+ key_algorithm = KeyAlgorithm}.
server_hello_done(#state{transport_cb = Transport,
socket = Socket,
@@ -1937,7 +1952,7 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
negotiated_version = Version,
socket = Socket,
transport_cb = Transport} = State) ->
- Msg = tls_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef),
+ Msg = tls_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef, Version),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -2014,12 +2029,13 @@ handle_server_key(#server_key_exchange{exchange_keys = Keys},
#state{key_algorithm = KeyAlg,
negotiated_version = Version} = State) ->
Params = tls_handshake:decode_server_key(Keys, KeyAlg, Version),
- HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
- case HashSign of
- {_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
- server_master_secret(Params#server_key_params.params, State);
- _ ->
- verify_server_key(Params, HashSign, State)
+ HashSign = negotiated_hashsign(Params#server_key_params.hashsign, KeyAlg, Version),
+ case is_anonymous(KeyAlg) of
+ true ->
+ server_master_secret(Params#server_key_params.params,
+ State#state{hashsign_algorithm = HashSign});
+ false ->
+ verify_server_key(Params, HashSign, State#state{hashsign_algorithm = HashSign})
end.
verify_server_key(#server_key_params{params = Params,
@@ -2995,11 +3011,6 @@ get_pending_connection_state_prf(CStates, Direction) ->
CS = tls_record:pending_connection_state(CStates, Direction),
CS#connection_state.security_parameters#security_parameters.prf_algorithm.
-connection_hashsign(HashSign = {_, _}, _State) ->
- HashSign;
-connection_hashsign(_, #state{hashsign_algorithm = HashSign}) ->
- HashSign.
-
%% RFC 5246, Sect. 7.4.1.4.1. Signature Algorithms
%% If the client does not send the signature_algorithms extension, the
%% server MUST do the following:
@@ -3014,12 +3025,18 @@ connection_hashsign(_, #state{hashsign_algorithm = HashSign}) ->
%% - If the negotiated key exchange algorithm is one of (ECDH_ECDSA,
%% ECDHE_ECDSA), behave as if the client had sent value {sha1,ecdsa}.
+negotiated_hashsign(undefined, Algo, Version) ->
+ default_hashsign(Version, Algo);
+negotiated_hashsign(HashSign = {_, _}, _, _) ->
+ HashSign.
+
default_hashsign(_Version = {Major, Minor}, KeyExchange)
- when Major == 3 andalso Minor >= 3 andalso
+ when Major >= 3 andalso Minor >= 3 andalso
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
KeyExchange == dh_rsa orelse
KeyExchange == ecdhe_rsa orelse
+ KeyExchange == ecdh_rsa orelse
KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
@@ -3027,12 +3044,12 @@ default_hashsign(_Version, KeyExchange)
KeyExchange == dhe_rsa;
KeyExchange == dh_rsa;
KeyExchange == ecdhe_rsa;
+ KeyExchange == ecdh_rsa;
KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == ecdhe_ecdsa;
- KeyExchange == ecdh_ecdsa;
- KeyExchange == ecdh_rsa ->
+ KeyExchange == ecdh_ecdsa ->
{sha, ecdsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
@@ -3081,3 +3098,13 @@ select_curve(#state{client_ecc = {[Curve|_], _}}) ->
{namedCurve, Curve};
select_curve(_) ->
{namedCurve, ?secp256k1}.
+
+is_anonymous(Algo) when Algo == dh_anon;
+ Algo == ecdh_anon;
+ Algo == psk;
+ Algo == dhe_psk;
+ Algo == rsa_psk;
+ Algo == srp_anon ->
+ true;
+is_anonymous(_) ->
+ false.
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 51fd2e1dc9..6cc6e9e885 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -34,11 +34,12 @@
-export([master_secret/4, client_hello/8, server_hello/7, hello/4,
hello_request/0, certify/7, certificate/4,
client_certificate_verify/6, certificate_verify/6, verify_signature/5,
- certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
+ certificate_request/4, key_exchange/3, server_key_exchange_hash/2,
finished/5, verify_connection/6, get_tls_handshake/3,
decode_client_key/3, decode_server_key/3, server_hello_done/0,
encode_handshake/2, init_handshake_history/0, update_handshake_history/2,
- decrypt_premaster_secret/2, prf/5, next_protocol/1]).
+ decrypt_premaster_secret/2, prf/5, next_protocol/1, select_hashsign/2,
+ select_cert_hashsign/3]).
-export([dec_hello_extensions/2]).
@@ -82,7 +83,7 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info =
renegotiation_info(client, ConnectionStates, Renegotiation),
srp = SRP,
- hash_signs = default_hash_signs(),
+ hash_signs = advertised_hash_signs(Version),
ec_point_formats = EcPointFormats,
elliptic_curves = EllipticCurves,
next_protocol_negotiation =
@@ -152,7 +153,6 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
#ssl_options{secure_renegotiate = SecureRenegotation, next_protocol_selector = NextProtocolSelector,
versions = SupportedVersions},
ConnectionStates0, Renegotiation) ->
- %%TODO: select hash and signature algorigthm
case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
case handle_renegotiation_info(client, Info, ConnectionStates0,
@@ -177,7 +177,6 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
hello(#client_hello{client_version = ClientVersion} = Hello,
#ssl_options{versions = Versions} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
- %% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
case tls_record:is_acceptable_version(Version, Versions) of
true ->
@@ -298,7 +297,7 @@ client_certificate_verify(undefined, _, _, _, _, _) ->
client_certificate_verify(_, _, _, _, undefined, _) ->
ignore;
client_certificate_verify(OwnCert, MasterSecret, Version,
- {HashAlgo, SignAlgo},
+ {HashAlgo, _} = HashSign,
PrivateKey, {Handshake, _}) ->
case public_key:pkix_is_fixed_dh_cert(OwnCert) of
true ->
@@ -307,7 +306,7 @@ client_certificate_verify(OwnCert, MasterSecret, Version,
Hashes =
calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
Signed = digitally_signed(Version, Hashes, HashAlgo, PrivateKey),
- #certificate_verify{signature = Signed, hashsign_algorithm = {HashAlgo, SignAlgo}}
+ #certificate_verify{signature = Signed, hashsign_algorithm = HashSign}
end.
%%--------------------------------------------------------------------
@@ -349,17 +348,17 @@ verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey
public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}).
%%--------------------------------------------------------------------
--spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) ->
+-spec certificate_request(#connection_states{}, db_handle(), certdb_ref(), tls_version()) ->
#certificate_request{}.
%%
%% Description: Creates a certificate_request message, called by the server.
%%--------------------------------------------------------------------
-certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
+certificate_request(ConnectionStates, CertDbHandle, CertDbRef, Version) ->
#connection_state{security_parameters =
#security_parameters{cipher_suite = CipherSuite}} =
tls_record:pending_connection_state(ConnectionStates, read),
Types = certificate_types(CipherSuite),
- HashSigns = default_hash_signs(),
+ HashSigns = advertised_hash_signs(Version),
Authorities = certificate_authorities(CertDbHandle, CertDbRef),
#certificate_request{
certificate_types = Types,
@@ -687,6 +686,54 @@ prf({3,1}, Secret, Label, Seed, WantedLength) ->
prf({3,_N}, Secret, Label, Seed, WantedLength) ->
{ok, ssl_tls1:prf(?SHA256, Secret, Label, Seed, WantedLength)}.
+
+%%--------------------------------------------------------------------
+-spec select_hashsign(#hash_sign_algos{}| undefined, undefined | term()) ->
+ [{atom(), atom()}] | undefined.
+
+%%
+%% Description:
+%%--------------------------------------------------------------------
+select_hashsign(_, undefined) ->
+ {null, anon};
+select_hashsign(undefined, Cert) ->
+ #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
+ #'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ select_cert_hashsign(undefined, Algo, {undefined, undefined});
+select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert) ->
+ #'OTPCertificate'{tbsCertificate = TBSCert} =public_key:pkix_decode_cert(Cert, otp),
+ #'OTPSubjectPublicKeyInfo'{algorithm = {_,Algo, _}} = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ DefaultHashSign = {_, Sign} = select_cert_hashsign(undefined, Algo, {undefined, undefined}),
+ case lists:filter(fun({sha, dsa}) ->
+ true;
+ ({_, dsa}) ->
+ false;
+ ({Hash, S}) when S == Sign ->
+ ssl_cipher:is_acceptable_hash(Hash, proplists:get_value(hashs, crypto:supports()));
+ (_) ->
+ false
+ end, HashSigns) of
+ [] ->
+ DefaultHashSign;
+ [HashSign| _] ->
+ HashSign
+ end.
+%%--------------------------------------------------------------------
+-spec select_cert_hashsign(#hash_sign_algos{}| undefined, oid(), tls_version()) ->
+ [{atom(), atom()}].
+
+%%
+%% Description:
+%%--------------------------------------------------------------------
+select_cert_hashsign(HashSign, _, {Major, Minor}) when HashSign =/= undefined andalso Major >= 3 andalso Minor >= 3 ->
+ HashSign;
+select_cert_hashsign(undefined,?'id-ecPublicKey', _) ->
+ {sha, ecdsa};
+select_cert_hashsign(undefined, ?rsaEncryption, _) ->
+ {md5sha, rsa};
+select_cert_hashsign(undefined, ?'id-dsa', _) ->
+ {sha, dsa}.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -1066,7 +1113,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suites = from_2bytes(CipherSuites),
compression_methods = Comp_methods,
renegotiation_info = RenegotiationInfo,
- srp = SRP,
+ srp = SRP,
hash_signs = HashSigns,
elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation
@@ -1179,12 +1226,12 @@ dec_ske_params(Len, Keys, Version) ->
dec_ske_signature(Params, <<?BYTE(HashAlgo), ?BYTE(SignAlgo),
?UINT16(0)>>, {Major, Minor})
- when Major == 3, Minor >= 3 ->
+ when Major >= 3, Minor >= 3 ->
HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)},
{Params, HashSign, <<>>};
dec_ske_signature(Params, <<?BYTE(HashAlgo), ?BYTE(SignAlgo),
?UINT16(Len), Signature:Len/binary>>, {Major, Minor})
- when Major == 3, Minor >= 3 ->
+ when Major >= 3, Minor >= 3 ->
HashSign = {ssl_cipher:hash_algorithm(HashAlgo), ssl_cipher:sign_algorithm(SignAlgo)},
{Params, HashSign, Signature};
dec_ske_signature(Params, <<>>, _) ->
@@ -1219,11 +1266,11 @@ dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID),
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
-dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct,
+dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary, _/binary>> = KeyStruct,
KeyExchange, Version)
when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK ->
Params = #server_psk_params{
- hint = PskIdentityHint},
+ hint = PskIdentityHint},
{BinMsg, HashSign, Signature} = dec_ske_params(Len + 2, KeyStruct, Version),
#server_key_params{params = Params,
params_bin = BinMsg,
@@ -1236,8 +1283,8 @@ dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary,
?KEY_EXCHANGE_DHE_PSK, Version) ->
DHParams = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y},
Params = #server_dhe_psk_params{
- hint = IdentityHint,
- dh_params = DHParams},
+ hint = IdentityHint,
+ dh_params = DHParams},
{BinMsg, HashSign, Signature} = dec_ske_params(Len + PLen + GLen + YLen + 8, KeyStruct, Version),
#server_key_params{params = Params,
params_bin = BinMsg,
@@ -1297,16 +1344,14 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
- EllipticCurveListLen = Len - 2,
- <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData,
+ <<?UINT16(_), EllipticCurveList/binary>> = ExtData,
EllipticCurves = [ssl_tls1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList],
dec_hello_extensions(Rest, [{elliptic_curves,
#elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]);
dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
- ECPointFormatListLen = Len - 1,
- <<?BYTE(ECPointFormatListLen), ECPointFormatList/binary>> = ExtData,
+ <<?BYTE(_), ECPointFormatList/binary>> = ExtData,
ECPointFormats = binary_to_list(ECPointFormatList),
dec_hello_extensions(Rest, [{ec_point_formats,
#ec_point_formats{ec_point_format_list = ECPointFormats}} | Acc]);
@@ -1755,26 +1800,6 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
{unknown, {SslState, UserState}}
end.
--define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
--define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
--define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}).
-
--define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)).
-
-default_hash_signs() ->
- HashSigns = [?TLSEXT_SIGALG(sha512),
- ?TLSEXT_SIGALG(sha384),
- ?TLSEXT_SIGALG(sha256),
- ?TLSEXT_SIGALG(sha224),
- ?TLSEXT_SIGALG(sha),
- ?TLSEXT_SIGALG_DSA(sha),
- ?TLSEXT_SIGALG_RSA(md5)],
- CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
- HasECC = proplists:get_bool(ecdsa, CryptoSupport),
- #hash_sign_algos{hash_sign_algos =
- lists:filter(fun({_, ecdsa}) -> HasECC;
- (_) -> true end, HashSigns)}.
-
handle_hello_extensions(#client_hello{random = Random,
cipher_suites = CipherSuites,
renegotiation_info = Info,
@@ -1825,3 +1850,26 @@ handle_srp_extension(#srp{username = Username}, Session) ->
int_to_bin(I) ->
L = (length(integer_to_list(I, 16)) + 1) div 2,
<<I:(L*8)>>.
+
+-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
+-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
+-define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}).
+
+-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)).
+
+advertised_hash_signs({Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
+ HashSigns = [?TLSEXT_SIGALG(sha512),
+ ?TLSEXT_SIGALG(sha384),
+ ?TLSEXT_SIGALG(sha256),
+ ?TLSEXT_SIGALG(sha224),
+ ?TLSEXT_SIGALG(sha),
+ ?TLSEXT_SIGALG_DSA(sha),
+ ?TLSEXT_SIGALG_RSA(md5)],
+ CryptoSupport = crypto:supports(),
+ HasECC = proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)),
+ Hashs = proplists:get_value(hashs, CryptoSupport),
+ #hash_sign_algos{hash_sign_algos =
+ lists:filter(fun({Hash, ecdsa}) -> HasECC andalso proplists:get_bool(Hash, Hashs);
+ ({Hash, _}) -> proplists:get_bool(Hash, Hashs) end, HashSigns)};
+advertised_hash_signs(_) ->
+ undefined.
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 39aa22ffb4..cb919baf4e 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -47,6 +47,7 @@ MODULES = \
ssl_payload_SUITE \
ssl_session_cache_SUITE \
ssl_to_openssl_SUITE \
+ ssl_ECC_SUITE \
make_certs\
erl_make_certs
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
new file mode 100644
index 0000000000..608f2f11c3
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -0,0 +1,225 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2013. 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_ECC_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.2', [], all_versions_groups()},
+ {'tlsv1.1', [], all_versions_groups()},
+ {'tlsv1', [], all_versions_groups()},
+ {'erlang_server', [], key_cert_combinations()},
+ {'erlang_client', [], key_cert_combinations()},
+ {'erlang', [], key_cert_combinations()}
+ ].
+
+all_versions_groups ()->
+ [{group, 'erlang_server'},
+ {group, 'erlang_client'},
+ {group, 'erlang'}
+ ].
+
+key_cert_combinations() ->
+ [client_ec_server_ec,
+ client_rsa_server_ec,
+ client_ec_server_rsa,
+ client_rsa_server_rsa].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl:start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+init_per_group(erlang_client, Config) ->
+ case ssl_test_lib:is_sane_ecc(openssl) of
+ true ->
+ common_init_per_group(erlang_client, [{server_type, openssl},
+ {client_type, erlang} | Config]);
+ false ->
+ {skip, "Known ECC bug in openssl"}
+ end;
+
+init_per_group(erlang_server, Config) ->
+ case ssl_test_lib:is_sane_ecc(openssl) of
+ true ->
+ common_init_per_group(erlang_client, [{server_type, erlang},
+ {client_type, openssl} | Config]);
+ false ->
+ {skip, "Known ECC bug in openssl"}
+ end;
+
+init_per_group(erlang = Group, Config) ->
+ case ssl_test_lib:sufficient_crypto_support(Group) of
+ true ->
+ common_init_per_group(erlang, [{server_type, erlang},
+ {client_type, erlang} | Config]);
+ false ->
+ {skip, "Crypto does not support ECC"}
+ end;
+init_per_group(Group, Config) ->
+ common_init_per_group(Group, Config).
+
+common_init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName),
+ [{tls_version, GroupName} | Config];
+ _ ->
+ openssl_check(GroupName, Config)
+ end.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+
+init_per_testcase(_TestCase, Config) ->
+ ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
+ ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+client_ec_server_ec(Config) when is_list(Config) ->
+ basic_test("ec1.crt", "ec1.key", "ec2.crt", "ec2.key", Config).
+
+client_ec_server_rsa(Config) when is_list(Config) ->
+ basic_test("ec1.crt", "ec1.key", "rsa1.crt", "rsa1.key", Config).
+
+client_rsa_server_ec(Config) when is_list(Config) ->
+ basic_test("rsa1.crt", "rsa1.key", "ec2.crt", "ec2.key", Config).
+
+client_rsa_server_rsa(Config) when is_list(Config) ->
+ basic_test("rsa1.crt", "rsa1.key", "rsa2.crt", "rsa2.key", Config).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+basic_test(ClientCert, ClientKey, ServerCert, ServerKey, Config) ->
+ DataDir = ?config(data_dir, Config),
+ SType = ?config(server_type, Config),
+ CType = ?config(client_type, Config),
+ {Server, Port} = start_server(SType,
+ filename:join(DataDir, "CA.pem"),
+ filename:join(DataDir, ServerCert),
+ filename:join(DataDir, ServerKey),
+ Config),
+ Client = start_client(CType, Port, filename:join(DataDir, "CA.pem"),
+ filename:join(DataDir, ClientCert),
+ filename:join(DataDir, ClientKey), Config),
+ check_result(Server, SType, Client, CType).
+
+start_client(openssl, Port, CA, Cert, Key, _) ->
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
+ Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
+ " -cert " ++ Cert ++ " -CAfile " ++ CA
+ ++ " -key " ++ Key ++ " -host localhost -msg",
+ OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
+ true = port_command(OpenSslPort, "Hello world"),
+ OpenSslPort;
+start_client(erlang, Port, CA, Cert, Key, Config) ->
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{verify, verify_peer}, {cacertfile, CA},
+ {certfile, Cert}, {keyfile, Key}]}]).
+
+start_server(openssl, CA, Cert, Key, _) ->
+ Port = ssl_test_lib:inet_port(node()),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
+ " -cert " ++ Cert ++ " -CAfile " ++ CA
+ ++ " -key " ++ Key ++ " -Verify 2 -msg",
+ OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
+ ssl_test_lib:wait_for_openssl_server(),
+ true = port_command(OpenSslPort, "Hello world"),
+ {OpenSslPort, Port};
+
+start_server(erlang, CA, Cert, Key, Config) ->
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active,
+ []}},
+ {options,
+ [{verify, verify_peer}, {cacertfile, CA},
+ {certfile, Cert}, {keyfile, Key}]}]),
+ {Server, ssl_test_lib:inet_port(Server)}.
+
+check_result(Server, erlang, Client, erlang) ->
+ ssl_test_lib:check_result(Server, ok, Client, ok);
+check_result(Server, erlang, _, _) ->
+ ssl_test_lib:check_result(Server, ok);
+check_result(_, _, Client, erlang) ->
+ ssl_test_lib:check_result(Client, ok);
+check_result(_,openssl, _, openssl) ->
+ ok.
+
+openssl_check(erlang, Config) ->
+ Config;
+openssl_check(_, Config) ->
+ TLSVersion = ?config(tls_version, Config),
+ case ssl_test_lib:check_sane_openssl_version(TLSVersion) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "TLS version not supported by openssl"}
+ end.
+
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/CA.pem b/lib/ssl/test/ssl_ECC_SUITE_data/CA.pem
new file mode 100644
index 0000000000..f82efdefc5
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/CA.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICGjCCAYegAwIBAgIQZIIqq4RXfpBKJXV69Jc4BjAJBgUrDgMCHQUAMB0xGzAZ
+BgNVBAMTEklTQSBUZXN0IEF1dGhvcml0eTAeFw0xMjAzMjAxNzEzMjFaFw0zOTEy
+MzEyMzU5NTlaMB0xGzAZBgNVBAMTEklTQSBUZXN0IEF1dGhvcml0eTCBnzANBgkq
+hkiG9w0BAQEFAAOBjQAwgYkCgYEAqnt6FSyFQVSDyP7mY63IhCzgysTxBEg1qDb8
+nBHj9REReZA5UQ5iyEOdTbdLyOaSk2rJyA2wdTjYkNnLzK49nZFlpf89r3/bakAM
+wZv69S3FJi9W2z9m4JPv/5+QCYnFNRSnnHw3maNElwoQyknx96I3W7EuVOvKtKhh
+4DaD0WsCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zBOBgNVHQEERzBFgBBCHwn2
+8AmbN+cvJl1iJ1bsoR8wHTEbMBkGA1UEAxMSSVNBIFRlc3QgQXV0aG9yaXR5ghBk
+giqrhFd+kEoldXr0lzgGMAkGBSsOAwIdBQADgYEAIlVecua5Cr1z/cdwQ8znlgOU
+U+y/uzg0nupKkopzVnRYhwV4hxZt3izAz4C/SJZB7eL0bUKlg1ceGjbQsGEm0fzF
+LEV3vym4G51bxv03Iecwo96G4NgjJ7+9/7ciBVzfxZyfuCpYG1M2LyrbOyuevtTy
+2+vIueT0lv6UftgBfIE=
+-----END CERTIFICATE-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec1.crt b/lib/ssl/test/ssl_ECC_SUITE_data/ec1.crt
new file mode 100644
index 0000000000..7d2b9cde9d
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/ec1.crt
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhjCB8AIBBjANBgkqhkiG9w0BAQUFADAdMRswGQYDVQQDExJJU0EgVGVzdCBB
+dXRob3JpdHkwHhcNMTMwODA4MTAxNDI3WhcNMjMwODA2MTAxNDI3WjBFMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExFTATBgNVBAcTDEZvcnQgQmVsdm9p
+cjEMMAoGA1UEAxMDZWMxMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEpiRIxUCESROR
+P8IByg+vBv1fDdAg7yXfAh95GxFtvhBqZs6ATwaRKyLmZYgUm/4NUAyUeqmTBb7s
+2msKo5mnNzANBgkqhkiG9w0BAQUFAAOBgQAmwzoB1DVO69FQOUdBVnyups4t0c1c
+8h+1z/5P4EtPltk4o3mRn0AZogqdXCpNbuSGbSJh+dep5xW30VLxNHdc+tZSLK6j
+pT7A3hymMk8qbi13hxeH/VpEP25y1EjHowow9Wmb6ebtT/v7qFQ9AAHD9ONcIM4I
+FCC8vdFo7M5GgQ==
+-----END CERTIFICATE-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec1.key b/lib/ssl/test/ssl_ECC_SUITE_data/ec1.key
new file mode 100644
index 0000000000..2dc9508b3c
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/ec1.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQACg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHQCAQEEIOO0WK8znNzLyZIoGRIlaKnCNr2Wy8uk9i+GGFIhDGNAoAcGBSuBBAAK
+oUQDQgAEpiRIxUCESRORP8IByg+vBv1fDdAg7yXfAh95GxFtvhBqZs6ATwaRKyLm
+ZYgUm/4NUAyUeqmTBb7s2msKo5mnNw==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec2.crt b/lib/ssl/test/ssl_ECC_SUITE_data/ec2.crt
new file mode 100644
index 0000000000..b0558a0ebc
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/ec2.crt
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhjCB8AIBBzANBgkqhkiG9w0BAQUFADAdMRswGQYDVQQDExJJU0EgVGVzdCBB
+dXRob3JpdHkwHhcNMTMwODA4MTAxNDM0WhcNMjMwODA2MTAxNDM0WjBFMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExFTATBgNVBAcTDEZvcnQgQmVsdm9p
+cjEMMAoGA1UEAxMDZWMyMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzXaYReUyvoYl
+FwGOe0MJEXWCUncMfr2xG4GMjGYlfZsvLGEokefsJIvW+I+9jgUT2UFjxFXYNAvm
+uD1A1iWVWjANBgkqhkiG9w0BAQUFAAOBgQBFa6iIlrT9DWptIdB8uSYvp7qwiHxN
+hiVH5YhGIHHqjGZqtRHrSxqNEYMXXrgH9Hxc6gDbk9PsHZyVVoh/HgVWddqW1inh
+tStZm420PAKCuH4T6Cfsk76GE2m7FRzJvw9TM1f2A5nIy9abyrpup8lZGcIL4Kmq
+1Fix1LRtrmLNTA==
+-----END CERTIFICATE-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/ec2.key b/lib/ssl/test/ssl_ECC_SUITE_data/ec2.key
new file mode 100644
index 0000000000..366d13648b
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/ec2.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQACg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHQCAQEEIPR3ORUpAFMTQhUJ0jllN38LKWziG8yP2H54Y/9vh1PwoAcGBSuBBAAK
+oUQDQgAEzXaYReUyvoYlFwGOe0MJEXWCUncMfr2xG4GMjGYlfZsvLGEokefsJIvW
++I+9jgUT2UFjxFXYNAvmuD1A1iWVWg==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.crt b/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.crt
new file mode 100644
index 0000000000..ed9beacf68
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVjCCAr8CAQkwDQYJKoZIhvcNAQEFBQAwHTEbMBkGA1UEAxMSSVNBIFRlc3Qg
+QXV0aG9yaXR5MB4XDTEzMDgwODEwMTUzNFoXDTQwMTIyNDEwMTUzNFowRjELMAkG
+A1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRUwEwYDVQQHEwxGb3J0IEJlbHZv
+aXIxDTALBgNVBAMTBHJzYTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQC62v40w1AjV3oJuyYC2Fw6XhTOi1il6xZFnB9J1WhCmuxAB/VMhBcNypx38mNk
+eQ7a/ERQ5ddhZey29DYeFYU8oqfDURgWx5USHufb90xBen9KPmX3VNuQ8ZFP2q8Q
+b01/oRHBJQRBuaCtFHzpGIVBjC6dD5yeQgJsYaF4u+PBbonsIGROXMybcvUzXmjU
+dwpy2NhjGQL5sWcOdIeRP43APSyRYvq4tuBUZk2XxWfBcvA8LpcoYPMlRTf6jGL1
+/fAAcCYJ9lh3h92w0NZ/7ZRa/ebTplxK6yqCftuSKui1KdL69m0WZqHl79AUSfs9
+lsOwx9lHkyYvJeMofyeDbZ+3OYLmVqEBG1fza2aV2XVh9zJ8fAwmXy/c2IDhw/oD
+HAe/rSg/Sgt03ydIKqtZHbl3v0EexQQRlJRULIzdtON02dJMUd4EFUgQ9OUtEmC2
+Psj9Jdu1g5cevU7Mymu8Ot+fjHiGTcBUsXNuXFCbON3Gw7cIDl4+iv+cpDHHVC9L
+HK3PMEq3vu3qOGXSz+LDOoqkfROcLG7BclBuN2zoVSsMHFkB4aJhwy7eHhGz0z2W
+c6LTVd+GAApdY80kmjOjT//QxHEsX/n1useHza3OszQqZiArr4ub4rtq+l1DxAS/
+DWrZ/JGsbKL8cjWso6qBF94xTi8WhjkKuUYhsm+qLAbNOQIDAQABMA0GCSqGSIb3
+DQEBBQUAA4GBAIcuzqRkfypV/9Z85ZQCCoejPm5Urhv7dfg1/B3QtazogPBZLgL5
+e60fG1uAw5GmqTViHLvW06z73oQvJrFkrCLVvadDNtrKYKXnXqdkgVyk36F/B737
+A43HGnMfSxCfRhIOuKZB9clP5PiNlhw36yi3DratqT6TUvI69hg8a7jA
+-----END CERTIFICATE-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.key b/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.key
new file mode 100644
index 0000000000..6e0d913d79
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/rsa1.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.crt b/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.crt
new file mode 100644
index 0000000000..06ca92dda3
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVjCCAr8CAQowDQYJKoZIhvcNAQEFBQAwHTEbMBkGA1UEAxMSSVNBIFRlc3Qg
+QXV0aG9yaXR5MB4XDTEzMDgwODEwMTYwMloXDTQwMTIyNDEwMTYwMlowRjELMAkG
+A1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRUwEwYDVQQHEwxGb3J0IEJlbHZv
+aXIxDTALBgNVBAMTBHJzYTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCjQUe0BGOpULjOAmLbXM4SSQzJvxJbCFi3tryyd+OARq6Fdp6/fslVhsr0PhWE
+X8yRbAugIjseTpLwz+1OC6LavOGV1ixzGTI/9HDXGKbf8qoCrSdh28sqQJnmqGT4
+UCKLn6Rqjg2iyBBcSK3LrtKEPI4C7NaSOZUtANkppvziEMwm+0r16sgHh2Xx6mxd
+22q01kq1lJqwEnIDPMSz3+ESUVQQ4T3ka7yFIhc9PYmILIXkZi0x7AiDeRkIILul
+GQrduTWSPGY3prXeDAbmQNazxrHp8fcR2AfFSI6HYxMALq9jWxc4xDIkss6BO2Et
+riJOIgXFpbyVsYCbkI1kXhEWFDt3uJBIcmtJKGzro4xv+XLG6BbUeTJgSHXMc7Cb
+fX87+CBIFR5a/aqkEKh/mcvsDdaV+kpNKdr7q4wAuIQb8g7IyXEDuAm1VZjQs9WC
+KFRGSq9sergEw9gna0iThRZjD+dzNzB17XmlAK4wa98a7MntwqpAt/GsCFOiPM8E
+c+8gpuo8WqC0kP8OpImyw9cQhlZ3dca1qkr2cyKyAOGxUxyA67FgiHSsxJJ2Xhse
+o49qeKTjMZd8zhSokM2TH6qEf7YfOePU51YRfAHUhzRmE31N/MExqDjFjklksEtM
+iHhbPo+cOoxV8x1u13umdUvtTaAUSBA/DpvzWdnORvnaqQIDAQABMA0GCSqGSIb3
+DQEBBQUAA4GBAFD+O7h+5R5S1rIN9eC+oEGpvRhMG4v4G3pJp+c7bbtO7ifFx1WP
+bta1b5YtiQYcKP0ORABm/3Kcvsb3VbaMH/zkxWEbASZsmIcBY3ml4f2kkn6WT2hD
+Wc6VMIAR3N6Mj1b30yI1qYVIid+zIouiykMB+zqllm+Uar0SPNjKxDU/
+-----END CERTIFICATE-----
diff --git a/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.key b/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.key
new file mode 100644
index 0000000000..d415ef0391
--- /dev/null
+++ b/lib/ssl/test/ssl_ECC_SUITE_data/rsa2.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index b5cf6d1212..b8849d5cbd 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -212,21 +212,20 @@ end_per_suite(_Config) ->
%%--------------------------------------------------------------------
init_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
+ case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
true ->
+ ssl_test_lib:init_tls_version(GroupName),
+ Config;
+ _ ->
case ssl_test_lib:sufficient_crypto_support(GroupName) of
true ->
- ssl_test_lib:init_tls_version(GroupName),
+ ssl:start(),
Config;
false ->
{skip, "Missing crypto support"}
- end;
- _ ->
- ssl:start(),
- Config
+ end
end.
-
end_per_group(_GroupName, Config) ->
Config.
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 34c52b10b3..74fadc0cc7 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -27,6 +27,7 @@
-compile(export_all).
-record(sslsocket, { fd = nil, pid = nil}).
+-define(SLEEP, 1000).
%% For now always run locally
run_where(_) ->
@@ -949,7 +950,10 @@ init_tls_version(Version) ->
sufficient_crypto_support('tlsv1.2') ->
CryptoSupport = crypto:supports(),
proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport));
-sufficient_crypto_support(ciphers_ec) ->
+sufficient_crypto_support(Group) when Group == ciphers_ec; %% From ssl_basic_SUITE
+ Group == erlang_server; %% From ssl_ECC_SUITE
+ Group == erlang_client; %% From ssl_ECC_SUITE
+ Group == erlang -> %% From ssl_ECC_SUITE
CryptoSupport = crypto:supports(),
proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport));
sufficient_crypto_support(_) ->
@@ -1026,3 +1030,39 @@ cipher_restriction(Config0) ->
true ->
Config0
end.
+
+check_sane_openssl_version(Version) ->
+ case {Version, os:cmd("openssl version")} of
+ {_, "OpenSSL 1.0.1" ++ _} ->
+ true;
+ {'tlsv1.2', "OpenSSL 1.0" ++ _} ->
+ false;
+ {'tlsv1.1', "OpenSSL 1.0" ++ _} ->
+ false;
+ {'tlsv1.2', "OpenSSL 0" ++ _} ->
+ false;
+ {'tlsv1.1', "OpenSSL 0" ++ _} ->
+ false;
+ {_, _} ->
+ true
+ end.
+
+wait_for_openssl_server() ->
+ receive
+ {Port, {data, Debug}} when is_port(Port) ->
+ ct:log("openssl ~s~n",[Debug]),
+ %% openssl has started make sure
+ %% it will be in accept. Parsing
+ %% output is too error prone. (Even
+ %% more so than sleep!)
+ ct:sleep(?SLEEP)
+ end.
+
+version_flag(tlsv1) ->
+ " -tls1 ";
+version_flag('tlsv1.1') ->
+ " -tls1_1 ";
+version_flag('tlsv1.2') ->
+ " -tls1_2 ";
+version_flag(sslv3) ->
+ " -ssl3 ".
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 019ed58b1b..b576b8f70d 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -120,7 +120,7 @@ end_per_suite(_Config) ->
init_per_group(GroupName, Config) ->
case ssl_test_lib:is_tls_version(GroupName) of
true ->
- case check_sane_openssl_version(GroupName) of
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
true ->
ssl_test_lib:init_tls_version(GroupName),
Config;
@@ -204,7 +204,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -269,14 +269,14 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -311,7 +311,7 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -host localhost",
ct:log("openssl cmd: ~p~n", [Cmd]),
@@ -345,7 +345,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2 -msg",
@@ -353,7 +353,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -392,7 +392,7 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -msg",
@@ -428,7 +428,7 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -host localhost -reconnect",
ct:log("openssl cmd: ~p~n", [Cmd]),
@@ -464,14 +464,14 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -513,14 +513,14 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -559,7 +559,7 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
{options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -host localhost -msg",
ct:log("openssl cmd: ~p~n", [Cmd]),
@@ -594,14 +594,14 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -636,7 +636,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
CaCertFile = proplists:get_value(cacertfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2",
@@ -644,7 +644,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -688,7 +688,7 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
KeyFile = proplists:get_value(keyfile, ClientOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
- ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ ++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -host localhost",
ct:log("openssl cmd: ~p~n", [Cmd]),
@@ -776,14 +776,14 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -839,7 +839,7 @@ expired_session(Config) when is_list(Config) ->
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client0 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -1033,14 +1033,14 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
ConnectionInfo = {ok, {Version, CipherSuite}},
@@ -1097,14 +1097,14 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server " ++ OpensslServerOpts ++ " -accept " ++
- integer_to_list(Port) ++ version_flag(Version) ++
+ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -1136,14 +1136,14 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
KeyFile = proplists:get_value(keyfile, ServerOpts),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- wait_for_openssl_server(),
+ ssl_test_lib:wait_for_openssl_server(),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -1174,7 +1174,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -host localhost",
ct:log("openssl cmd: ~p~n", [Cmd]),
@@ -1203,7 +1203,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
- Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
+ Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ ssl_test_lib:version_flag(Version) ++
" -host localhost",
ct:log("openssl cmd: ~p~n", [Cmd]),
@@ -1302,25 +1302,6 @@ server_sent_garbage(Socket) ->
end.
-wait_for_openssl_server() ->
- receive
- {Port, {data, Debug}} when is_port(Port) ->
- ct:log("openssl ~s~n",[Debug]),
- %% openssl has started make sure
- %% it will be in accept. Parsing
- %% output is too error prone. (Even
- %% more so than sleep!)
- ct:sleep(?SLEEP)
- end.
-
-version_flag(tlsv1) ->
- " -tls1 ";
-version_flag('tlsv1.1') ->
- " -tls1_1 ";
-version_flag('tlsv1.2') ->
- " -tls1_2 ";
-version_flag(sslv3) ->
- " -ssl3 ".
check_openssl_npn_support(Config) ->
HelpText = os:cmd("openssl s_client --help"),
@@ -1365,18 +1346,3 @@ supports_sslv2(Port) ->
true
end.
-check_sane_openssl_version(Version) ->
- case {Version, os:cmd("openssl version")} of
- {_, "OpenSSL 1.0.1" ++ _} ->
- true;
- {'tlsv1.2', "OpenSSL 1.0" ++ _} ->
- false;
- {'tlsv1.1', "OpenSSL 1.0" ++ _} ->
- false;
- {'tlsv1.2', "OpenSSL 0" ++ _} ->
- false;
- {'tlsv1.1', "OpenSSL 0" ++ _} ->
- false;
- {_, _} ->
- true
- end.