aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/src/ssl_certificate.erl47
-rw-r--r--lib/ssl/src/ssl_connection.erl113
-rw-r--r--lib/ssl/src/ssl_handshake.erl102
-rw-r--r--lib/ssl/test/erl_make_certs.erl51
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl87
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl40
-rw-r--r--lib/ssl/test/ssl_test_lib.erl19
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl24
-rw-r--r--lib/ssl/vsn.mk19
9 files changed, 298 insertions, 204 deletions
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 917e75157b..5026c760bd 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -31,7 +31,7 @@
-include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([trusted_cert_and_path/3,
+-export([trusted_cert_and_path/2,
certificate_chain/2,
file_to_certificats/1,
validate_extensions/6,
@@ -47,48 +47,46 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec trusted_cert_and_path([der_cert()], certdb_ref(), boolean()) ->
- {der_cert(), [der_cert()], list()}.
+-spec trusted_cert_and_path([der_cert()], certdb_ref()) ->
+ {der_cert() | unknown_ca, [der_cert()]}.
%%
%% Description: Extracts the root cert (if not presents tries to
%% look it up, if not found {bad_cert, unknown_ca} will be added verification
%% errors. Returns {RootCert, Path, VerifyErrors}
%%--------------------------------------------------------------------
-trusted_cert_and_path(CertChain, CertDbRef, Verify) ->
- [Cert | RestPath] = lists:reverse(CertChain),
+trusted_cert_and_path(CertChain, CertDbRef) ->
+ Path = [Cert | _] = lists:reverse(CertChain),
OtpCert = public_key:pkix_decode_cert(Cert, otp),
- IssuerAnPath =
+ IssuerID =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
{ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self),
- {IssuerId, RestPath};
- false ->
+ IssuerId;
+ false ->
case public_key:pkix_issuer_id(OtpCert, other) of
{ok, IssuerId} ->
- {IssuerId, [Cert | RestPath]};
+ IssuerId;
{error, issuer_not_found} ->
case find_issuer(OtpCert, no_candidate) of
{ok, IssuerId} ->
- {IssuerId, [Cert | RestPath]};
+ IssuerId;
Other ->
- {Other, RestPath}
+ Other
end
end
end,
- case IssuerAnPath of
- {{error, issuer_not_found}, _ } ->
- %% The root CA was not sent and can not be found, we fail if verify = true
- not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA), Verify, {Cert, RestPath});
- {{SerialNr, Issuer}, Path} ->
- case ssl_manager:lookup_trusted_cert(CertDbRef,
- SerialNr, Issuer) of
+ case IssuerID of
+ {error, issuer_not_found} ->
+ %% The root CA was not sent and can not be found.
+ {unknown_ca, Path};
+ {SerialNr, Issuer} ->
+ case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of
{ok, {BinCert,_}} ->
- {BinCert, Path, []};
+ {BinCert, Path};
_ ->
- %% Fail if verify = true
- not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA),
- Verify, {Cert, RestPath})
+ %% Root CA could not be verified
+ {unknown_ca, Path}
end
end.
@@ -244,11 +242,6 @@ find_issuer(OtpCert, PrevCandidateKey) ->
end
end.
-not_valid(Alert, true, _) ->
- throw(Alert);
-not_valid(_, false, {ErlCert, Path}) ->
- {ErlCert, Path, [{bad_cert, unknown_ca}]}.
-
is_valid_extkey_usage(KeyUse, client) ->
%% Client wants to verify server
is_valid_key_usage(KeyUse,?'id-kp-serverAuth');
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 76422155a5..dd8f77a0ca 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -334,14 +334,12 @@ hello(start, #state{host = Host, port = Port, role = client,
ssl_options = SslOpts,
transport_cb = Transport, socket = Socket,
connection_states = ConnectionStates,
- own_cert = Cert,
renegotiation = {Renegotiation, _}}
= State0) ->
Hello = ssl_handshake:client_hello(Host, Port,
ConnectionStates,
- SslOpts, Cert,
- Renegotiation),
+ SslOpts, Renegotiation),
Version = Hello#client_hello.client_version,
Hashes0 = ssl_handshake:init_hashes(),
@@ -353,7 +351,7 @@ hello(start, #state{host = Host, port = Port, role = client,
session =
#session{session_id = Hello#client_hello.session_id,
is_resumable = false},
- tls_handshake_hashes = Hashes1},
+ tls_handshake_hashes = Hashes1},
{Record, State} = next_record(State1),
next_state(hello, Record, State);
@@ -579,58 +577,61 @@ certify(#client_key_exchange{} = Msg,
%% We expect a certificate here
handle_unexpected_message(Msg, certify_client_key_exchange, State);
-certify(#client_key_exchange{exchange_keys
- = #encrypted_premaster_secret{premaster_secret
- = EncPMS}},
- #state{negotiated_version = Version,
- connection_states = ConnectionStates0,
- session = Session0,
- private_key = Key} = State0) ->
- try ssl_handshake:decrypt_premaster_secret(EncPMS, Key) of
- PremasterSecret ->
- case ssl_handshake:master_secret(Version, PremasterSecret,
- ConnectionStates0, server) of
- {MasterSecret, ConnectionStates} ->
- Session = Session0#session{master_secret = MasterSecret},
- State1 = State0#state{connection_states = ConnectionStates,
- session = Session},
- {Record, State} = next_record(State1),
- next_state(cipher, Record, State);
- #alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_client_key_exchange, State0),
- {stop, normal, State0}
- end
+certify(#client_key_exchange{exchange_keys = Keys},
+ State = #state{key_algorithm = KeyAlg, negotiated_version = Version}) ->
+ try
+ certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version), State)
catch
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify_client_key_exchange,
- State0),
+ handle_own_alert(Alert, Version, certify_client_key_exchange, State),
+ {stop, normal, State}
+ end;
+
+certify(Msg, State) ->
+ handle_unexpected_message(Msg, certify, State).
+
+certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS},
+ #state{negotiated_version = Version,
+ connection_states = ConnectionStates0,
+ session = Session0,
+ private_key = Key} = State0) ->
+ PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
+ case ssl_handshake:master_secret(Version, PremasterSecret,
+ ConnectionStates0, server) of
+ {MasterSecret, ConnectionStates} ->
+ Session = Session0#session{master_secret = MasterSecret},
+ State1 = State0#state{connection_states = ConnectionStates,
+ session = Session},
+ {Record, State} = next_record(State1),
+ next_state(cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version,
+ certify_client_key_exchange, State0),
{stop, normal, State0}
end;
-certify(#client_key_exchange{exchange_keys = #client_diffie_hellman_public{
- dh_public = ClientPublicDhKey}},
- #state{negotiated_version = Version,
- diffie_hellman_params = #'DHParameter'{prime = P,
- base = G},
- diffie_hellman_keys = {_, ServerDhPrivateKey},
- role = Role,
- session = Session,
- connection_states = ConnectionStates0} = State0) ->
-
+certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
+ #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},
+ Session#session{master_secret
+ = MasterSecret},
+ connection_states = ConnectionStates},
{Record, State} = next_record(State1),
next_state(cipher, Record, State);
@@ -638,10 +639,7 @@ certify(#client_key_exchange{exchange_keys = #client_diffie_hellman_public{
handle_own_alert(Alert, Version,
certify_client_key_exchange, State0),
{stop, normal, State0}
- end;
-
-certify(Msg, State) ->
- handle_unexpected_message(Msg, certify, State).
+ end.
%%--------------------------------------------------------------------
-spec cipher(#hello_request{} | #certificate_verify{} | #finished{} | term(),
@@ -701,14 +699,13 @@ connection(#hello_request{}, #state{host = Host, port = Port,
socket = Socket,
ssl_options = SslOpts,
negotiated_version = Version,
- own_cert = Cert,
transport_cb = Transport,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _},
tls_handshake_hashes = Hashes0} = State0) ->
- Hello = ssl_handshake:client_hello(Host, Port,
- ConnectionStates0, SslOpts, Cert, Renegotiation),
+ Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0,
+ SslOpts, Renegotiation),
{BinMsg, ConnectionStates1, Hashes1} =
encode_handshake(Hello, Version, ConnectionStates0, Hashes0),
@@ -1638,8 +1635,6 @@ application_data(Data, #state{user_application = {_Mon, Pid},
true -> <<Buffer0/binary, Data/binary>>
end,
case get_data(SOpts, BytesToRead, Buffer1) of
- {ok, <<>>, Buffer} -> % no reply, we need more data
- next_record(State0#state{user_data_buffer = Buffer});
{ok, ClientData, Buffer} -> % Send data
SocketOpt = deliver_app_data(SOpts, ClientData, Pid, From),
State = State0#state{user_data_buffer = Buffer,
@@ -1655,12 +1650,16 @@ application_data(Data, #state{user_application = {_Mon, Pid},
true -> %% We have more data
application_data(<<>>, State)
end;
+ {more, Buffer} -> % no reply, we need more data
+ next_record(State0#state{user_data_buffer = Buffer});
{error,_Reason} -> %% Invalid packet in packet mode
deliver_packet_error(SOpts, Buffer1, Pid, From),
{stop, normal, State0}
end.
%% Picks ClientData
+get_data(_, _, <<>>) ->
+ {more, <<>>};
get_data(#socket_options{active=Active, packet=Raw}, BytesToRead, Buffer)
when Raw =:= raw; Raw =:= 0 -> %% Raw Mode
if
@@ -1673,13 +1672,13 @@ get_data(#socket_options{active=Active, packet=Raw}, BytesToRead, Buffer)
{ok, Data, Rest};
true ->
%% Passive Mode not enough data
- {ok, <<>>, Buffer}
+ {more, Buffer}
end;
get_data(#socket_options{packet=Type, packet_size=Size}, _, Buffer) ->
PacketOpts = [{packet_size, Size}],
case decode_packet(Type, Buffer, PacketOpts) of
{more, _} ->
- {ok, <<>>, Buffer};
+ {more, Buffer};
Decoded ->
Decoded
end.
@@ -1794,9 +1793,7 @@ next_state(Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
handle_alerts(Alerts, {next_state, Next, State});
next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
- State0 = #state{key_algorithm = KeyAlg,
- tls_handshake_buffer = Buf0,
- negotiated_version = Version}) ->
+ State0 = #state{tls_handshake_buffer = Buf0, negotiated_version = Version}) ->
Handle =
fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
%% This message should not be included in handshake
@@ -1819,7 +1816,7 @@ next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
(_, StopState) -> StopState
end,
try
- {Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0, KeyAlg,Version),
+ {Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0),
State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf},
handle_tls_handshake(Handle, StateName, State)
catch throw:#alert{} = Alert ->
@@ -1831,7 +1828,7 @@ next_state(StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State
case application_data(Data, State0) of
Stop = {stop,_,_} ->
Stop;
- {Record, State} ->
+ {Record, State} ->
next_state(StateName, Record, State)
end;
next_state(StateName, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 3d831eae02..add5147fb4 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -31,13 +31,13 @@
-include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/6, server_hello/4, hello/4,
+-export([master_secret/4, client_hello/5, server_hello/4, hello/4,
hello_request/0, certify/7, certificate/3,
client_certificate_verify/6,
certificate_verify/6, certificate_request/2,
key_exchange/2, server_key_exchange_hash/2, finished/4,
verify_connection/5,
- get_tls_handshake/4,
+ get_tls_handshake/2, decode_client_key/3,
server_hello_done/0, sig_alg/1,
encode_handshake/3, init_hashes/0,
update_hashes/2, decrypt_premaster_secret/2]).
@@ -52,13 +52,13 @@
%%====================================================================
%%--------------------------------------------------------------------
-spec client_hello(host(), port_num(), #connection_states{},
- #ssl_options{}, binary(), boolean()) -> #client_hello{}.
+ #ssl_options{}, boolean()) -> #client_hello{}.
%%
%% Description: Creates a client hello message.
%%--------------------------------------------------------------------
client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
ciphers = UserSuites}
- = SslOpts, Cert, Renegotiation) ->
+ = SslOpts, Renegotiation) ->
Fun = fun(Version) ->
ssl_record:protocol_version(Version)
@@ -203,18 +203,15 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef,
end
end,
try
- %% Allow missing root_cert and check that with VerifyFun
- ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbRef, false) of
- {TrustedErlCert, CertPath, VerifyErrors} ->
+ ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbRef) of
+ {TrustedErlCert, CertPath} ->
Result = public_key:pkix_path_validation(TrustedErlCert,
CertPath,
[{max_path_length,
MaxPathLen},
{verify, VerifyBool},
{validate_extensions_fun,
- ValidateExtensionFun},
- {acc_errors,
- VerifyErrors}]),
+ ValidateExtensionFun}]),
case Result of
{error, Reason} ->
path_validation_alert(Reason, Verify);
@@ -461,29 +458,36 @@ encode_handshake(Package, Version, KeyAlg) ->
[MsgType, ?uint24(Len), Bin].
%%--------------------------------------------------------------------
--spec get_tls_handshake(binary(), binary() | iolist(), key_algo(), tls_version()) ->
+-spec get_tls_handshake(binary(), binary() | iolist()) ->
{[tls_handshake()], binary()}.
%%
%% Description: Given buffered and new data from ssl_record, collects
%% and returns it as a list of handshake messages, also returns leftover
%% data.
%%--------------------------------------------------------------------
-get_tls_handshake(Data, <<>>, KeyAlg, Version) ->
- get_tls_handshake_aux(Data, KeyAlg, Version, []);
-get_tls_handshake(Data, Buffer, KeyAlg, Version) ->
- get_tls_handshake_aux(list_to_binary([Buffer, Data]),
- KeyAlg, Version, []).
+get_tls_handshake(Data, <<>>) ->
+ get_tls_handshake_aux(Data, []);
+get_tls_handshake(Data, Buffer) ->
+ get_tls_handshake_aux(list_to_binary([Buffer, Data]), []).
+
+%%--------------------------------------------------------------------
+-spec decode_client_key(binary(), key_algo(), tls_version()) ->
+ #encrypted_premaster_secret{} | #client_diffie_hellman_public{}.
+%%
+%% Description: Decode client_key data and return appropriate type
+%%--------------------------------------------------------------------
+decode_client_key(ClientKey, Type, Version) ->
+ dec_client_key(ClientKey, key_exchange_alg(Type), Version).
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
- Body:Length/binary,Rest/binary>>, KeyAlg,
- Version, Acc) ->
+ Body:Length/binary,Rest/binary>>, Acc) ->
Raw = <<?BYTE(Type), ?UINT24(Length), Body/binary>>,
- H = dec_hs(Type, Body, key_exchange_alg(KeyAlg), Version),
- get_tls_handshake_aux(Rest, KeyAlg, Version, [{H,Raw} | Acc]);
-get_tls_handshake_aux(Data, _KeyAlg, _Version, Acc) ->
+ H = dec_hs(Type, Body),
+ get_tls_handshake_aux(Rest, [{H,Raw} | Acc]);
+get_tls_handshake_aux(Data, Acc) ->
{lists:reverse(Acc), Data}.
verify_bool(verify_peer) ->
@@ -503,6 +507,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, unknown_ca}, _) ->
+ ?ALERT_REC(?FATAL, ?UNKNOWN_CA);
path_validation_alert(_, _) ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE).
@@ -729,7 +735,7 @@ master_secret(Version, MasterSecret, #security_parameters{
ServerCipherState, Role)}.
-dec_hs(?HELLO_REQUEST, <<>>, _, _) ->
+dec_hs(?HELLO_REQUEST, <<>>) ->
#hello_request{};
%% Client hello v2.
@@ -739,8 +745,7 @@ dec_hs(?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor),
?UINT16(CSLength), ?UINT16(0),
?UINT16(CDLength),
CipherSuites:CSLength/binary,
- ChallengeData:CDLength/binary>>,
- _, _) ->
+ ChallengeData:CDLength/binary>>) ->
?DBG_HEX(CipherSuites),
?DBG_HEX(CipherSuites),
#client_hello{client_version = {Major, Minor},
@@ -754,8 +759,7 @@ dec_hs(?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
?UINT16(Cs_length), CipherSuites:Cs_length/binary,
?BYTE(Cm_length), Comp_methods:Cm_length/binary,
- Extensions/binary>>,
- _, _) ->
+ Extensions/binary>>) ->
RenegotiationInfo = proplists:get_value(renegotiation_info, dec_hello_extensions(Extensions),
undefined),
@@ -770,7 +774,7 @@ dec_hs(?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
dec_hs(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
- Cipher_suite:2/binary, ?BYTE(Comp_method)>>, _, _) ->
+ Cipher_suite:2/binary, ?BYTE(Comp_method)>>) ->
#server_hello{
server_version = {Major,Minor},
random = Random,
@@ -782,7 +786,7 @@ dec_hs(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
dec_hs(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
Cipher_suite:2/binary, ?BYTE(Comp_method),
- ?UINT16(ExtLen), Extensions:ExtLen/binary>>, _, _) ->
+ ?UINT16(ExtLen), Extensions:ExtLen/binary>>) ->
RenegotiationInfo = proplists:get_value(renegotiation_info, dec_hello_extensions(Extensions, []),
undefined),
@@ -793,44 +797,42 @@ dec_hs(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo};
-dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>, _, _) ->
+dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
#certificate{asn1_certificates = certs_to_list(ASN1Certs)};
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>>,
- ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
+ ?UINT16(Len), Sig:Len/binary>>) ->
#server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
dh_y = Y},
signed_params = Sig};
dec_hs(?CERTIFICATE_REQUEST,
<<?BYTE(CertTypesLen), CertTypes:CertTypesLen/binary,
- ?UINT16(CertAuthsLen), CertAuths:CertAuthsLen/binary>>, _, _) ->
+ ?UINT16(CertAuthsLen), CertAuths:CertAuthsLen/binary>>) ->
#certificate_request{certificate_types = CertTypes,
certificate_authorities = CertAuths};
-dec_hs(?SERVER_HELLO_DONE, <<>>, _, _) ->
+dec_hs(?SERVER_HELLO_DONE, <<>>) ->
#server_hello_done{};
-dec_hs(?CERTIFICATE_VERIFY,<<?UINT16(_), Signature/binary>>, _, _)->
+dec_hs(?CERTIFICATE_VERIFY,<<?UINT16(_), Signature/binary>>)->
#certificate_verify{signature = Signature};
-dec_hs(?CLIENT_KEY_EXCHANGE, PKEPMS, ?KEY_EXCHANGE_RSA, {3, 0}) ->
- PreSecret = #encrypted_premaster_secret{premaster_secret = PKEPMS},
- #client_key_exchange{exchange_keys = PreSecret};
-dec_hs(?CLIENT_KEY_EXCHANGE, <<?UINT16(_), PKEPMS/binary>>,
- ?KEY_EXCHANGE_RSA, _) ->
- PreSecret = #encrypted_premaster_secret{premaster_secret = PKEPMS},
- #client_key_exchange{exchange_keys = PreSecret};
-dec_hs(?CLIENT_KEY_EXCHANGE, <<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
- throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
-dec_hs(?CLIENT_KEY_EXCHANGE, <<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
- ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
- #client_key_exchange{exchange_keys =
- #client_diffie_hellman_public{dh_public = DH_Y}};
-dec_hs(?FINISHED, VerifyData, _, _) ->
+dec_hs(?CLIENT_KEY_EXCHANGE, PKEPMS) ->
+ #client_key_exchange{exchange_keys = PKEPMS};
+dec_hs(?FINISHED, VerifyData) ->
#finished{verify_data = VerifyData};
-dec_hs(_, _, _, _) ->
+dec_hs(_, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
+dec_client_key(PKEPMS, ?KEY_EXCHANGE_RSA, {3, 0}) ->
+ #encrypted_premaster_secret{premaster_secret = PKEPMS};
+dec_client_key(<<?UINT16(_), PKEPMS/binary>>, ?KEY_EXCHANGE_RSA, _) ->
+ #encrypted_premaster_secret{premaster_secret = PKEPMS};
+dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
+ #client_diffie_hellman_public{dh_public = DH_Y}.
+
dec_hello_extensions(<<>>) ->
[];
dec_hello_extensions(<<?UINT16(ExtLen), Extensions:ExtLen/binary>>) ->
@@ -1126,7 +1128,7 @@ sig_alg(_) ->
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_anon ->
+ Alg == dh_dss; Alg == dh_rsa ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
key_exchange_alg(_) ->
?NULL.
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index c9db0d3851..f8aef55754 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -66,9 +66,9 @@ make_cert(Opts) ->
%% @end
%%--------------------------------------------------------------------
write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
- ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ ".pem"),
+ ok = der_to_pem(filename:join(Dir, FileName ++ ".pem"),
[{'Certificate', Cert, not_encrypted}]),
- ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
+ ok = der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
%%--------------------------------------------------------------------
%% @doc Creates a rsa key (OBS: for testing only)
@@ -144,34 +144,39 @@ encode_key(Key = #'DSAPrivateKey'{}) ->
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
- {Issuer, IssuerKey} = issuer(Opts, SubjectKey),
+
+ IssuerProp = proplists:get_value(issuer, Opts, true),
+ {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey),
{Algo, Parameters} = sign_algorithm(IssuerKey, Opts),
SignAlgo = #'SignatureAlgorithm'{algorithm = Algo,
parameters = Parameters},
-
+ Subject = case IssuerProp of
+ true -> %% Is a Root Ca
+ Issuer;
+ _ ->
+ subject(proplists:get_value(subject, Opts),false)
+ end,
+
{#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1,
signature = SignAlgo,
issuer = Issuer,
validity = validity(Opts),
- subject = subject(proplists:get_value(subject, Opts),false),
+ subject = Subject,
subjectPublicKeyInfo = publickey(SubjectKey),
version = Version,
extensions = extensions(Opts)
}, IssuerKey}.
-issuer(Opts, SubjectKey) ->
- IssuerProp = proplists:get_value(issuer, Opts, true),
- case IssuerProp of
- true -> %% Self signed
- {subject(proplists:get_value(subject, Opts), true), SubjectKey};
- {Issuer, IssuerKey} when is_binary(Issuer) ->
- {issuer_der(Issuer), decode_key(IssuerKey)};
- {File, IssuerKey} when is_list(File) ->
- {ok, [{cert, Cert, _}|_]} = public_key:pem_to_der(File),
- {issuer_der(Cert), decode_key(IssuerKey)}
- end.
+issuer(true, Opts, SubjectKey) ->
+ %% Self signed
+ {subject(proplists:get_value(subject, Opts), true), SubjectKey};
+issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) ->
+ {issuer_der(Issuer), decode_key(IssuerKey)};
+issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) ->
+ {ok, [{cert, Cert, _}|_]} = public_key:pem_to_der(File),
+ {issuer_der(Cert), decode_key(IssuerKey)}.
issuer_der(Issuer) ->
Decoded = public_key:pkix_decode_cert(Issuer, otp),
@@ -179,8 +184,8 @@ issuer_der(Issuer) ->
#'OTPTBSCertificate'{subject=Subject} = Tbs,
Subject.
-subject(undefined, IsCA) ->
- User = if IsCA -> "CA"; true -> os:getenv("USER") end,
+subject(undefined, IsRootCA) ->
+ User = if IsRootCA -> "RootCA"; true -> os:getenv("USER") end,
Opts = [{email, User ++ "@erlang.org"},
{name, User},
{city, "Stockholm"},
@@ -267,7 +272,7 @@ publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
#'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
validity(Opts) ->
- DefFrom0 = date(),
+ DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7),
{DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}),
Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end,
@@ -406,3 +411,11 @@ extended_gcd(A, B) ->
{X, Y} = extended_gcd(B, N),
{Y, X-Y*(A div B)}
end.
+
+pem_to_der(File) ->
+ {ok, PemBin} = file:read_file(File),
+ public_key:pem_decode(PemBin).
+
+der_to_pem(File, Entries) ->
+ PemBin = public_key:pem_encode(Entries),
+ file:write_file(File, PemBin).
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 53142250e8..d50b34b6ac 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -7,7 +7,7 @@
%% 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/.
+%% 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
@@ -234,7 +234,8 @@ all(suite) ->
server_no_wrap_sequence_number, extended_key_usage,
validate_extensions_fun, no_authority_key_identifier,
invalid_signature_client, invalid_signature_server, cert_expired,
- client_with_cert_cipher_suites_handshake
+ client_with_cert_cipher_suites_handshake, unknown_server_ca_fail,
+ unknown_server_ca_accept
].
%% Test cases starts here.
@@ -1553,25 +1554,26 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, true),
test_server:format("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
+
+ ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
+
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
{options,
[{ciphers,[CipherSuite]} |
ClientOpts]}]),
-
- ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
-
- ServerMsg = ClientMsg = {ok, {Version, ErlangCipherSuite}},
-
- Result = ssl_test_lib:wait_for_result(Server, ServerMsg,
- Client, ClientMsg),
+
+ Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
+
ssl_test_lib:close(Server),
receive
{'EXIT', Server, normal} ->
@@ -2612,12 +2614,13 @@ validate_extensions_fun(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
no_authority_key_identifier(doc) ->
- ["Test cert that does not have authorityKeyIdentifier extension"];
+ ["Test cert that does not have authorityKeyIdentifier extension"
+ " but are present in trusted certs db."];
no_authority_key_identifier(suite) ->
[];
no_authority_key_identifier(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_opts, Config),
PrivDir = ?config(priv_dir, Config),
@@ -2675,7 +2678,7 @@ invalid_signature_server(suite) ->
[];
invalid_signature_server(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_verification_opts, Config),
PrivDir = ?config(priv_dir, Config),
@@ -2792,7 +2795,7 @@ cert_expired(suite) ->
[];
cert_expired(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_verification_opts, Config),
PrivDir = ?config(priv_dir, Config),
@@ -2881,6 +2884,59 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+unknown_server_ca_fail(doc) ->
+ ["Test that the client fails if the ca is unknown in verify_peer mode"];
+unknown_server_ca_fail(suite) ->
+ [];
+unknown_server_ca_fail(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error,"unknown ca"}, Client, {error, "unknown ca"}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+unknown_server_ca_accept(doc) ->
+ ["Test that the client succeds if the ca is unknown in verify_none mode"];
+unknown_server_ca_accept(suite) ->
+ [];
+unknown_server_ca_accept(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_active, []}},
+ {options,
+ [{verify, verify_none}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
%%% Internal functions
@@ -2907,6 +2963,7 @@ send_recv_result_active_once(Socket) ->
result_ok(_Socket) ->
ok.
+
renegotiate(Socket, Data) ->
test_server:format("Renegotiating ~n", []),
Result = ssl:renegotiate(Socket),
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 9553241ad4..1e7cde1c25 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -2196,21 +2196,29 @@ header_decode_two_bytes_one_sent(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
%% Internal functions
-send_raw(_,_, 0) ->
+send_raw(Socket,_, 0) ->
+ ssl:send(Socket, <<>>),
no_result_msg;
send_raw(Socket, Data, N) ->
ssl:send(Socket, Data),
send_raw(Socket, Data, N-1).
-passive_raw(_, _, 0) ->
+passive_raw(Socket, _, 0) ->
+ {error, timeout} = ssl:recv(Socket, 0, 500),
ok;
passive_raw(Socket, Data, N) ->
Length = length(Data),
{ok, Data} = ssl:recv(Socket, Length),
passive_raw(Socket, Data, N-1).
-passive_recv_packet(_, _, 0) ->
- ok;
+passive_recv_packet(Socket, _, 0) ->
+ case ssl:recv(Socket, 0) of
+ {ok, []} ->
+ {error, timeout} = ssl:recv(Socket, 0, 500),
+ ok;
+ Other ->
+ {other, Other, ssl:session_info(Socket), 0}
+ end;
passive_recv_packet(Socket, Data, N) ->
case ssl:recv(Socket, 0) of
{ok, Data} ->
@@ -2219,7 +2227,8 @@ passive_recv_packet(Socket, Data, N) ->
{other, Other, ssl:session_info(Socket), N}
end.
-send(_,_, 0) ->
+send(Socket,_, 0) ->
+ ssl:send(Socket, <<>>),
no_result_msg;
send(Socket, Data, N) ->
case ssl:send(Socket, [Data]) of
@@ -2233,6 +2242,7 @@ send_incomplete(Socket, Data, N) ->
send_incomplete(Socket, Data, N, <<>>).
send_incomplete(Socket, _Data, 0, Prev) ->
ssl:send(Socket, Prev),
+ ssl:send(Socket, [?uint32(0)]),
no_result_msg;
send_incomplete(Socket, Data, N, Prev) ->
Length = size(Data),
@@ -2261,8 +2271,13 @@ active_once_raw(Socket, Data, N, Acc) ->
end
end.
-active_once_packet(_,_, 0) ->
- ok;
+active_once_packet(Socket,_, 0) ->
+ receive
+ {ssl, Socket, []} ->
+ ok;
+ {ssl, Socket, Other} ->
+ {other, Other, ssl:session_info(Socket), 0}
+ end;
active_once_packet(Socket, Data, N) ->
receive
{ssl, Socket, Data} ->
@@ -2274,7 +2289,7 @@ active_once_packet(Socket, Data, N) ->
active_raw(Socket, Data, N) ->
active_raw(Socket, Data, N, []).
-active_raw(_, _, 0, _) ->
+active_raw(_Socket, _, 0, _) ->
ok;
active_raw(Socket, Data, N, Acc) ->
receive
@@ -2289,8 +2304,13 @@ active_raw(Socket, Data, N, Acc) ->
end
end.
-active_packet(_, _, 0) ->
- ok;
+active_packet(Socket, _, 0) ->
+ receive
+ {ssl, Socket, []} ->
+ ok;
+ Other ->
+ {other, Other, ssl:session_info(Socket), 0}
+ end;
active_packet(Socket, Data, N) ->
receive
{ssl, Socket, Data} ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index c7ff015034..ce164f7e4c 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -332,7 +332,7 @@ make_dsa_cert(Config) ->
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_dsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
- {cacertfile, ServerCaCertFile},
+ {cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
@@ -623,3 +623,20 @@ pem_to_der(File) ->
der_to_pem(File, Entries) ->
PemBin = public_key:pem_encode(Entries),
file:write_file(File, PemBin).
+
+cipher_result(Socket, Result) ->
+ Result = ssl:connection_info(Socket),
+ test_server:format("Successfull connect: ~p~n", [Result]),
+ %% Importante to send two packets here
+ %% to properly test "cipher state" handling
+ ssl:send(Socket, "Hello\n"),
+ receive
+ {ssl, Socket, "Hello\n"} ->
+ ssl:send(Socket, " world\n"),
+ receive
+ {ssl, Socket, " world\n"} ->
+ ok
+ end;
+ Other ->
+ {unexpected, Other}
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 75cfce0052..7f512f2ab9 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1136,17 +1136,31 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
wait_for_openssl_server(),
+ ConnectionInfo = {ok, {Version, CipherSuite}},
+
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
{options,
[{ciphers,[CipherSuite]} |
ClientOpts]}]),
-
- ClientMsg = {ok, {Version, CipherSuite}},
-
- Result = ssl_test_lib:wait_for_result(Client, ClientMsg),
+
+ port_command(OpenSslPort, "Hello\n"),
+
+ receive
+ {Port, {data, _}} when is_port(Port) ->
+ ok
+ after 500 ->
+ test_server:format("Time out on openssl port, check that"
+ " the messages Hello and world are received"
+ " during close of port" , []),
+ ok
+ end,
+
+ port_command(OpenSslPort, " world\n"),
+
+ Result = ssl_test_lib:wait_for_result(Client, ok),
close_port(OpenSslPort),
%% Clean close down!
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 6c40a4529c..709a089892 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1,20 +1 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-
SSL_VSN = 4.0.1