aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/public_key/src/public_key.erl163
-rw-r--r--lib/ssl/src/ssl_connection.erl35
-rw-r--r--lib/ssl/src/ssl_handshake.erl9
-rw-r--r--lib/ssl/test/erl_make_certs.erl4
4 files changed, 99 insertions, 112 deletions
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 41ebaef76d..06bffeea76 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, generate_key/1, generate_key/2,
+ sign/3, verify/4,
+ generate_key/1,
compute_key/2, compute_key/3,
pkix_sign/2, pkix_verify/2,
pkix_sign_types/1,
@@ -326,18 +327,14 @@ encrypt_private(PlainText,
%%--------------------------------------------------------------------
-spec generate_key(#'ECPrivateKey'{} | {curve, Name ::atom()} | #'DHParameter'{}) -> {'ECKey', term()} | {binary(), binary()}.
--spec generate_key(#'ECPoint'{}, #'OTPECParameters'{} | {namedCurve, oid()}) -> {'ECKey', term()}.
-
%% Description: Generates new key(s)
%%--------------------------------------------------------------------
-generate_key(#'ECPrivateKey'{} = Key) ->
- ec_private_key_to_eckey(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);
+ Term = crypto:ec_key_to_term(ECDHKey),
+ ec_key(Term);
generate_key(#'DHParameter'{prime = P, base = G}) ->
crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]);
@@ -350,27 +347,33 @@ generate_key({srp, Version, Generator, Prime}) when is_binary(Generator), is_bin
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).
+ crypto:srp_generate_key(Verifier, Generator, Prime, Version);
-generate_key(#'ECPoint'{} = Key, Params) ->
+generate_key(Params) ->
%% TODO: Better crypto API
- ECKey = ec_public_key_to_eckey({Key,Params}),
- ECClntKey = crypto:term_to_ec_key(ECKey),
+ Name = ec_curve_spec(Params),
+ ECClntKey = crypto:ec_key_new(Name),
+ %% ECDHKey = format_ecdh_key(Params),
+ %% ECClntKey = crypto:term_to_ec_key(ECDHKey),
crypto:ec_key_generate(ECClntKey),
- crypto:ec_key_to_term(ECClntKey).
+ Term = crypto:ec_key_to_term(ECClntKey),
+ ec_key(Term, Params).
%%--------------------------------------------------------------------
--spec compute_key(#'ECPoint'{}, {'ECKey', binary()}) -> binary().
+-spec compute_key(#'ECPoint'{}, #'ECPrivateKey'{} | crypto:ecdh_key()) -> binary().
-spec compute_key(OthersKey ::binary(), MyKey::binary() | {binary(), binary()},
{dh, binary(), binary()} |
- {srp, atom(), binary(), binary()} |
- {srp, string(), string(), binary(), atom(), binary(), binary()})
+ {srp,'3'|'6'| '6a' , binary(), binary()} |
+ {srp, string(), string(), binary(), '3'|'6'| '6a', binary(), binary()})
-> binary().
%% Description: Compute shared secret
%%--------------------------------------------------------------------
-compute_key(#'ECPoint'{point = Point}, Term) ->
+compute_key(PubKey, #'ECPrivateKey'{} = PrivateKey) ->
+ compute_key(PubKey, format_ecdh_key(PrivateKey));
+
+compute_key(#'ECPoint'{point = Point}, ECDHKeys) ->
%% TODO: Better crypto API
- ECKey = crypto:term_to_ec_key(Term),
+ ECKey = crypto:term_to_ec_key(ECDHKeys),
crypto:ecdh_compute_key(ECKey, Point).
compute_key(OthersKey, MyKey, {dh, Prime, Base}) when is_binary(OthersKey),
@@ -428,30 +431,16 @@ pkix_sign_types(?'ecdsa-with-SHA512') ->
dsa_private_key()) -> Signature :: binary().
%% Description: Create digital signature.
%%--------------------------------------------------------------------
-sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:sign(rsa, DigestType, Digest, format_rsa_private_key(Key));
-
-sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:sign(rsa, DigestType, PlainText, format_rsa_private_key(Key));
-
-sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:sign(dss, sha, Digest, [P, Q, G, X]);
+sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
+ crypto:sign(rsa, DigestType, DigestOrPlainText, format_rsa_private_key(Key));
-sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:sign(dss, sha, PlainText, [P, Q, G, X]);
+sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
+ crypto:sign(dss, sha, DigestOrPlainText, [P, Q, G, X]);
-sign(Digest, DigestType, Key = {?'id-ecPublicKey', _, _}) ->
- sign(Digest, DigestType, ec_public_key_to_eckey(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, Key = #'ECPrivateKey'{}) ->
- ECDHKey = ec_private_key_to_eckey(Key),
+sign(DigestOrPlainText, DigestType, Key = #'ECPrivateKey'{}) ->
+ ECDHKey = format_ecdh_key(Key),
ECKey = crypto:term_to_ec_key(ECDHKey),
- crypto:sign(ecdsa, DigestType, PlainText, ECKey);
+ crypto:sign(ecdsa, DigestType, DigestOrPlainText, ECKey);
%% Backwards compatible
sign(Digest, none, #'DSAPrivateKey'{} = Key) ->
@@ -463,36 +452,28 @@ sign(Digest, none, #'DSAPrivateKey'{} = Key) ->
| dsa_public_key()) -> boolean().
%% Description: Verifies a digital signature.
%%--------------------------------------------------------------------
-verify({digest,_} = Digest, DigestType, Signature,
- #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:verify(rsa, DigestType, Digest, Signature, [Exp, Mod]);
-
-verify(PlainText, DigestType, Signature,
+verify(DigestOrPlainText, DigestType, Signature,
#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:verify(rsa, DigestType, PlainText, Signature,
+ crypto:verify(rsa, DigestType, DigestOrPlainText, Signature,
[Exp, Mod]);
-verify({digest,_} = Digest, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(Signature) ->
- crypto:verify(dss, DigestType, Digest, Signature, [P, Q, G, Key]);
-
verify(Digest, DigestType, Signature, Key = #'ECPrivateKey'{}) ->
- ECDHKey = ec_private_key_to_eckey(Key),
+ ECDHKey = format_ecdh_key(Key),
ECKey = crypto:term_to_ec_key(ECDHKey),
crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey);
-verify(Digest, DigestType, Signature, Key = {#'ECPoint'{}, _}) ->
- ECDHKey = ec_public_key_to_eckey(Key),
+verify(DigestOrPlaintext, DigestType, Signature, Key = {#'ECPoint'{}, _}) ->
+ ECDHKey = format_ecdh_key(Key),
ECKey = crypto:term_to_ec_key(ECDHKey),
- crypto:verify(ecdsa, DigestType, Digest, Signature, ECKey);
+ crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, ECKey);
%% Backwards compatibility
verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) ->
verify({digest,Digest}, sha, Signature, Key);
-verify(PlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(PlainText), is_binary(Signature) ->
- crypto:verify(dss, DigestType, PlainText, Signature, [P, Q, G, Key]).
+verify(DigestOrPlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
+ when is_integer(Key), is_binary(Signature) ->
+ crypto:verify(dss, DigestType, DigestOrPlainText, Signature, [P, Q, G, Key]).
%%--------------------------------------------------------------------
-spec pkix_sign(#'OTPTBSCertificate'{},
@@ -939,40 +920,46 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
is_integer(D) ->
[E, N, D].
-%%
-%% Description: convert a ECPrivate key into resource Key
-%%--------------------------------------------------------------------
+format_ecdh_key(#'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param,
+ publicKey = _}) ->
+ ECCurve = ec_curve_spec(Param),
+ {ECCurve, list2int(PrivKey), undefined};
+
+format_ecdh_key({#'ECPoint'{point = Point}, Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ {ECCurve, undefined, Point}.
+
+ec_curve_spec( #'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};
+ec_curve_spec({namedCurve, OID}) ->
+ pubkey_cert_records:namedCurves(OID).
+
+ec_key({Curve, PrivateKey, PubKey}) when is_atom(Curve) ->
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivateKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(Curve)},
+ publicKey = {0, PubKey}}.
+
+ec_key({Curve, PrivateKey, PubKey}, _Params) when is_atom(Curve) ->
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivateKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(Curve)},
+ publicKey = {0, PubKey}};
+
+ec_key({_Curve, PrivateKey, PubKey}, Params) ->
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivateKey),
+ parameters = Params,
+ publicKey = {0, PubKey}}.
+
list2int(L) ->
S = length(L) * 8,
<<R:S/integer>> = 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)}.
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index dc9ab89331..4d64cd8523 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1378,9 +1378,9 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
public_key_info = PublicKeyInfo},
State2 = case PublicKeyInfo of
{?'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);
+ ECDHKey = public_key:generate_key(PublicKeyParams),
+ State3 = State1#state{diffie_hellman_keys = ECDHKey},
+ ec_dh_master_secret(ECDHKey, PublicKey, State3);
_ -> State1
end,
@@ -1615,13 +1615,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
when Algo == dhe_dss;
Algo == dhe_rsa;
Algo == dh_anon ->
- Keys = public_key:generate_key(Params),
+ DHKeys = public_key:generate_key(Params),
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, {dh, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1629,13 +1629,12 @@ 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 = DHKeys,
tls_handshake_history = Handshake};
key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State)
when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
- ECDH = public_key:generate_key(Key),
- State#state{diffie_hellman_keys = ECDH};
+ State#state{diffie_hellman_keys = Key};
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
private_key = PrivateKey,
@@ -1648,13 +1647,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
Algo == ecdh_anon ->
- ECDHKey = public_key:generate_key({curve, default_curve(State)}),
+ ECDHKeys = 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, ECDHKey,
+ Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1662,7 +1661,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 = ECDHKey,
+ diffie_hellman_keys = ECDHKeys,
tls_handshake_history = Handshake1};
key_exchange(#state{role = server, key_algorithm = psk,
@@ -1704,13 +1703,13 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
socket = Socket,
transport_cb = Transport
} = State) ->
- Keys = public_key:generate_key(Params),
+ DHKeys = public_key:generate_key(Params),
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, {dhe_psk, PskIdentityHint, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1718,7 +1717,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
key_exchange(#state{role = server, key_algorithm = rsa_psk,
@@ -2051,8 +2050,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) ->
- Key = public_key:generate_key({curve, ECCurve}),
- ec_dh_master_secret(Key, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = Key});
+ ECDHKeys = public_key:generate_key({curve, ECCurve}),
+ ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys});
server_master_secret(#server_psk_params{
hint = IdentityHint},
@@ -2098,9 +2097,9 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
{dh, PMpint, GMpint}),
master_from_premaster_secret(PremasterSecret, State).
-ec_dh_master_secret(ECKey, ECPoint, State) ->
+ec_dh_master_secret(ECDHKeys, ECPoint, State) ->
PremasterSecret =
- public_key:compute_key(ECPoint, ECKey),
+ public_key:compute_key(ECPoint, ECDHKeys),
master_from_premaster_secret(PremasterSecret, State).
handle_psk_identity(_PSKIdentity, LookupFun)
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index f736de3327..cde3e6fc66 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -418,7 +418,7 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
dh_public = PublicKey}
};
-key_exchange(client, _Version, {ecdh, {_,_,ECPublicKey}}) ->
+key_exchange(client, _Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}}}) ->
#client_key_exchange{
exchange_keys = #client_ec_diffie_hellman_public{
dh_public = ECPublicKey}
@@ -461,7 +461,8 @@ key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
enc_server_key_exchange(Version, ServerDHParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
-key_exchange(server, Version, {ecdh, {ECCurve, _, ECPublicKey}, HashSign, ClientRandom, ServerRandom,
+key_exchange(server, Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey},
+ parameters = ECCurve}, HashSign, ClientRandom, ServerRandom,
PrivateKey}) ->
ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey},
enc_server_key_exchange(Version, ServerECParams, HashSign,
@@ -1513,10 +1514,10 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
GLen = byte_size(G),
YLen = byte_size(Y),
<<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
-enc_server_key(#server_ecdh_params{curve = ECCurve, public = ECPubKey}) ->
+enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) ->
%%TODO: support arbitrary keys
KLen = size(ECPubKey),
- <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:ec_nid2curve_id(ECCurve))),
+ <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:ec_nid2curve_id(pubkey_cert_records:namedCurves(ECCurve)))),
?BYTE(KLen), ECPubKey/binary>>;
enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
Len = byte_size(PskIdentityHint),
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index f37928be85..f8d086513b 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -114,8 +114,8 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
#'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
- parameters = _Params, publicKey = _PubKey} ->
- public_key:pkix_verify(DerEncodedCert, Key)
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%