summaryrefslogtreecommitdiff
path: root/lib/ssl/src/ssl_cipher.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl/src/ssl_cipher.erl')
-rw-r--r--lib/ssl/src/ssl_cipher.erl66
1 files changed, 65 insertions, 1 deletions
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index c16e2331ff..c97884ec08 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -48,7 +48,11 @@
key_material/1, signature_algorithm_to_scheme/1]).
%% RFC 8446 TLS 1.3
--export([generate_client_shares/1, generate_server_share/1, add_zero_padding/2]).
+-export([generate_client_shares/1,
+ generate_server_share/1,
+ add_zero_padding/2,
+ encrypt_ticket/3,
+ decrypt_ticket/3]).
-compile(inline).
@@ -1386,3 +1390,63 @@ add_zero_padding(Bin, PrimeSize)
Bin;
add_zero_padding(Bin, PrimeSize) ->
add_zero_padding(<<0, Bin/binary>>, PrimeSize).
+
+
+%% Functions for handling self-encrypted session tickets (TLS 1.3).
+%%
+encrypt_ticket(#stateless_ticket{
+ hash = Hash,
+ pre_shared_key = PSK,
+ ticket_age_add = TicketAgeAdd,
+ lifetime = Lifetime,
+ timestamp = Timestamp
+ }, Shard, IV) ->
+ Plaintext = <<(ssl_cipher:hash_algorithm(Hash)):8,PSK/binary,
+ ?UINT64(TicketAgeAdd),?UINT32(Lifetime),?UINT32(Timestamp)>>,
+ encrypt_ticket_data(Plaintext, Shard, IV).
+
+
+decrypt_ticket(CipherFragment, Shard, IV) ->
+ case decrypt_ticket_data(CipherFragment, Shard, IV) of
+ error ->
+ error;
+ Plaintext ->
+ <<?BYTE(HKDF),T/binary>> = Plaintext,
+ Hash = hash_algorithm(HKDF),
+ HashSize = hash_size(Hash),
+ <<PSK:HashSize/binary,?UINT64(TicketAgeAdd),?UINT32(Lifetime),?UINT32(Timestamp),_/binary>> = T,
+ #stateless_ticket{
+ hash = Hash,
+ pre_shared_key = PSK,
+ ticket_age_add = TicketAgeAdd,
+ lifetime = Lifetime,
+ timestamp = Timestamp
+ }
+ end.
+
+
+encrypt_ticket_data(Plaintext, Shard, IV) ->
+ AAD = additional_data(erlang:iolist_size(Plaintext) + 16), %% TagLen = 16
+ {OTP, Key} = make_otp_key(Shard),
+ {Content, CipherTag} = crypto:crypto_one_time_aead(aes_256_gcm, Key, IV, Plaintext, AAD, 16, true),
+ <<Content/binary,CipherTag/binary,OTP/binary>>.
+
+
+decrypt_ticket_data(CipherFragment, Shard, IV) ->
+ Size = byte_size(Shard),
+ AAD = additional_data(erlang:iolist_size(CipherFragment) - Size),
+ Len = byte_size(CipherFragment) - Size - 16,
+ <<Encrypted:Len/binary,CipherTag:16/binary,OTP:Size/binary>> = CipherFragment,
+ Key = crypto:exor(OTP, Shard),
+ crypto:crypto_one_time_aead(aes_256_gcm, Key, IV, Encrypted, AAD, CipherTag, false).
+
+
+additional_data(Length) ->
+ <<"ticket",?UINT16(Length)>>.
+
+
+make_otp_key(Shard) ->
+ Size = byte_size(Shard),
+ OTP = crypto:strong_rand_bytes(Size),
+ Key = crypto:exor(OTP, Shard),
+ {OTP, Key}.