aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl/test/inet_crypto_dist.erl
diff options
context:
space:
mode:
authorRaimo Niskanen <[email protected]>2019-04-18 14:39:56 +0200
committerRaimo Niskanen <[email protected]>2019-04-18 14:39:56 +0200
commit03961a5520b43e7c2a70f0e2089302dd78fd6d9c (patch)
tree3fdd493309ec928eb2ca4ee84d6ff5f42dbaffdc /lib/ssl/test/inet_crypto_dist.erl
parentcd685023c1ae84b3361979851d725e0cc1c4bdb0 (diff)
downloadotp-03961a5520b43e7c2a70f0e2089302dd78fd6d9c.tar.gz
otp-03961a5520b43e7c2a70f0e2089302dd78fd6d9c.tar.bz2
otp-03961a5520b43e7c2a70f0e2089302dd78fd6d9c.zip
Keep the keypair for the node's lifetime
Diffstat (limited to 'lib/ssl/test/inet_crypto_dist.erl')
-rw-r--r--lib/ssl/test/inet_crypto_dist.erl125
1 files changed, 86 insertions, 39 deletions
diff --git a/lib/ssl/test/inet_crypto_dist.erl b/lib/ssl/test/inet_crypto_dist.erl
index 6d8a8b7d09..4574e1e6c3 100644
--- a/lib/ssl/test/inet_crypto_dist.erl
+++ b/lib/ssl/test/inet_crypto_dist.erl
@@ -51,27 +51,69 @@
-record(params,
{socket,
dist_handle,
- public_key_type,
- public_key_params,
- hmac_algorithm,
- aead_cipher,
- iv,
- key,
- tag_len,
- rekey_interval
+ hmac_algorithm = sha256,
+ aead_cipher = aes_gcm,
+ iv = 12,
+ key = 16,
+ tag_len = 16,
+ rekey_interval = 32768
}).
-current_params(Socket) ->
- #params{
- socket = Socket,
- public_key_type = ecdh,
- public_key_params = brainpoolP384t1,
- hmac_algorithm = sha256,
- aead_cipher = aes_gcm,
- iv = 12,
- key = 16,
- tag_len = 16,
- rekey_interval = 32768}.
+-record(public_key_pair,
+ {type = ecdh,
+ params = brainpoolP384t1,
+ public,
+ private}).
+
+params(Socket) ->
+ #params{socket = Socket}.
+
+
+%% -------------------------------------------------------------------------
+%% Keep the same public/private key pair during the node's lifetime
+%% in the process state of a process linked to the acceptor process.
+%% Create it the first time it is needed.
+%%
+
+start_public_key_pair() ->
+ spawn_link(
+ fun () ->
+ register(?MODULE, self()),
+ public_key_pair(#public_key_pair{})
+ end).
+
+public_key_pair(PKP) ->
+ receive
+ {Pid, Tag, public_key_pair} ->
+ case PKP of
+ #public_key_pair{
+ type = Type,
+ params = Params,
+ public = undefined} ->
+ %%
+ {Public, Private} = crypto:generate_key(Type, Params),
+ PKP_1 =
+ PKP#public_key_pair{
+ public = Public, private = Private},
+ Pid ! {Tag, PKP_1},
+ public_key_pair(PKP_1);
+ #public_key_pair{} ->
+ Pid ! {Tag, PKP},
+ public_key_pair(PKP)
+ end
+ end.
+
+public_key_pair() ->
+ Pid = whereis(?MODULE),
+ Ref = erlang:monitor(process, Pid),
+ Pid ! {self(), Ref, public_key_pair},
+ receive
+ {Ref, PKP} ->
+ erlang:demonitor(Ref, [flush]),
+ PKP;
+ {'DOWN', Ref, process, Pid, Reason} ->
+ error(Reason)
+ end.
%% -------------------------------------------------------------------------
%% Erlang distribution plugin structure explained to myself
@@ -227,6 +269,7 @@ gen_accept(Listen, Driver) ->
monitor_dist_proc(
spawn_opt(
fun () ->
+ start_public_key_pair(),
accept_loop(Listen, Driver, NetKernel)
end,
[link, {priority, max}])).
@@ -642,7 +685,7 @@ nodelay() ->
%%% * Restart and/or code reload policy (not needed in kernel)
%%% * Fitting into the epmd/Erlang distro protocol version framework
%%% (something needs to be created for multiple protocols, epmd,
-%%% multiple address families, etc)
+%%% multiple address families, fallback to previous version, etc)
%% Debug client and server
@@ -739,19 +782,21 @@ reply({Ref, Pid}, Msg) ->
%% blocks we have a deadlock.
%%
%% The init + start sequence tries to implement Password Encrypted
-%% Key Exchange using an ephemeral public/private keypair and the
+%% Key Exchange using a node public/private keypair and the
%% shared secret (the Cookie) to create session encryption keys
%% that can not be re-created if the shared secret is compromized,
-%% which should create forward secrecy.
+%% which should create forward secrecy. You need both nodes'
+%% keypairs and the shared secret to decrypt the traffic
+%% between the nodes.
%%
%% All exchanged messages uses {packet, 2} i.e 16 bit size header.
%%
-%% The init message contains a random number and encrypted: a public key
+%% The init message contains a random number and encrypted: the public key
%% and two random numbers. The encryption is done with Key and IV hashed
%% from the unencrypted random number and the shared secret.
%%
-%% The exchanged epemeral public/private keypairs are used
-%% to create a shared key that is hashed with one of the encrypted
+%% The other node's public key is used with the own node's private
+%% key to create a shared key that is hashed with one of the encrypted
%% random numbers from each side to create Key and IV for the session.
%%
%% The start message contains the two encrypted random numbers
@@ -773,18 +818,19 @@ reply({Ref, Pid}, Msg) ->
%% -------------------------------------------------------------------------
init(Socket, Secret) ->
- Params = current_params(Socket),
- {PrivKey, R2, R3, Msg} = init_msg(Params, Secret),
+ #public_key_pair{public = PubKey} = PKP = public_key_pair(),
+ Params = params(Socket),
+ {R2, R3, Msg} = init_msg(Params, PubKey, Secret),
ok = gen_tcp:send(Socket, Msg),
- init(Params, Secret, PrivKey, R2, R3).
+ init_recv(Params, Secret, PKP, R2, R3).
-init(
- #params{socket = Socket, iv = IVLen} = Params, Secret, PrivKey, R2, R3) ->
+init_recv(
+ #params{socket = Socket, iv = IVLen} = Params, Secret, PKP, R2, R3) ->
%%
{ok, InitMsg} = gen_tcp:recv(Socket, 0),
IVSaltLen = IVLen - 6,
try
- case init_msg(Params, Secret, PrivKey, R2, R3, InitMsg) of
+ case init_msg(Params, Secret, PKP, R2, R3, InitMsg) of
{#params{iv = <<IV2ASalt:IVSaltLen/binary, IV2ANo:48>>} =
SendParams,
RecvParams, SendStartMsg} ->
@@ -807,15 +853,12 @@ init(
init_msg(
#params{
- public_key_type = PublicKeyType,
- public_key_params = PublicKeyParams,
hmac_algorithm = HmacAlgo,
aead_cipher = AeadCipher,
key = KeyLen,
iv = IVLen,
- tag_len = TagLen}, Secret) ->
+ tag_len = TagLen}, PubKeyA, Secret) ->
%%
- {PubKeyA, PrivKey} = crypto:generate_key(PublicKeyType, PublicKeyParams),
RLen = KeyLen + IVLen,
<<R1A:RLen/binary, R2A:RLen/binary, R3A:RLen/binary>> =
crypto:strong_rand_bytes(3 * RLen),
@@ -826,18 +869,22 @@ init_msg(
{Ciphertext, Tag} =
crypto:block_encrypt(AeadCipher, Key1A, IV1A, {AAD, Plaintext, TagLen}),
Msg = [R1A, Tag, Ciphertext],
- {PrivKey, R2A, R3A, Msg}.
+ {R2A, R3A, Msg}.
%%
init_msg(
#params{
- public_key_type = PublicKeyType,
- public_key_params = PublicKeyParams,
hmac_algorithm = HmacAlgo,
aead_cipher = AeadCipher,
key = KeyLen,
iv = IVLen,
tag_len = TagLen,
- rekey_interval = RekeyInterval} = Params, Secret, PrivKey, R2A, R3A, Msg) ->
+ rekey_interval = RekeyInterval} = Params,
+ Secret,
+ #public_key_pair{
+ type = PublicKeyType,
+ params = PublicKeyParams,
+ private = PrivKey},
+ R2A, R3A, Msg) ->
%%
RLen = KeyLen + IVLen,
case Msg of