aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ssl/src/ssl.erl57
-rw-r--r--lib/ssl/src/ssl_cipher.erl59
-rw-r--r--lib/ssl/src/ssl_handshake.erl26
-rw-r--r--lib/ssl/src/ssl_handshake.hrl13
-rw-r--r--lib/ssl/src/ssl_internal.hrl1
-rw-r--r--lib/ssl/src/tls_handshake_1_3.hrl28
-rw-r--r--lib/ssl/src/tls_v1.erl61
7 files changed, 210 insertions, 35 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 166ffac1c0..ef9aac34bf 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -919,13 +919,14 @@ handle_options(Opts0, Role, Host) ->
CertFile = handle_option(certfile, Opts, <<>>),
RecordCb = record_cb(Opts),
- Versions = case handle_option(versions, Opts, []) of
- [] ->
- RecordCb:supported_protocol_versions();
- Vsns ->
- Versions0 = [RecordCb:protocol_version(Vsn) || Vsn <- Vsns],
- lists:sort(fun RecordCb:is_higher/2, Versions0)
- end,
+ [HighestVersion|_] = Versions =
+ case handle_option(versions, Opts, []) of
+ [] ->
+ RecordCb:supported_protocol_versions();
+ Vsns ->
+ Versions0 = [RecordCb:protocol_version(Vsn) || Vsn <- Vsns],
+ lists:sort(fun RecordCb:is_higher/2, Versions0)
+ end,
Protocol = handle_option(protocol, Opts, tls),
@@ -957,13 +958,28 @@ handle_options(Opts0, Role, Host) ->
psk_identity = handle_option(psk_identity, Opts, undefined),
srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_cipher_option(proplists:get_value(ciphers, Opts, []),
- RecordCb:highest_protocol_version(Versions)),
+ HighestVersion),
eccs = handle_eccs_option(proplists:get_value(eccs, Opts, eccs()),
- RecordCb:highest_protocol_version(Versions)),
- signature_algs = handle_hashsigns_option(proplists:get_value(signature_algs, Opts,
- default_option_role(server,
- tls_v1:default_signature_algs(Versions), Role)),
- tls_version(RecordCb:highest_protocol_version(Versions))),
+ HighestVersion),
+ signature_algs =
+ handle_hashsigns_option(
+ proplists:get_value(
+ signature_algs,
+ Opts,
+ default_option_role(server,
+ tls_v1:default_signature_algs(HighestVersion),
+ Role)),
+ tls_version(HighestVersion)),
+ signature_algs_cert =
+ handle_signature_algorithms_option(
+ proplists:get_value(
+ signature_algs_cert,
+ Opts,
+ default_option_role(server,
+ tls_v1:default_signature_schemes(HighestVersion),
+ Role
+ )),
+ tls_version(HighestVersion)),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
reuse_sessions = handle_option(reuse_sessions, Opts, true),
@@ -1300,6 +1316,21 @@ handle_hashsigns_option(_, Version) when Version >= {3, 3} ->
handle_hashsigns_option(_, _Version) ->
undefined.
+handle_signature_algorithms_option(Value, Version) when is_list(Value)
+ andalso Version >= {3, 4} ->
+ case tls_v1:signature_schemes(Version, Value) of
+ [] ->
+ throw({error, {options,
+ no_supported_signature_schemes,
+ {signature_algs_cert, Value}}});
+ _ ->
+ Value
+ end;
+handle_signature_algorithms_option(_, Version) when Version >= {3, 4} ->
+ handle_signature_algorithms_option(tls_v1:default_signature_schemes(Version), Version);
+handle_signature_algorithms_option(_, _Version) ->
+ undefined.
+
validate_options([]) ->
[];
validate_options([{Opt, Value} | Tail]) ->
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 00e0ff7986..799f240659 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -31,6 +31,7 @@
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
-include("ssl_alert.hrl").
+-include("tls_handshake_1_3.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([security_parameters/2, security_parameters/3,
@@ -42,7 +43,8 @@
filter/3, filter_suites/1, filter_suites/2,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1,
random_bytes/1, calc_mac_hash/4,
- is_stream_ciphersuite/1]).
+ is_stream_ciphersuite/1, signature_scheme/1,
+ scheme_to_components/1]).
-compile(inline).
@@ -861,6 +863,61 @@ sign_algorithm(?ECDSA) -> ecdsa;
sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 4) and (Other =< 223)) -> unassigned;
sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 224) and (Other =< 255)) -> Other.
+
+signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256;
+signature_scheme(rsa_pkcs1_sha384) -> ?RSA_PKCS1_SHA384;
+signature_scheme(rsa_pkcs1_sha512) -> ?RSA_PKCS1_SHA512;
+signature_scheme(ecdsa_secp256r1_sha256) -> ?ECDSA_SECP256R1_SHA256;
+signature_scheme(ecdsa_secp384r1_sha384) -> ?ECDSA_SECP384R1_SHA384;
+signature_scheme(ecdsa_secp521r1_sha512) -> ?ECDSA_SECP521R1_SHA512;
+signature_scheme(rsa_pss_rsae_sha256) -> ?RSA_PSS_RSAE_SHA256;
+signature_scheme(rsa_pss_rsae_sha384) -> ?RSA_PSS_RSAE_SHA384;
+signature_scheme(rsa_pss_rsae_sha512) -> ?RSA_PSS_RSAE_SHA512;
+signature_scheme(ed25519) -> ?ED25519;
+signature_scheme(ed448) -> ?ED448;
+signature_scheme(rsa_pss_pss_sha256) -> ?RSA_PSS_PSS_SHA256;
+signature_scheme(rsa_pss_pss_sha384) -> ?RSA_PSS_PSS_SHA384;
+signature_scheme(rsa_pss_pss_sha512) -> ?RSA_PSS_PSS_SHA512;
+signature_scheme(rsa_pkcs1_sha1) -> ?RSA_PKCS1_SHA1;
+signature_scheme(ecdsa_sha1) -> ?ECDSA_SHA1;
+signature_scheme(?RSA_PKCS1_SHA256) -> rsa_pkcs1_sha256;
+signature_scheme(?RSA_PKCS1_SHA384) -> rsa_pkcs1_sha384;
+signature_scheme(?RSA_PKCS1_SHA512) -> rsa_pkcs1_sha512;
+signature_scheme(?ECDSA_SECP256R1_SHA256) -> ecdsa_secp256r1_sha256;
+signature_scheme(?ECDSA_SECP384R1_SHA384) -> ecdsa_secp384r1_sha384;
+signature_scheme(?ECDSA_SECP521R1_SHA512) -> ecdsa_secp521r1_sha512;
+signature_scheme(?RSA_PSS_RSAE_SHA256) -> rsa_pss_rsae_sha256;
+signature_scheme(?RSA_PSS_RSAE_SHA384) -> rsa_pss_rsae_sha384;
+signature_scheme(?RSA_PSS_RSAE_SHA512) -> rsa_pss_rsae_sha512;
+signature_scheme(?ED25519) -> ed25519;
+signature_scheme(?ED448) -> ed448;
+signature_scheme(?RSA_PSS_PSS_SHA256) -> rsa_pss_pss_sha256;
+signature_scheme(?RSA_PSS_PSS_SHA384) -> rsa_pss_pss_sha384;
+signature_scheme(?RSA_PSS_PSS_SHA512) -> rsa_pss_pss_sha512;
+signature_scheme(?RSA_PKCS1_SHA1) -> rsa_pkcs1_sha1;
+signature_scheme(?ECDSA_SHA1) -> ecdsa_sha1;
+signature_scheme(_) -> unassigned.
+%% TODO: reserved code points?
+
+scheme_to_components(rsa_pkcs1_sha256) -> {sha256, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha384) -> {sha384, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha512) -> {sha512, rsa_pkcs1, undefined};
+scheme_to_components(ecdsa_secp256r1_sha256) -> {sha256, ecdsa, secp256r1};
+scheme_to_components(ecdsa_secp384r1_sha384) -> {sha384, ecdsa, secp384r1};
+scheme_to_components(ecdsa_secp521r1_sha512) -> {sha512, ecdsa, secp521r1};
+scheme_to_components(rsa_pss_rsae_sha256) -> {sha256, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha384) -> {sha384, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha512) -> {sha512, rsa_pss_rsae, undefined};
+%% scheme_to_components(ed25519) -> {undefined, undefined, undefined};
+%% scheme_to_components(ed448) -> {undefined, undefined, undefined};
+scheme_to_components(rsa_pss_pss_sha256) -> {sha256, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pss_pss_sha384) -> {sha384, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pss_pss_sha512) -> {sha512, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pkcs1_sha1) -> {sha1, rsa_pkcs1, undefined};
+scheme_to_components(ecdsa_sha1) -> {sha1, ecdsa, undefined}.
+
+
+
hash_size(null) ->
0;
%% The AEAD MAC hash size is not used in the context
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 918062a662..467a8e27a9 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -636,6 +636,14 @@ encode_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Res
Len = ListLen + 2,
encode_hello_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT),
?UINT16(Len), ?UINT16(ListLen), SignAlgoList/binary, Acc/binary>>);
+encode_hello_extensions([#signature_scheme_list{
+ signature_scheme_list = SignatureSchemes} | Rest], Acc) ->
+ SignSchemeList = << <<(ssl_cipher:signature_scheme(SignatureScheme)):16 >> ||
+ SignatureScheme <- SignatureSchemes >>,
+ ListLen = byte_size(SignSchemeList),
+ Len = ListLen + 2,
+ encode_hello_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_CERT_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), SignSchemeList/binary, Acc/binary>>);
encode_hello_extensions([#sni{hostname = Hostname} | Rest], Acc) ->
HostLen = length(Hostname),
HostnameBin = list_to_binary(Hostname),
@@ -960,6 +968,7 @@ premaster_secret(EncSecret, #'RSAPrivateKey'{} = RSAPrivateKey) ->
%%====================================================================
client_hello_extensions(Version, CipherSuites,
#ssl_options{signature_algs = SupportedHashSigns,
+ signature_algs_cert = SignatureSchemes,
eccs = SupportedECCs,
versions = Versions} = SslOpts, ConnectionStates, Renegotiation) ->
{EcPointFormats, EllipticCurves} =
@@ -990,7 +999,9 @@ client_hello_extensions(Version, CipherSuites,
{3,4} ->
HelloExtensions#hello_extensions{
client_hello_versions = #client_hello_versions{
- versions = Versions}};
+ versions = Versions},
+ signature_algs_cert = #signature_scheme_list{
+ signature_scheme_list = SignatureSchemes}};
_Else ->
HelloExtensions
end.
@@ -1777,6 +1788,7 @@ encode_versions([{M,N}|T], Acc) ->
hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo,
srp = SRP,
signature_algs = HashSigns,
+ signature_algs_cert = SignatureSchemes,
ec_point_formats = EcPointFormats,
elliptic_curves = EllipticCurves,
alpn = ALPN,
@@ -1784,7 +1796,7 @@ hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo,
sni = Sni,
client_hello_versions = Versions,
server_hello_selected_version = Version}) ->
- [Ext || Ext <- [RenegotiationInfo, SRP, HashSigns,
+ [Ext || Ext <- [RenegotiationInfo, SRP, HashSigns, SignatureSchemes,
EcPointFormats, EllipticCurves, ALPN,
NextProtocolNegotiation, Sni,
Versions, Version], Ext =/= undefined].
@@ -1962,6 +1974,16 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(Rest, Acc#hello_extensions{signature_algs =
#hash_sign_algos{hash_sign_algos = HashSignAlgos}});
+dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_CERT_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ SignSchemeListLen = Len - 2,
+ <<?UINT16(SignSchemeListLen), SignSchemeList/binary>> = ExtData,
+ SignSchemes = [ssl_cipher:signature_scheme(SignScheme) ||
+ <<?UINT16(SignScheme)>> <= SignSchemeList],
+ dec_hello_extensions(Rest, Acc#hello_extensions{signature_algs_cert =
+ #signature_scheme_list{
+ signature_scheme_list = SignSchemes}});
+
dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
<<?UINT16(_), EllipticCurveList/binary>> = ExtData,
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index cde1471f98..36aefd5e22 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -107,7 +107,8 @@
elliptic_curves,
sni,
client_hello_versions,
- server_hello_selected_version
+ server_hello_selected_version,
+ signature_algs_cert
}).
-record(server_hello, {
@@ -416,7 +417,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Supported Versions TLS 1.3 section 4.2.1 also affects TLS-1.2
+%% Supported Versions RFC 8446 (TLS 1.3) section 4.2.1 also affects TLS-1.2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(SUPPORTED_VERSIONS_EXT, 43).
@@ -424,4 +425,12 @@
-record(client_hello_versions, {versions}).
-record(server_hello_selected_version, {selected_version}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Signature Algorithms RFC 8446 (TLS 1.3) section 4.2.3 also affects TLS-1.2
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SIGNATURE_ALGORITHMS_CERT_EXT, 50).
+
+-record(signature_scheme_list, {signature_scheme_list}).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index d3f8f8224e..5a18f6aa99 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -168,6 +168,7 @@
crl_check :: boolean() | peer | best_effort,
crl_cache,
signature_algs,
+ signature_algs_cert,
eccs,
honor_ecc_order :: boolean(),
max_handshake_size :: integer(),
diff --git a/lib/ssl/src/tls_handshake_1_3.hrl b/lib/ssl/src/tls_handshake_1_3.hrl
index 0ef954e2e9..9ee0e0f845 100644
--- a/lib/ssl/src/tls_handshake_1_3.hrl
+++ b/lib/ssl/src/tls_handshake_1_3.hrl
@@ -40,18 +40,18 @@
%% %% when a "hello-retry-request" (special server_hello) is sent
-define(MESSAGE_HASH, 254).
-%% %% RFC 8446 B.3.1.
-%% %% New extension types in TLS-1.3
--define(PRE_SHARED_KEY, 41).
--define(EARLY_DATA, 42).
-%%-define(SUPPORTED_VERSIONS, 43). %% Updates TLS 1.2 so defined in ssl_handshake.hrl
--define(COOKIE, 44).
--define(PSK_KEY_EXCHANGE_MODES, 45).
--define(CERTIFICATE_AUTHORITIES, 47).
--define(OID_FILTERS, 48).
--define(POST_HANDSHAKE_AUTH, 49).
--define(SIGNATURE_ALGORITHMS_CERT, 50).
--define(KEY_SHARE, 51).
+%% %% RFC 8446 B.3.1.
+%% %% New extension types in TLS-1.3
+-define(PRE_SHARED_KEY_EXT, 41).
+-define(EARLY_DATA_EXT, 42).
+%%-define(SUPPORTED_VERSIONS_EXT, 43). %% Updates TLS 1.2 so defined in ssl_handshake.hrl
+-define(COOKIE_EXT, 44).
+-define(PSK_KEY_EXCHANGE_MODES_EXT, 45).
+-define(CERTIFICATE_AUTHORITIES_EXT, 47).
+-define(OID_FILTERS_EXT, 48).
+-define(POST_HANDSHAKE_AUTH_EXT, 49).
+%% -define(SIGNATURE_ALGORITHMS_CERT_EXT, 50). %% Updates TLS 1.2 so defined in ssl_handshake.hrl
+-define(KEY_SHARE_EXT, 51).
%% RFC 8446 B.3.1
-record(key_share_entry, {
@@ -133,10 +133,6 @@
-define(RSA_PKCS1_SHA1, 16#201).
-define(ECDSA_SHA1, 16#0203).
--record(signature_scheme_list, {
- signature_scheme_list
- }).
-
%% RFC 8446 B.3.1.4. Supported Groups Extension
%% Elliptic Curve Groups (ECDHE)
-define(SECP256R1, 16#0017).
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 79d50684f1..e6be574916 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -32,7 +32,8 @@
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, hmac_hash/3,
setup_keys/8, suites/1, prf/5,
ecc_curves/1, ecc_curves/2, oid_to_enum/1, enum_to_oid/1,
- default_signature_algs/1, signature_algs/2, v1_3_filters/0]).
+ default_signature_algs/1, signature_algs/2, v1_3_filters/0,
+ default_signature_schemes/1, signature_schemes/2]).
-type named_curve() :: sect571r1 | sect571k1 | secp521r1 | brainpoolP512r1 |
sect409k1 | sect409r1 | brainpoolP384r1 | secp384r1 |
@@ -303,6 +304,64 @@ default_signature_algs({3, 3} = Version) ->
default_signature_algs(_) ->
undefined.
+
+signature_schemes(Version, SignatureSchemes) when is_tuple(Version)
+ andalso Version >= {3, 3} ->
+ CryptoSupports = crypto:supports(),
+ Hashes = proplists:get_value(hashs, CryptoSupports),
+ PubKeys = proplists:get_value(public_keys, CryptoSupports),
+ Curves = proplists:get_value(curves, CryptoSupports),
+ Fun = fun (Scheme, Acc) ->
+ {Hash0, Sign0, Curve} =
+ ssl_cipher:scheme_to_components(Scheme),
+ Sign = case Sign0 of
+ rsa_pkcs1 -> rsa;
+ S -> S
+ end,
+ Hash = case Hash0 of
+ sha1 -> sha;
+ H -> H
+ end,
+ case proplists:get_bool(Sign, PubKeys)
+ andalso proplists:get_bool(Hash, Hashes)
+ andalso (Curve =:= undefined orelse
+ proplists:get_bool(Curve, Curves))
+ andalso is_pair(Hash, Sign, Hashes)
+ of
+ true ->
+ [Scheme | Acc];
+ false ->
+ Acc
+ end
+ end,
+ Supported = lists:foldl(Fun, [], SignatureSchemes),
+ lists:reverse(Supported);
+signature_schemes(_, _) ->
+ [].
+
+
+default_signature_schemes(Version) ->
+ Default = [
+ rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ %% ed25519,
+ %% ed448,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1
+ ],
+ signature_schemes(Version, Default).
+
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------