aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/src/ssl_handshake.erl
diff options
context:
space:
mode:
authorAndreas Schultz <[email protected]>2012-04-08 03:39:52 +0200
committerIngela Anderton Andin <[email protected]>2012-08-22 14:00:45 +0200
commit0bcbe96a1a68fef87efc43719853edcee2f58720 (patch)
treea4b20a1ce363ada409ab05ac61e15b2083da28d4 /lib/ssl/src/ssl_handshake.erl
parent7682bd59933f20cba5c32df96a58f252924478a9 (diff)
downloadotp-0bcbe96a1a68fef87efc43719853edcee2f58720.tar.gz
otp-0bcbe96a1a68fef87efc43719853edcee2f58720.tar.bz2
otp-0bcbe96a1a68fef87efc43719853edcee2f58720.zip
ssl: Make signature handling version dependant
TLS 1.2 introduces changes on how signatures are calculate and encoded. This makes the signature handling version aware
Diffstat (limited to 'lib/ssl/src/ssl_handshake.erl')
-rw-r--r--lib/ssl/src/ssl_handshake.erl113
1 files changed, 60 insertions, 53 deletions
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'.