aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ssl/src/ssl_cipher.erl5
-rw-r--r--lib/ssl/src/ssl_connection.erl21
-rw-r--r--lib/ssl/src/ssl_handshake.erl113
-rw-r--r--lib/ssl/src/ssl_handshake.hrl6
-rw-r--r--lib/ssl/src/ssl_ssl3.erl2
-rw-r--r--lib/ssl/src/ssl_tls1.erl4
6 files changed, 85 insertions, 66 deletions
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 9e1fbe20f4..8b6d5ea4ea 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -35,7 +35,8 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
suite/1, suites/1, anonymous_suites/0,
- openssl_suite/1, openssl_suite_name/1, filter/2]).
+ openssl_suite/1, openssl_suite_name/1, filter/2,
+ hash_algorithm/1, sign_algorithm/1]).
-compile(inline).
@@ -608,7 +609,7 @@ hash_algorithm(sha512) -> ?SHA512;
hash_algorithm(?NULL) -> null;
hash_algorithm(?MD5) -> md5;
hash_algorithm(?SHA) -> sha;
-%%hash_algorithm(?SHA224) -> sha224;
+hash_algorithm(?SHA224) -> sha224;
hash_algorithm(?SHA256) -> sha256;
hash_algorithm(?SHA384) -> sha384;
hash_algorithm(?SHA512) -> sha512.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 0d3efae5f4..19847575e5 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -77,6 +77,7 @@
supported_protocol_versions, % [atom()]
client_certificate_requested = false,
key_algorithm, % atom as defined by cipher_suite
+ hashsign_algorithm, % atom as defined by cipher_suite
public_key_info, % PKIX: {Algorithm, PublicKey, PublicKeyParams}
private_key, % PKIX: #'RSAPrivateKey'{}
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
@@ -380,6 +381,7 @@ hello(#server_hello{cipher_suite = CipherSuite,
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
State = State0#state{key_algorithm = KeyAlgorithm,
+ hashsign_algorithm = default_hashsign(Version, KeyAlgorithm),
negotiated_version = Version,
connection_states = ConnectionStates,
premaster_secret = PremasterSecret},
@@ -643,10 +645,11 @@ cipher(#certificate_verify{signature = Signature},
public_key_info = PublicKeyInfo,
negotiated_version = Version,
session = #session{master_secret = MasterSecret},
+ hashsign_algorithm = HashSign,
tls_handshake_history = Handshake
} = State0) ->
case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
- Version, MasterSecret, Handshake) of
+ Version, HashSign, MasterSecret, Handshake) of
valid ->
{Record, State} = next_record(State0),
next_state(cipher, cipher, Record, State);
@@ -1247,10 +1250,11 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
private_key = PrivateKey,
session = #session{master_secret = MasterSecret,
own_certificate = OwnCert},
+ hashsign_algorithm = HashSign,
tls_handshake_history = Handshake0} = State) ->
case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
- Version, PrivateKey, Handshake0) of
+ Version, HashSign, PrivateKey, Handshake0) of
#certificate_verify{} = Verified ->
{BinVerified, ConnectionStates, Handshake} =
encode_handshake(Verified, Version,
@@ -1391,7 +1395,8 @@ server_hello(ServerHello, #state{transport_cb = Transport,
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates1,
tls_handshake_history = Handshake1,
- key_algorithm = KeyAlgorithm}.
+ key_algorithm = KeyAlgorithm,
+ hashsign_algorithm = default_hashsign(Version, KeyAlgorithm)}.
server_hello_done(#state{transport_cb = Transport,
socket = Socket,
@@ -1433,6 +1438,7 @@ certify_server(#state{transport_cb = Transport,
key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
+ hashsign_algorithm = {HashAlgo, _},
diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
@@ -1451,7 +1457,7 @@ key_exchange(#state{role = server, key_algorithm = Algo,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params,
- Algo, ClientRandom,
+ HashAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
{BinMsg, ConnectionStates, Handshake} =
@@ -1577,22 +1583,23 @@ handle_server_key(
#server_dh_params{dh_p = P,
dh_g = G,
dh_y = ServerPublicDhKey},
- signed_params = Signed},
+ signed_params = Signed,
+ hashsign = HashSign},
#state{negotiated_version = Version,
public_key_info = PubKeyInfo,
- key_algorithm = KeyAlgo,
connection_states = ConnectionStates} = State) ->
PLen = size(P),
GLen = size(G),
YLen = size(ServerPublicDhKey),
+ HashAlgo = connection_hash_algo(HashSign, State),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Hash = ssl_handshake:server_key_exchange_hash(KeyAlgo,
+ Hash = ssl_handshake:server_key_exchange_hash(HashAlgo,
<<ClientRandom/binary,
ServerRandom/binary,
?UINT16(PLen), P/binary,
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 7dba77560c..0d681e9fcb 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -32,7 +32,7 @@
-export([master_secret/4, client_hello/8, server_hello/4, hello/4,
hello_request/0, certify/7, certificate/4,
- client_certificate_verify/5, certificate_verify/5,
+ client_certificate_verify/6, certificate_verify/6,
certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
finished/5, verify_connection/6, get_tls_handshake/3,
decode_client_key/3, server_hello_done/0,
@@ -258,31 +258,31 @@ certificate(OwnCert, CertDbHandle, CertDbRef, server) ->
%%--------------------------------------------------------------------
-spec client_certificate_verify(undefined | der_cert(), binary(),
- tls_version(), private_key(),
+ tls_version(), term(), private_key(),
tls_handshake_history()) ->
#certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
%%--------------------------------------------------------------------
-client_certificate_verify(undefined, _, _, _, _) ->
+client_certificate_verify(undefined, _, _, _, _, _) ->
ignore;
-client_certificate_verify(_, _, _, undefined, _) ->
+client_certificate_verify(_, _, _, _, undefined, _) ->
ignore;
client_certificate_verify(OwnCert, MasterSecret, Version,
+ {HashAlgo, SignAlgo},
PrivateKey, {Handshake, _}) ->
case public_key:pkix_is_fixed_dh_cert(OwnCert) of
true ->
?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE);
- false ->
- Hashes =
- calc_certificate_verify(Version, MasterSecret,
- alg_oid(PrivateKey), Handshake),
- Signed = digitally_signed(Hashes, PrivateKey),
- #certificate_verify{signature = Signed}
+ false ->
+ Hashes =
+ calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
+ Signed = digitally_signed(Version, Hashes, HashAlgo, PrivateKey),
+ #certificate_verify{signature = Signed, hashsign_algorithm = {HashAlgo, SignAlgo}}
end.
%%--------------------------------------------------------------------
--spec certificate_verify(binary(), public_key_info(), tls_version(),
+-spec certificate_verify(binary(), public_key_info(), tls_version(), term(),
binary(), tls_handshake_history()) -> valid | #alert{}.
%%
%% Description: Checks that the certificate_verify message is valid.
@@ -296,18 +296,25 @@ certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, {Major, Minor})
certificate_verify_rsa(Hashes, _HashAlgo, Signature, PublicKey, _Version) ->
case public_key:decrypt_public(Signature, PublicKey,
[{rsa_pad, rsa_pkcs1_padding}]) of
- Hashes ->
+ Hashes -> true;
+ _ -> false
+ end.
+
+certificate_verify(Signature, {?'rsaEncryption', PublicKey, _}, Version,
+ {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) ->
+ Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
+ case certificate_verify_rsa(Hashes, HashAlgo, Signature, PublicKey, Version) of
+ true ->
valid;
_ ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
end;
-certificate_verify(Signature, {?'id-dsa' = Algorithm, PublicKey, PublicKeyParams}, Version,
- MasterSecret, {_, Handshake}) ->
- Hashes = calc_certificate_verify(Version, MasterSecret,
- Algorithm, Handshake),
+certificate_verify(Signature, {?'id-dsa', PublicKey, PublicKeyParams}, Version,
+ {HashAlgo, _SignAlgo}, MasterSecret, {_, Handshake}) ->
+ Hashes = calc_certificate_verify(Version, HashAlgo, MasterSecret, Handshake),
case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of
- true ->
- valid;
+ true ->
+ valid;
false ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
end.
@@ -324,9 +331,11 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
#security_parameters{cipher_suite = CipherSuite}} =
ssl_record:pending_connection_state(ConnectionStates, read),
Types = certificate_types(CipherSuite),
+ HashSigns = hashsign_algorithms(CipherSuite),
Authorities = certificate_authorities(CertDbHandle, CertDbRef),
#certificate_request{
certificate_types = Types,
+ hashsign_algorithms = HashSigns,
certificate_authorities = Authorities
}.
@@ -334,7 +343,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
-spec key_exchange(client | server, tls_version(),
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
- {dh, {binary(), binary()}, #'DHParameter'{}, key_algo(),
+ {dh, {binary(), binary()}, #'DHParameter'{}, hash_algo(),
binary(), binary(), private_key()}) ->
#client_key_exchange{} | #server_key_exchange{}.
%%
@@ -351,9 +360,9 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
dh_public = PublicKey}
};
-key_exchange(server, _Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
+key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
#'DHParameter'{prime = P, base = G},
- KeyAlgo, ClientRandom, ServerRandom, PrivateKey}) ->
+ HashAlgo, ClientRandom, ServerRandom, PrivateKey}) ->
<<?UINT32(_), PBin/binary>> = crypto:mpint(P),
<<?UINT32(_), GBin/binary>> = crypto:mpint(G),
PLen = byte_size(PBin),
@@ -362,20 +371,22 @@ key_exchange(server, _Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
ServerDHParams = #server_dh_params{dh_p = PBin,
dh_g = GBin, dh_y = PublicKey},
- case KeyAlgo of
- dh_anon ->
+ case HashAlgo of
+ null ->
#server_key_exchange{params = ServerDHParams,
- signed_params = <<>>};
+ signed_params = <<>>,
+ hashsign = {null, anon}};
_ ->
Hash =
- server_key_exchange_hash(KeyAlgo, <<ClientRandom/binary,
+ server_key_exchange_hash(HashAlgo, <<ClientRandom/binary,
ServerRandom/binary,
?UINT16(PLen), PBin/binary,
?UINT16(GLen), GBin/binary,
?UINT16(YLen), PublicKey/binary>>),
- Signed = digitally_signed(Hash, PrivateKey),
+ Signed = digitally_signed(Version, Hash, HashAlgo, PrivateKey),
#server_key_exchange{params = ServerDHParams,
- signed_params = Signed}
+ signed_params = Signed,
+ hashsign = {HashAlgo, digitally_signed_alg(PrivateKey)}}
end.
%%--------------------------------------------------------------------
@@ -527,6 +538,7 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
[{rsa_pad, rsa_pkcs1_padding}])
catch
_:_ ->
+ io:format("decrypt_premaster_secret error"),
throw(?ALERT_REC(?FATAL, ?DECRYPT_ERROR))
end.
@@ -535,14 +547,13 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
%%
%% Description: Calculate server key exchange hash
%%--------------------------------------------------------------------
-server_key_exchange_hash(Algorithm, Value) when Algorithm == rsa;
- Algorithm == dhe_rsa ->
+server_key_exchange_hash(md5sha, Value) ->
MD5 = crypto:md5(Value),
- SHA = crypto:sha(Value),
+ SHA = crypto:sha(Value),
<<MD5/binary, SHA/binary>>;
-server_key_exchange_hash(dhe_dss, Value) ->
- crypto:sha(Value).
+server_key_exchange_hash(Hash, Value) ->
+ crypto:hash(Hash, Value).
%%--------------------------------------------------------------------
-spec prf(tls_version(), binary(), binary(), [binary()], non_neg_integer()) ->
@@ -878,14 +889,14 @@ dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
?UINT16(0)>>) -> %% May happen if key_algorithm is dh_anon
#server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
dh_y = Y},
- signed_params = <<>>};
+ signed_params = <<>>, hashsign = {null, anon}};
dec_hs(_Version, ?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P:PLen/binary,
?UINT16(GLen), G:GLen/binary,
?UINT16(YLen), Y:YLen/binary,
?UINT16(Len), Sig:Len/binary>>) ->
#server_key_exchange{params = #server_dh_params{dh_p = P,dh_g = G,
dh_y = Y},
- signed_params = Sig};
+ signed_params = Sig, hashsign = undefined};
dec_hs(_Version, ?CERTIFICATE_REQUEST,
<<?BYTE(CertTypesLen), CertTypes:CertTypesLen/binary,
?UINT16(CertAuthsLen), CertAuths:CertAuthsLen/binary>>) ->
@@ -894,7 +905,7 @@ dec_hs(_Version, ?CERTIFICATE_REQUEST,
dec_hs(_Version, ?SERVER_HELLO_DONE, <<>>) ->
#server_hello_done{};
dec_hs(_Version, ?CERTIFICATE_VERIFY,<<?UINT16(SignLen), Signature:SignLen/binary>>)->
- #certificate_verify{signature = Signature};
+ #certificate_verify{hashsign_algorithm = {unknown, unknown}, signature = Signature};
dec_hs(_Version, ?CLIENT_KEY_EXCHANGE, PKEPMS) ->
#client_key_exchange{exchange_keys = PKEPMS};
dec_hs(_Version, ?FINISHED, VerifyData) ->
@@ -1005,15 +1016,15 @@ enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
{?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>};
enc_hs(#server_key_exchange{params = #server_dh_params{
dh_p = P, dh_g = G, dh_y = Y},
- signed_params = SignedParams}, _Version) ->
+ signed_params = SignedParams, hashsign = HashSign}, Version) ->
PLen = byte_size(P),
GLen = byte_size(G),
YLen = byte_size(Y),
- SignedLen = byte_size(SignedParams),
+ Signature = enc_sign(HashSign, SignedParams, Version),
{?SERVER_KEY_EXCHANGE, <<?UINT16(PLen), P/binary,
?UINT16(GLen), G/binary,
?UINT16(YLen), Y/binary,
- ?UINT16(SignedLen), SignedParams/binary>>
+ Signature/binary>>
};
enc_hs(#certificate_request{certificate_types = CertTypes,
certificate_authorities = CertAuths},
@@ -1028,8 +1039,8 @@ enc_hs(#server_hello_done{}, _Version) ->
{?SERVER_HELLO_DONE, <<>>};
enc_hs(#client_key_exchange{exchange_keys = ExchangeKeys}, Version) ->
{?CLIENT_KEY_EXCHANGE, enc_cke(ExchangeKeys, Version)};
-enc_hs(#certificate_verify{signature = BinSig}, _) ->
- EncSig = enc_bin_sig(BinSig),
+enc_hs(#certificate_verify{signature = BinSig, hashsign_algorithm = HashSign}, Version) ->
+ EncSig = enc_sign(HashSign, BinSig, Version),
{?CERTIFICATE_VERIFY, EncSig};
enc_hs(#finished{verify_data = VerifyData}, _Version) ->
{?FINISHED, VerifyData}.
@@ -1043,9 +1054,9 @@ enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
<<?UINT16(Len), DHPublic/binary>>.
-enc_bin_sig(BinSig) ->
- Size = byte_size(BinSig),
- <<?UINT16(Size), BinSig/binary>>.
+enc_sign(_HashSign, Sign, _Version) ->
+ SignLen = byte_size(Sign),
+ <<?UINT16(SignLen), Sign/binary>>.
%% Renegotiation info, only current extension
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
@@ -1125,7 +1136,7 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
[Cert | Acc];
(_, Acc) ->
Acc
- end,
+ end,
ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle).
@@ -1135,10 +1146,11 @@ digitally_signed(_Version, Hash, _HashAlgo, #'DSAPrivateKey'{} = Key) ->
public_key:sign({digest, Hash}, sha, Key);
digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
- [{rsa_pad, rsa_pkcs1_padding}]);
-digitally_signed(Hash, #'DSAPrivateKey'{} = Key) ->
- public_key:sign(Hash, none, Key).
-
+ [{rsa_pad, rsa_pkcs1_padding}]).
+
+digitally_signed_alg(#'RSAPrivateKey'{} = _Key) -> rsa;
+digitally_signed_alg(#'DSAPrivateKey'{} = _Key) -> dsa.
+
calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
@@ -1182,8 +1194,3 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
{unknown, UserState} ->
{unknown, {SslState, UserState}}
end.
-
-alg_oid(#'RSAPrivateKey'{}) ->
- ?'rsaEncryption';
-alg_oid(#'DSAPrivateKey'{}) ->
- ?'id-dsa'.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 20e498ea2e..abe2fa5261 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -32,6 +32,7 @@
-type public_key_params() :: #'Dss-Parms'{} | term().
-type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}.
-type tls_handshake_history() :: {[binary()], [binary()]}.
+-type hash_algo() :: atom().
%% Signature algorithms
-define(ANON, 0).
@@ -136,7 +137,8 @@
-record(server_key_exchange, {
params, %% #server_rsa_params{} | #server_dh_params{}
- signed_params %% #signature{}
+ signed_params, %% #signature{}
+ hashsign %% term(atom(), atom())
}).
%% enum { anonymous, rsa, dsa } SignatureAlgorithm;
@@ -166,6 +168,7 @@
-record(certificate_request, {
certificate_types, %ClientCertificateType <1..2^8-1>
+ hashsign_algorithms, %%SignatureAndHashAlgorithm <2^16-1>;
certificate_authorities %DistinguishedName <0..2^16-1>
}).
@@ -200,6 +203,7 @@
%%% Certificate verify - RFC 4346 section 7.4.8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-record(certificate_verify, {
+ hashsign_algorithm,
signature % binary()
}).
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index bb368fe5d0..a11c5b8c0c 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -76,7 +76,7 @@ finished(Role, MasterSecret, Handshake) ->
-spec certificate_verify(md5sha | sha, binary(), [binary()]) -> binary().
-certificate_verify(?'rsaEncryption', MasterSecret, Handshake) ->
+certificate_verify(md5sha, MasterSecret, Handshake) ->
%% md5_hash
%% MD5(master_secret + pad_2 +
%% MD5(handshake_messages + master_secret + pad_1));
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index e6e55048a4..d62ea6e5a4 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -28,7 +28,7 @@
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
--export([master_secret/4, finished/5, certificate_verify/2, mac_hash/7,
+-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
setup_keys/8, suites/1, prf/5]).
%%====================================================================
@@ -75,7 +75,7 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
-certificate_verify(?'rsaEncryption', Handshake) ->
+certificate_verify(md5sha, _Version, Handshake) ->
MD5 = crypto:md5(Handshake),
SHA = crypto:sha(Handshake),
<<MD5/binary, SHA/binary>>;