From dfd9c13f882ef199dfcb830823cb12d83bcc4f10 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Wed, 17 Apr 2013 10:28:25 +0200 Subject: ssl & public_key: New public_key API for DH/ECDH/SRP keys --- lib/public_key/src/public_key.erl | 192 +++++++++++++++++++++++++------------- lib/ssl/src/ssl_connection.erl | 104 +++++++-------------- lib/ssl/src/ssl_handshake.erl | 16 ++-- 3 files changed, 171 insertions(+), 141 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 4b8fda8d40..41ebaef76d 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -34,7 +34,8 @@ decrypt_private/2, decrypt_private/3, encrypt_public/2, encrypt_public/3, decrypt_public/2, decrypt_public/3, - sign/3, verify/4, + sign/3, verify/4, generate_key/1, generate_key/2, + compute_key/2, compute_key/3, pkix_sign/2, pkix_verify/2, pkix_sign_types/1, pkix_is_self_signed/1, @@ -323,58 +324,70 @@ encrypt_private(PlainText, Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding), crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding). -format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D, - prime1 = P1, prime2 = P2, - exponent1 = E1, exponent2 = E2, - coefficient = C}) - when is_integer(N), is_integer(E), is_integer(D), - is_integer(P1), is_integer(P2), - is_integer(E1), is_integer(E2), is_integer(C) -> - [E, N, D, P1, P2, E1, E2, C]; - -format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, - privateExponent = D}) when is_integer(N), - is_integer(E), - is_integer(D) -> - [E, N, D]. +%%-------------------------------------------------------------------- +-spec generate_key(#'ECPrivateKey'{} | {curve, Name ::atom()} | #'DHParameter'{}) -> {'ECKey', term()} | {binary(), binary()}. +-spec generate_key(#'ECPoint'{}, #'OTPECParameters'{} | {namedCurve, oid()}) -> {'ECKey', term()}. -%% -%% Description: convert a ECPrivate key into resource Key +%% Description: Generates new key(s) %%-------------------------------------------------------------------- -list2int(L) -> - S = length(L) * 8, - <> = erlang:iolist_to_binary(L), - R. +generate_key(#'ECPrivateKey'{} = Key) -> + ec_private_key_to_eckey(Key); -ec_private_key_to_eckey(#'ECPrivateKey'{privateKey = PrivKey, - parameters = Param, - publicKey = _PubKey}) -> - ECCurve = case Param of - #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> - Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, - Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, - {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; - {namedCurve, OID} -> - pubkey_cert_records:namedCurves(OID) - end, - Key = {ECCurve, list2int(PrivKey), undefined}, - {'ECKey', crypto:term_to_ec_key(Key)}. +generate_key({curve, Name}) -> + %% TODO: Better crypto API + ECDHKey = crypto:ec_key_new(Name), + crypto:ec_key_generate(ECDHKey), + crypto:ec_key_to_term(ECDHKey); -ec_public_key_to_eckey({#'ECPoint'{point = ECPoint}, Param}) -> - ECCurve = case Param of - #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> - Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, - Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, - {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; - {namedCurve, OID} -> - pubkey_cert_records:namedCurves(OID) - end, - Key = {ECCurve, undefined, ECPoint}, - {'ECKey', crypto:term_to_ec_key(Key)}. +generate_key(#'DHParameter'{prime = P, base = G}) -> + crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]); + +generate_key({dh, Prime, Base}) when is_binary(Prime), is_binary(Base) -> + %% TODO: Is mpint could be normal binary! + crypto:dh_generate_key([Prime, Base]); + +generate_key({srp, Version, Generator, Prime}) when is_binary(Generator), is_binary(Prime) -> + crypto:srp_generate_key(Generator, Prime, Version); + +generate_key({srp, Version, Verifier, Generator, Prime}) when is_binary(Verifier), is_binary(Generator), is_binary(Prime) -> + crypto:srp_generate_key(Verifier, Generator, Prime, Version). + +generate_key(#'ECPoint'{} = Key, Params) -> + %% TODO: Better crypto API + ECKey = ec_public_key_to_eckey({Key,Params}), + ECClntKey = crypto:term_to_ec_key(ECKey), + crypto:ec_key_generate(ECClntKey), + crypto:ec_key_to_term(ECClntKey). %%-------------------------------------------------------------------- +-spec compute_key(#'ECPoint'{}, {'ECKey', binary()}) -> binary(). +-spec compute_key(OthersKey ::binary(), MyKey::binary() | {binary(), binary()}, + {dh, binary(), binary()} | + {srp, atom(), binary(), binary()} | + {srp, string(), string(), binary(), atom(), binary(), binary()}) + -> binary(). +%% Description: Compute shared secret +%%-------------------------------------------------------------------- +compute_key(#'ECPoint'{point = Point}, Term) -> + %% TODO: Better crypto API + ECKey = crypto:term_to_ec_key(Term), + crypto:ecdh_compute_key(ECKey, Point). + +compute_key(OthersKey, MyKey, {dh, Prime, Base}) when is_binary(OthersKey), + is_binary(MyKey), + is_binary(Prime), + is_binary(Base) -> + %% TODO: Is mpint could be binary! + crypto:dh_compute_key(OthersKey, MyKey, [Prime, Base]); + +compute_key(ClientPub, {ServerPub, ServerPriv}, {srp, Version, Verifier, Prime}) -> + crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, Version); + +compute_key(ServerPub, {ClientPub, ClientPriv}, {srp, Username, Password, Salt, Version, Prime, Generator}) -> + DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), + crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, Version). +%%-------------------------------------------------------------------- -spec pkix_sign_types(SignatureAlg::oid()) -> %% Relevant dsa digest type is subpart of rsa digest type { DigestType :: rsa_digest_type(), @@ -430,14 +443,15 @@ sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> sign(Digest, DigestType, Key = {?'id-ecPublicKey', _, _}) -> sign(Digest, DigestType, ec_public_key_to_eckey(Key)); -sign(Digest, DigestType, Key = #'ECPrivateKey'{}) -> - sign(Digest, DigestType, ec_private_key_to_eckey(Key)); - -sign({digest,_}=Digest, DigestType, {'ECKey', Key}) -> - crypto:sign(ecdsa, DigestType, Digest, Key); +sign({digest,_} = Digest, DigestType, Key = #'ECPrivateKey'{}) -> + ECDHKey = ec_private_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:sign(ecdsa, DigestType, Digest, ECKey); -sign(PlainText, DigestType, {'ECKey', Key}) -> - crypto:sign(ecdsa, DigestType, PlainText, Key); +sign(PlainText, DigestType, Key = #'ECPrivateKey'{}) -> + ECDHKey = ec_private_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:sign(ecdsa, DigestType, PlainText, ECKey); %% Backwards compatible sign(Digest, none, #'DSAPrivateKey'{} = Key) -> @@ -462,17 +476,15 @@ verify({digest,_} = Digest, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = when is_integer(Key), is_binary(Signature) -> crypto:verify(dss, DigestType, Digest, Signature, [P, Q, G, Key]); -verify({digest,_} = Digest, DigestType, Signature, {'ECKey', Key}) -> - crypto:verify(ecdsa, DigestType, Digest, Signature, Key); - -verify(PlainText, DigestType, Signature, Key = #'ECPrivateKey'{}) -> - verify(PlainText, DigestType, Signature, ec_private_key_to_eckey(Key)); +verify(Digest, DigestType, Signature, Key = #'ECPrivateKey'{}) -> + ECDHKey = ec_private_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey); -verify(PlainText, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> - verify(PlainText, DigestType, Signature, ec_public_key_to_eckey(Key)); - -verify(PlainText, DigestType, Signature, {'ECKey', Key}) -> - crypto:verify(ecdsa, DigestType, PlainText, Signature, Key); +verify(Digest, DigestType, Signature, Key = {#'ECPoint'{}, _}) -> + ECDHKey = ec_public_key_to_eckey(Key), + ECKey = crypto:term_to_ec_key(ECDHKey), + crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey); %% Backwards compatibility verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) -> @@ -910,3 +922,57 @@ combine(CRL, DeltaCRLs) -> end, lists:foldl(Fun, hd(Deltas), tl(Deltas)) end. + +format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D, + prime1 = P1, prime2 = P2, + exponent1 = E1, exponent2 = E2, + coefficient = C}) + when is_integer(N), is_integer(E), is_integer(D), + is_integer(P1), is_integer(P2), + is_integer(E1), is_integer(E2), is_integer(C) -> + [E, N, D, P1, P2, E1, E2, C]; + +format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, + privateExponent = D}) when is_integer(N), + is_integer(E), + is_integer(D) -> + [E, N, D]. + +%% +%% Description: convert a ECPrivate key into resource Key +%%-------------------------------------------------------------------- +list2int(L) -> + S = length(L) * 8, + <> = erlang:iolist_to_binary(L), + R. + +ec_private_key_to_eckey(#'ECPrivateKey'{privateKey = PrivKey, + parameters = Param, + publicKey = _PubKey}) -> + ECCurve = + case Param of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), + FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + {ECCurve, list2int(PrivKey), undefined}. + %%{'ECKey', crypto:term_to_ec_key(Key)}. + +ec_public_key_to_eckey({#'ECPoint'{point = ECPoint}, Param}) -> + ECCurve = + case Param of + #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> + Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), + FieldId#'OTPFieldID'.parameters}, + Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, + {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; + {namedCurve, OID} -> + pubkey_cert_records:namedCurves(OID) + end, + {ECCurve, undefined, ECPoint}. + %%{'ECKey', crypto:term_to_ec_key(Key)}. diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index aa02c47a3d..dc9ab89331 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -685,8 +685,8 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint}, #state{negotiated_version = Version, - diffie_hellman_keys = {'ECKey', ECDHKey}} = State0) -> - case ec_dh_master_secret(ECDHKey, ClientPublicEcDhPoint, State0) of + diffie_hellman_keys = ECDHKey} = State0) -> + case ec_dh_master_secret(ECDHKey, #'ECPoint'{point = ClientPublicEcDhPoint}, State0) of #state{} = State1 -> {Record, State} = next_record(State1), next_state(certify, cipher, Record, State); @@ -1325,28 +1325,9 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = privateKey = Key}) -> public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key)); -private_key(#'ECPrivateKey'{privateKey = PrivKey, - parameters = Param, - publicKey = _PubKey}) -> - ECCurve = case Param of - #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> - Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, - Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, - {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; - {namedCurve, OID} -> - pubkey_cert_records:namedCurves(OID) - end, - Key = {ECCurve, list2int(PrivKey), undefined}, - {'ECKey', crypto:term_to_ec_key(Key)}; - private_key(Key) -> Key. -list2int(L) -> - S = length(L) * 8, - <> = erlang:iolist_to_binary(L), - R. - -spec(file_error(_,_) -> no_return()). file_error(File, Throw) -> case Throw of @@ -1396,20 +1377,10 @@ handle_peer_cert(PeerCert, PublicKeyInfo, Session#session{peer_certificate = PeerCert}, public_key_info = PublicKeyInfo}, State2 = case PublicKeyInfo of - {?'id-ecPublicKey', {'ECPoint', PublicKey}, PublicKeyParams} -> - ECCurve = case PublicKeyParams of - #'OTPECParameters'{ fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor } -> - Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'OTPFieldID'.fieldType), FieldId#'OTPFieldID'.parameters}, - Curve = {list2int(PCurve#'Curve'.a), list2int(PCurve#'Curve'.b), none}, - {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor}; - {namedCurve, OID} -> - pubkey_cert_records:namedCurves(OID) - end, - %% Generate Client ECDH Key - ECClntKey = crypto:ec_key_new(ECCurve), - crypto:ec_key_generate(ECClntKey), - State3 = State1#state{diffie_hellman_keys = {'ECKey', ECClntKey}}, - ec_dh_master_secret(ECClntKey, PublicKey, State3); + {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} -> + Keys = public_key:generate_key(PublicKey, PublicKeyParams), + State3 = State1#state{diffie_hellman_keys = Keys}, + ec_dh_master_secret(Keys, PublicKey, State3); _ -> State1 end, @@ -1633,7 +1604,7 @@ key_exchange(#state{role = server, key_algorithm = rsa} = State) -> State; key_exchange(#state{role = server, key_algorithm = Algo, hashsign_algorithm = HashSignAlgo, - diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, + diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version, @@ -1644,7 +1615,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, when Algo == dhe_dss; Algo == dhe_rsa; Algo == dh_anon -> - Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), + Keys = public_key:generate_key(Params), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, @@ -1663,7 +1634,8 @@ key_exchange(#state{role = server, key_algorithm = Algo, key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State) when Algo == ecdh_ecdsa; Algo == ecdh_rsa -> - State#state{diffie_hellman_keys = Key}; + ECDH = public_key:generate_key(Key), + State#state{diffie_hellman_keys = ECDH}; key_exchange(#state{role = server, key_algorithm = Algo, hashsign_algorithm = HashSignAlgo, private_key = PrivateKey, @@ -1675,19 +1647,14 @@ key_exchange(#state{role = server, key_algorithm = Algo, } = State) when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa; Algo == ecdh_anon -> - %%TODO: select prefered curve from extension - - %% Generate Server ECDH Key - ECDHKey = crypto:ec_key_new(secp256k1), - crypto:ec_key_generate(ECDHKey), - Keys = {'ECKey', ECDHKey}, + ECDHKey = public_key:generate_key({curve, default_curve(State)}), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, #security_parameters{client_random = ClientRandom, server_random = ServerRandom} = SecParams, - Msg = ssl_handshake:key_exchange(server, Version, {ecdh, Keys, + Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKey, HashSignAlgo, ClientRandom, ServerRandom, PrivateKey}), @@ -1695,7 +1662,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, encode_handshake(Msg, Version, ConnectionStates0, Handshake0), Transport:send(Socket, BinMsg), State#state{connection_states = ConnectionStates, - diffie_hellman_keys = Keys, + diffie_hellman_keys = ECDHKey, tls_handshake_history = Handshake1}; key_exchange(#state{role = server, key_algorithm = psk, @@ -1729,7 +1696,7 @@ key_exchange(#state{role = server, key_algorithm = psk, key_exchange(#state{role = server, key_algorithm = dhe_psk, ssl_options = #ssl_options{psk_identity = PskIdentityHint}, hashsign_algorithm = HashSignAlgo, - diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, + diffie_hellman_params = #'DHParameter'{} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version, @@ -1737,7 +1704,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk, socket = Socket, transport_cb = Transport } = State) -> - Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), + Keys = public_key:generate_key(Params), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, @@ -2084,12 +2051,8 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey}, State) -> - %% Generate Client ECDH Key - ECClntKey = crypto:ec_key_new(ECCurve), - crypto:ec_key_generate(ECClntKey), - State1 = State#state{diffie_hellman_keys = {'ECKey', ECClntKey}}, - - ec_dh_master_secret(ECClntKey, ECServerPubKey, State1); + Key = public_key:generate_key({curve, ECCurve}), + ec_dh_master_secret(Key, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = Key}); server_master_secret(#server_psk_params{ hint = IdentityHint}, @@ -2126,18 +2089,18 @@ dh_master_secret(Prime, Base, PublicDhKey, undefined, State) -> PMpint = mpint_binary(Prime), GMpint = mpint_binary(Base), Keys = {_, PrivateDhKey} = - crypto:dh_generate_key([PMpint,GMpint]), + public_key:generate_key({dh, PMpint,GMpint}), dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) -> PremasterSecret = - crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, - [PMpint, GMpint]), + public_key:compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + {dh, PMpint, GMpint}), master_from_premaster_secret(PremasterSecret, State). ec_dh_master_secret(ECKey, ECPoint, State) -> PremasterSecret = - crypto:ecdh_compute_key(ECKey, ECPoint), + public_key:compute_key(ECPoint, ECKey), master_from_premaster_secret(PremasterSecret, State). handle_psk_identity(_PSKIdentity, LookupFun) @@ -2163,7 +2126,7 @@ dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) - PMpint = mpint_binary(Prime), GMpint = mpint_binary(Base), Keys = {_, PrivateDhKey} = - crypto:dh_generate_key([PMpint,GMpint]), + public_key:generate_key({dh, PMpint, GMpint}), dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys}); @@ -2172,8 +2135,8 @@ dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey, case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of {ok, PSK} when is_binary(PSK) -> DHSecret = - crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey, - [PMpint, GMpint]), + public_key:compute_key(mpint_binary(PublicDhKey), PrivateDhKey, + {dh, PMpint, GMpint}), DHLen = erlang:byte_size(DHSecret), Len = erlang:byte_size(PSK), PremasterSecret = <>, @@ -2202,7 +2165,7 @@ generate_srp_server_keys(_SrpParams, 10) -> generate_srp_server_keys(SrpParams = #srp_user{generator = Generator, prime = Prime, verifier = Verifier}, N) -> - case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of + case public_key:generate_key({srp, '6a', Verifier, Generator, Prime}) of error -> generate_srp_server_keys(SrpParams, N+1); Keys -> @@ -2213,7 +2176,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); generate_srp_client_keys(Generator, Prime, N) -> - case crypto:srp_generate_key(Generator, Prime, '6a') of + case public_key:generate_key({srp, '6a', Generator, Prime}) of error -> generate_srp_client_keys(Generator, Prime, N+1); Keys -> @@ -2234,8 +2197,8 @@ handle_srp_identity(Username, {Fun, UserState}) -> throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)) end. -server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) -> - case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of +server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKey}) -> + case public_key:compute_key(ClientPub, ServerKey, {srp, '6a', Verifier, Prime}) of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> @@ -2248,14 +2211,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) -> Keys = generate_srp_client_keys(Generator, Prime, 0), client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys}); -client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv}, +client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys, #state{ssl_options = SslOpts} = State) -> case ssl_srp_primes:check_srp_params(Generator, Prime) of ok -> {Username, Password} = SslOpts#ssl_options.srp_identity, - DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]), - - case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of + case public_key:compute_key(ServerPub, ClientKeys, {srp, Username, Password, Salt, + '6a', Prime, Generator}) of error -> ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER); PremasterSecret -> @@ -3122,3 +3084,7 @@ handle_close_alert(Data, StateName, State0) -> _ -> ok end. + +default_curve(_) -> + %%TODO: select prefered curve from extension + secp256k1. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index eca36ba650..f736de3327 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -418,8 +418,7 @@ key_exchange(client, _Version, {dh, <>}) -> dh_public = PublicKey} }; -key_exchange(client, _Version, {ecdh, {'ECKey', ECDHKey}}) -> - {_, _, ECPublicKey} = crypto:ec_key_to_term(ECDHKey), +key_exchange(client, _Version, {ecdh, {_,_,ECPublicKey}}) -> #client_key_exchange{ exchange_keys = #client_ec_diffie_hellman_public{ dh_public = ECPublicKey} @@ -453,8 +452,8 @@ key_exchange(client, _Version, {srp, PublicKey}) -> }; key_exchange(server, Version, {dh, {<>, _}, - #'DHParameter'{prime = P, base = G}, - HashSign, ClientRandom, ServerRandom, PrivateKey}) -> + #'DHParameter'{prime = P, base = G}, + HashSign, ClientRandom, ServerRandom, PrivateKey}) -> <> = crypto:mpint(P), <> = crypto:mpint(G), ServerDHParams = #server_dh_params{dh_p = PBin, @@ -462,10 +461,9 @@ key_exchange(server, Version, {dh, {<>, _}, enc_server_key_exchange(Version, ServerDHParams, HashSign, ClientRandom, ServerRandom, PrivateKey); -key_exchange(server, Version, {ecdh, {'ECKey', ECKey}, HashSign, ClientRandom, ServerRandom, - PrivateKey}) -> - {ECCurve, _ECPrivKey, ECPubKey} = crypto:ec_key_to_term(ECKey), - ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPubKey}, +key_exchange(server, Version, {ecdh, {ECCurve, _, ECPublicKey}, HashSign, ClientRandom, ServerRandom, + PrivateKey}) -> + ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey}, enc_server_key_exchange(Version, ServerECParams, HashSign, ClientRandom, ServerRandom, PrivateKey); @@ -1700,7 +1698,7 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) -> digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, [{rsa_pad, rsa_pkcs1_padding}]); -digitally_signed(_Version, Hash, HashAlgo, {'ECKey', _} = Key) -> +digitally_signed(_Version, Hash, HashAlgo, Key) -> public_key:sign({digest, Hash}, HashAlgo, Key). calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) -> -- cgit v1.2.3