aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Dimitrov <[email protected]>2019-05-24 15:00:33 +0200
committerGitHub <[email protected]>2019-05-24 15:00:33 +0200
commit1014d7d46c39e2ab829d6c6c968b37ee9ae7a929 (patch)
treea8e332d8cf223268c5e435dfca45c5c2cfacdd11
parentf8a89b02fa87598a6d6340c9184eecfe30bc0514 (diff)
parenta816848aaa259d7d2ee58ec2518220a046d3044d (diff)
downloadotp-1014d7d46c39e2ab829d6c6c968b37ee9ae7a929.tar.gz
otp-1014d7d46c39e2ab829d6c6c968b37ee9ae7a929.tar.bz2
otp-1014d7d46c39e2ab829d6c6c968b37ee9ae7a929.zip
Merge pull request #2234 from peterdmv/peterdmv/ssl/tls13-client
Add basic TLS 1.3 client
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml400
-rw-r--r--lib/ssl/src/ssl_handshake.erl5
-rw-r--r--lib/ssl/src/ssl_logger.erl5
-rw-r--r--lib/ssl/src/tls_connection.erl22
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl61
-rw-r--r--lib/ssl/src/tls_handshake.erl39
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl646
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl457
8 files changed, 1327 insertions, 308 deletions
diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml
index ca98385f85..3bd86178c8 100644
--- a/lib/ssl/doc/src/standards_compliance.xml
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -126,10 +126,10 @@
<section>
<title>TLS 1.3</title>
- <p>OTP-22 introduces basic support for TLS 1.3 on the server side. Basic functionality
+ <p>OTP-22 introduces basic support for TLS 1.3. Basic functionality
covers a simple TLS 1.3 handshake with support of the mandatory extensions
(supported_groups, signature_algorithms, key_share, supported_versions and
- signature_algorithms_cert). The server supports a selective set of cryptographic algorithms:</p>
+ signature_algorithms_cert). The current implementation supports a selective set of cryptographic algorithms:</p>
<list type="bulleted">
<item>Key Exchange: ECDHE</item>
<item>Groups: all standard groups supported for the Diffie-Hellman key exchange</item>
@@ -140,15 +140,12 @@
</list>
<p>Other notable features:</p>
<list type="bulleted">
- <item>The server supports the HelloRetryRequest mechanism</item>
<item>PSK and session resumption not supported</item>
<item>Early data and 0-RTT not supported</item>
<item>Key and Initialization Vector Update not supported</item>
</list>
<p>For more detailed information see the
<seealso marker="#soc_table">Standards Compliance</seealso> below.</p>
- <warning><p>Note that the client side is not yet functional. It is planned to be released
- later in OTP-22.</p></warning>
<p> The following table describes the current state of standards compliance for TLS 1.3.</p>
<p>(<em>C</em> = Compliant, <em>NC</em> = Non-Compliant, <em>PC</em> = Partially-Compliant,
@@ -176,25 +173,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Version downgrade protection mechanism</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">RSASSA-PSS signature schemes</cell>
<cell align="left" valign="middle"><em>PC</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (ClientHello) extension</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert extension</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -211,7 +208,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">(EC)DHE</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -295,8 +292,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -319,14 +316,14 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_groups (RFC7919)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -373,8 +370,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -403,8 +400,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -427,8 +424,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -459,13 +456,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_groups (RFC7919)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -513,7 +510,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -543,7 +540,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -567,7 +564,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -577,20 +574,20 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Version downgrade protection</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -601,8 +598,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -615,13 +612,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Version downgrade protection</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -633,7 +630,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -650,7 +647,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -662,7 +659,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -672,8 +669,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -706,26 +703,26 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha256</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha384</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha512</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -748,20 +745,20 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha256</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha384</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha512</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -796,14 +793,14 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ecdsa_sha1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -816,19 +813,19 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha512</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -852,19 +849,19 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha512</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -900,13 +897,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha1</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ecdsa_sha1</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -967,68 +964,68 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">secp256r1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">secp384r1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">secp521r1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">x25519</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">x448</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe2048</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe3072</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe4096</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe6144</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe8192</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -1105,8 +1102,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1224,8 +1221,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1362,8 +1359,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1374,8 +1371,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1398,8 +1395,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -1417,8 +1414,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1441,8 +1438,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1463,8 +1460,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1521,73 +1518,82 @@
4.4.2.2. Server Certificate Selection
</url>
</cell>
- <cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate type MUST be X.509v3</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">The certificate type MUST be X.509v3, unless explicitly
+ negotiated otherwise</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate's public key is compatible</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">The server's end-entity certificate's public key (and associated
+ restrictions) MUST be compatible with the selected authentication
+ algorithm from the client's "signature_algorithms" extension
+ (currently RSA, ECDSA, or EdDSA).</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing
+ with a signature scheme indicated in the client's "signature_algorithms"/"signature_algorithms_cert"
+ extensions</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">server_name and certificate_authorities are used</cell>
+ <cell align="left" valign="middle">The "server_name" and "certificate_authorities"
+ extensions are used to guide certificate selection. As servers
+ MAY require the presence of the "server_name" extension, clients
+ SHOULD send this extension, when applicable.</cell>
<cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"></cell>
</row>
<row>
- <cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.3">
+ 4.4.2.3. Client Certificate Selection
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
<cell align="left" valign="middle"><em>PC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate type MUST be X.509v3</cell>
+ <cell align="left" valign="middle">The certificate type MUST be X.509v3, unless explicitly
+ negotiated otherwise</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>22</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate's public key is compatible</cell>
- <cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>22</em></cell>
+ <cell align="left" valign="middle">If the "certificate_authorities" extension in the
+ CertificateRequest message was present, at least one of the
+ certificates in the certificate chain SHOULD be issued by one of
+ the listed CAs.</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing</cell>
+ <cell align="left" valign="middle">The certificates MUST be signed using an acceptable signature
+ algorithm</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>22</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">server_name and certificate_authorities are used</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
- </row>
-
- <row>
- <cell align="left" valign="middle">
- <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.3">
- 4.4.2.3. Client Certificate Selection
- </url>
- </cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">If the CertificateRequest message contained a non-empty
+ "oid_filters" extension, the end-entity certificate MUST match the
+ extension OIDs that are recognized by the client</cell>
<cell align="left" valign="middle"><em>NC</em></cell>
<cell align="left" valign="middle"><em></em></cell>
</row>
@@ -1599,8 +1605,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1616,8 +1622,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1633,8 +1639,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1738,25 +1744,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST NOT be interleaved with other record types</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST NOT span key changes</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST NOT send zero-length fragments</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Alert messages MUST NOT be fragmented</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1807,7 +1813,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">The padding sent is automatically verified</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1957,19 +1963,19 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST implement the TLS_AES_128_GCM_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">SHOULD implement the TLS_AES_256_GCM_SHA384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">SHOULD implement the TLS_CHACHA20_POLY1305_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1982,13 +1988,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST support rsa_pkcs1_sha256 (for certificates)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST support rsa_pss_rsae_sha256 (for CertificateVerify and certificates)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2007,13 +2013,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST support key exchange with secp256r1</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">SHOULD support key exchange with X25519</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -2030,7 +2036,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Supported Versions</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2042,25 +2048,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Signature Algorithms</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Signature Algorithms Certificate</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Negotiated Groups</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Key Share</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2072,32 +2078,32 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>MUST send and use these extensions</em></cell>
- <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
<cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"supported_versions" is REQUIRED for ClientHello, ServerHello and HelloRetryRequest</cell>
- <cell align="left" valign="middle"><em>PC</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"signature_algorithms" is REQUIRED for certificate authentication</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"supported_groups" is REQUIRED for ClientHello messages using (EC)DHE key exchange</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"key_share" is REQUIRED for (EC)DHE key exchange</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2115,20 +2121,20 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>TLS 1.3 ClientHello</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">If not containing a "pre_shared_key" extension, it MUST contain both a "signature_algorithms" extension and a "supported_groups" extension.</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">If containing a "supported_groups" extension, it MUST also contain a "key_share" extension, and vice versa. An empty KeyShare.client_shares vector is permitted.</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -2151,30 +2157,44 @@
</url>
</cell>
<cell align="left" valign="middle"><em></em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>MUST correctly handle extensible fields</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">A client sending a ClientHello MUST support all parameters advertised in it.</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">A client sending a ClientHello MUST support all parameters
+ advertised in it. Otherwise, the server may fail to interoperate by selecting one of those parameters.</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">A middlebox which terminates a TLS connection MUST behave as a compliant TLS server</cell>
+ <cell align="left" valign="middle">A server receiving a ClientHello MUST correctly ignore all
+ unrecognized cipher suites, extensions, and other parameters. Otherwise, it may fail to
+ interoperate with newer clients. In TLS 1.3, a client receiving a CertificateRequest or
+ NewSessionTicket MUST also ignore all unrecognized extensions.</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">A middlebox which terminates a TLS connection MUST behave as a
+ compliant TLS server</cell>
<cell align="left" valign="middle"><em>NA</em></cell>
<cell align="left" valign="middle"></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">A middlebox which forwards ClientHello parameters it does not understand MUST NOT process any messages beyond that ClientHello.</cell>
+ <cell align="left" valign="middle">A middlebox which forwards ClientHello parameters it does not
+ understand MUST NOT process any messages beyond that ClientHello. It MUST forward all subsequent
+ traffic unmodified. Otherwise, it may fail to interoperate with newer clients and servers.</cell>
<cell align="left" valign="middle"><em>NA</em></cell>
<cell align="left" valign="middle"></cell>
</row>
@@ -2193,25 +2213,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_AES_128_GCM_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_AES_256_GCM_SHA384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_CHACHA20_POLY1305_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_AES_128_CCM_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index f68d3e9b26..b51ba0fa2d 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -3046,6 +3046,11 @@ empty_extensions({3,4}, server_hello) ->
key_share => undefined,
pre_shared_key => undefined
};
+empty_extensions({3,4}, hello_retry_request) ->
+ #{server_hello_selected_version => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined
+ };
empty_extensions(_, server_hello) ->
#{renegotiation_info => undefined,
alpn => undefined,
diff --git a/lib/ssl/src/ssl_logger.erl b/lib/ssl/src/ssl_logger.erl
index 987693b96b..514a4464bc 100644
--- a/lib/ssl/src/ssl_logger.erl
+++ b/lib/ssl/src/ssl_logger.erl
@@ -200,6 +200,11 @@ parse_handshake(Direction, #encrypted_extensions{} = EncryptedExtensions) ->
Header = io_lib:format("~s Handshake, EncryptedExtensions",
[header_prefix(Direction)]),
Message = io_lib:format("~p", [?rec_info(encrypted_extensions, EncryptedExtensions)]),
+ {Header, Message};
+parse_handshake(Direction, #new_session_ticket{} = NewSessionTicket) ->
+ Header = io_lib:format("~s Post-Handshake, NewSessionTicket",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(new_session_ticket, NewSessionTicket)]),
{Header, Message}.
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 61281a3fb2..2651fc09bd 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -31,6 +31,7 @@
-include("tls_connection.hrl").
-include("tls_handshake.hrl").
+-include("tls_handshake_1_3.hrl").
-include("ssl_alert.hrl").
-include("tls_record.hrl").
-include("ssl_cipher.hrl").
@@ -394,6 +395,7 @@ queue_handshake(Handshake, #state{handshake_env = #handshake_env{tls_handshake_h
handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist},
flight_buffer = Flight0 ++ [BinHandshake]}.
+
send_handshake_flight(#state{static_env = #static_env{socket = Socket,
transport_cb = Transport},
flight_buffer = Flight} = State0) ->
@@ -659,10 +661,16 @@ hello(internal, #server_hello{} = Hello,
case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert -> %%TODO
ssl_connection:handle_own_alert(Alert, ReqVersion, hello,
- State#state{connection_env = CEnv#connection_env{negotiated_version = ReqVersion}});
+ State#state{connection_env =
+ CEnv#connection_env{negotiated_version = ReqVersion}});
+ %% Legacy TLS 1.2 and older
{Version, NewId, ConnectionStates, ProtoExt, Protocol} ->
ssl_connection:handle_session(Hello,
- Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
+ Version, NewId, ConnectionStates, ProtoExt, Protocol, State);
+ %% TLS 1.3
+ {next_state, wait_sh} ->
+ %% Continue in TLS 1.3 'wait_sh' state
+ {next_state, wait_sh, State, [{next_event, internal, Hello}]}
end;
hello(info, Event, State) ->
gen_info(Event, ?FUNCTION_NAME, State);
@@ -803,6 +811,11 @@ connection(internal, #client_hello{},
State = reinit_handshake_data(State0),
next_event(?FUNCTION_NAME, no_record, State);
+connection(internal, #new_session_ticket{}, State) ->
+ %% TLS 1.3
+ %% Drop NewSessionTicket (currently not supported)
+ next_event(?FUNCTION_NAME, no_record, State);
+
connection(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
@@ -1286,9 +1299,10 @@ maybe_generate_client_shares(#ssl_options{
versions = [Version|_],
supported_groups =
#supported_groups{
- supported_groups = Groups}})
+ supported_groups = [Group|_]}})
when Version =:= {3,4} ->
- ssl_cipher:generate_client_shares(Groups);
+ %% Generate only key_share entry for the most preferred group
+ ssl_cipher:generate_client_shares([Group]);
maybe_generate_client_shares(_) ->
undefined.
diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
index 76cdebc76f..821b7000cc 100644
--- a/lib/ssl/src/tls_connection_1_3.erl
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -112,7 +112,10 @@
negotiated/4,
wait_cert/4,
wait_cv/4,
- wait_finished/4
+ wait_finished/4,
+ wait_sh/4,
+ wait_ee/4,
+ wait_cert_cr/4
]).
@@ -127,6 +130,13 @@ start(internal, #client_hello{} = Hello, State0, _Module) ->
{State, negotiated} ->
{next_state, negotiated, State, [{next_event, internal, start_handshake}]}
end;
+start(internal, #server_hello{} = ServerHello, State0, _Module) ->
+ case tls_handshake_1_3:do_start(ServerHello, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, start, State0);
+ {State, NextState} ->
+ {next_state, NextState, State, []}
+ end;
start(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
@@ -183,3 +193,52 @@ wait_finished(internal,
end;
wait_finished(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_sh(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_sh(internal, #server_hello{} = Hello, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_sh(Hello, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_sh, State0);
+ {State1, start, ServerHello} ->
+ %% hello_retry_request: go to start
+ {next_state, start, State1, [{next_event, internal, ServerHello}]};
+ {State1, wait_ee} ->
+ tls_connection:next_event(wait_ee, no_record, State1)
+ end;
+wait_sh(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_ee(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_ee(internal, #encrypted_extensions{} = EE, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_ee(EE, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_ee, State0);
+ {State1, NextState} ->
+ tls_connection:next_event(NextState, no_record, State1)
+ end;
+wait_ee(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_cert_cr(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_cert_cr(internal, #certificate_1_3{} = Certificate, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_cert_cr(Certificate, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State0);
+ {State1, NextState} ->
+ tls_connection:next_event(NextState, no_record, State1)
+ end;
+wait_cert_cr(internal, #certificate_request_1_3{} = CertificateRequest, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_cert_cr(CertificateRequest, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State0);
+ {State1, NextState} ->
+ tls_connection:next_event(NextState, no_record, State1)
+ end;
+wait_cert_cr(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 2480e05097..c132f75eae 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -105,7 +105,7 @@ client_hello(Host, Port, ConnectionStates,
{tls_record:tls_version(), {resumed | new, #session{}},
ssl_record:connection_states(), binary() | undefined,
HelloExt::map(), {ssl:hash(), ssl:sign_algo()} |
- undefined} | #alert{}.
+ undefined} | {atom(), atom()} |#alert{}.
%%
%% Description: Handles a received hello message
%%--------------------------------------------------------------------
@@ -148,29 +148,48 @@ hello(#server_hello{server_version = {Major, Minor},
%%
%% - If "supported_version" is present (ServerHello):
%% - Abort handshake with an "illegal_parameter" alert
-hello(#server_hello{server_version = Version,
+hello(#server_hello{server_version = LegacyVersion,
+ random = Random,
+ cipher_suite = CipherSuite,
+ compression_method = Compression,
+ session_id = SessionId,
extensions = #{server_hello_selected_version :=
- #server_hello_selected_version{selected_version = Version}}
+ #server_hello_selected_version{selected_version = Version} = HelloExt}
},
- #ssl_options{versions = SupportedVersions},
- _ConnectionStates0, _Renegotiation) ->
- case tls_record:is_higher({3,4}, Version) of
+ #ssl_options{versions = SupportedVersions} = SslOpt,
+ ConnectionStates0, Renegotiation) ->
+ %% In TLS 1.3, the TLS server indicates its version using the "supported_versions" extension
+ %% (Section 4.2.1), and the legacy_version field MUST be set to 0x0303, which is the version
+ %% number for TLS 1.2.
+ %% The "supported_versions" extension is supported from TLS 1.2.
+ case LegacyVersion > {3,3} orelse
+ LegacyVersion =:= {3,3} andalso Version < {3,3} of
true ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
false ->
case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
- %% Implement TLS 1.3 statem ???
- ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+ case Version of
+ {3,3} ->
+ %% TLS 1.2 ServerHello with "supported_versions" (special case)
+ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
+ Compression, HelloExt, SslOpt,
+ ConnectionStates0, Renegotiation);
+ {3,4} ->
+ %% TLS 1.3
+ {next_state, wait_sh}
+ end;
false ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
end
end;
-hello(#server_hello{server_version = Version, random = Random,
+hello(#server_hello{server_version = Version,
+ random = Random,
cipher_suite = CipherSuite,
compression_method = Compression,
- session_id = SessionId, extensions = HelloExt},
+ session_id = SessionId,
+ extensions = HelloExt},
#ssl_options{versions = SupportedVersions} = SslOpt,
ConnectionStates0, Renegotiation) ->
case tls_record:is_acceptable_version(Version, SupportedVersions) of
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 8a4ad922e1..12ab2015aa 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -46,7 +46,17 @@
do_negotiated/2,
do_wait_cert/2,
do_wait_cv/2,
- do_wait_finished/2]).
+ do_wait_finished/2,
+ do_wait_sh/2,
+ do_wait_ee/2,
+ do_wait_cert_cr/2]).
+
+
+%% crypto:hash(sha256, "HelloRetryRequest").
+-define(HELLO_RETRY_REQUEST_RANDOM, <<207,33,173,116,229,154,97,17,
+ 190,29,140,2,30,101,184,145,
+ 194,162,17,22,122,187,140,94,
+ 7,158,9,226,200,168,51,156>>).
%%====================================================================
%% Create handshake messages
@@ -79,7 +89,7 @@ server_hello_random(server_hello, #security_parameters{server_random = Random})
%% CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
%% C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
server_hello_random(hello_retry_request, _) ->
- crypto:hash(sha256, "HelloRetryRequest").
+ ?HELLO_RETRY_REQUEST_RANDOM.
%% TODO: implement support for encrypted_extensions
@@ -111,7 +121,7 @@ add_signature_algorithms_cert(Extensions, undefined) ->
Extensions;
add_signature_algorithms_cert(Extensions, SignAlgsCert) ->
Extensions#{signature_algorithms_cert =>
- #signature_algorithms{signature_scheme_list = SignAlgsCert}}.
+ #signature_algorithms_cert{signature_scheme_list = SignAlgsCert}}.
filter_tls13_algs(undefined) -> undefined;
@@ -119,7 +129,6 @@ filter_tls13_algs(Algo) ->
lists:filter(fun is_atom/1, Algo).
-%% TODO: use maybe monad for error handling!
%% enum {
%% X509(0),
%% RawPublicKey(2),
@@ -142,18 +151,28 @@ filter_tls13_algs(Algo) ->
%% opaque certificate_request_context<0..2^8-1>;
%% CertificateEntry certificate_list<0..2^24-1>;
%% } Certificate;
-certificate(OwnCert, CertDbHandle, CertDbRef, _CRContext, server) ->
+certificate(OwnCert, CertDbHandle, CertDbRef, _CRContext, Role) ->
case ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef) of
{ok, _, Chain} ->
CertList = chain_to_cert_list(Chain),
%% If this message is in response to a CertificateRequest, the value of
%% certificate_request_context in that message. Otherwise (in the case
%%of server authentication), this field SHALL be zero length.
- #certificate_1_3{
- certificate_request_context = <<>>,
- certificate_list = CertList};
- {error, Error} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {server_has_no_suitable_certificates, Error})
+ {ok, #certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = CertList}};
+ {error, Error} when Role =:= server ->
+ {error, {no_suitable_certificates, Error}};
+ {error, _Error} when Role =:= client ->
+ %% The client MUST send a Certificate message if and only if the server
+ %% has requested client authentication via a CertificateRequest message
+ %% (Section 4.3.2). If the server requests client authentication but no
+ %% suitable certificate is available, the client MUST send a Certificate
+ %% message containing no certificates (i.e., with the "certificate_list"
+ %% field having length 0).
+ {ok, #certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []}}
end.
@@ -161,7 +180,7 @@ certificate_verify(PrivateKey, SignatureScheme,
#state{connection_states = ConnectionStates,
handshake_env =
#handshake_env{
- tls_handshake_history = {Messages, _}}}, server) ->
+ tls_handshake_history = {Messages, _}}}, Role) ->
#{security_parameters := SecParamsR} =
ssl_record:pending_connection_state(ConnectionStates, write),
#security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
@@ -173,11 +192,11 @@ certificate_verify(PrivateKey, SignatureScheme,
%% Transcript-Hash uses the HKDF hash function defined by the cipher suite.
THash = tls_v1:transcript_hash(Context, HKDFAlgo),
+ ContextString = context_string(Role),
%% Digital signatures use the hash function defined by the selected signature
%% scheme.
- case sign(THash, <<"TLS 1.3, server CertificateVerify">>,
- HashAlgo, PrivateKey) of
+ case sign(THash, ContextString, HashAlgo, PrivateKey) of
{ok, Signature} ->
{ok, #certificate_verify_1_3{
algorithm = SignatureScheme,
@@ -252,6 +271,21 @@ encode_handshake(HandshakeMsg) ->
%% Decode handshake
%%====================================================================
+
+decode_handshake(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+ ?BYTE(SID_length), Session_ID:SID_length/binary,
+ Cipher_suite:2/binary, ?BYTE(Comp_method),
+ ?UINT16(ExtLen), Extensions:ExtLen/binary>>)
+ when Random =:= ?HELLO_RETRY_REQUEST_RANDOM ->
+ HelloExtensions = ssl_handshake:decode_hello_extensions(Extensions, {3,4}, {Major, Minor},
+ hello_retry_request),
+ #server_hello{
+ server_version = {Major,Minor},
+ random = Random,
+ session_id = Session_ID,
+ cipher_suite = Cipher_suite,
+ compression_method = Comp_method,
+ extensions = HelloExtensions};
decode_handshake(?CERTIFICATE_REQUEST, <<?BYTE(0), ?UINT16(Size), EncExts:Size/binary>>) ->
Exts = decode_extensions(EncExts, certificate_request),
#certificate_request_1_3{
@@ -428,6 +462,7 @@ build_content(Context, THash) ->
%%====================================================================
+%% TLS Server
do_start(#client_hello{cipher_suites = ClientCiphers,
session_id = SessionId,
extensions = Extensions} = _Hello,
@@ -436,7 +471,6 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
signature_algs = ServerSignAlgs,
supported_groups = ServerGroups0},
session = #session{own_certificate = Cert}} = State0) ->
-
ClientGroups0 = maps:get(elliptic_curves, Extensions, undefined),
ClientGroups = get_supported_groups(ClientGroups0),
ServerGroups = get_supported_groups(ServerGroups0),
@@ -449,8 +483,6 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
ClientSignAlgsCert = get_signature_scheme_list(
maps:get(signature_algs_cert, Extensions, undefined)),
- %% TODO: use library function if it exists
- %% Init the maybe "monad"
{Ref,Maybe} = maybe(),
try
@@ -460,7 +492,7 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
%% the client.
Cipher = Maybe(select_cipher_suite(ClientCiphers, ServerCiphers)),
Groups = Maybe(select_common_groups(ServerGroups, ClientGroups)),
- Maybe(validate_key_share(ClientGroups, ClientShares)),
+ Maybe(validate_client_key_share(ClientGroups, ClientShares)),
{PublicKeyAlgo, SignAlgo, SignHash} = get_certificate_params(Cert),
@@ -506,6 +538,81 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
{Ref, {insufficient_security, no_suitable_public_key}} ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ end;
+%% TLS Client
+do_start(#server_hello{cipher_suite = SelectedCipherSuite,
+ session_id = SessionId,
+ extensions = Extensions} = _ServerHello,
+ #state{static_env = #static_env{role = client,
+ host = Host,
+ port = Port,
+ transport_cb = Transport,
+ socket = Socket,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _},
+ tls_handshake_history = _HHistory} = HsEnv,
+ connection_env = CEnv,
+ ssl_options = #ssl_options{ciphers = ClientCiphers,
+ supported_groups = ClientGroups0} = SslOpts,
+ session = #session{own_certificate = Cert} = Session0,
+ connection_states = ConnectionStates0
+ } = State0) ->
+ ClientGroups = get_supported_groups(ClientGroups0),
+
+ {Ref,Maybe} = maybe(),
+ try
+ ServerKeyShare = maps:get(key_share, Extensions, undefined),
+ SelectedGroup = get_selected_group(ServerKeyShare),
+
+ %% Upon receipt of this extension in a HelloRetryRequest, the client
+ %% MUST verify that (1) the selected_group field corresponds to a group
+ %% which was provided in the "supported_groups" extension in the
+ %% original ClientHello and (2) the selected_group field does not
+ %% correspond to a group which was provided in the "key_share" extension
+ %% in the original ClientHello. If either of these checks fails, then
+ %% the client MUST abort the handshake with an "illegal_parameter"
+ %% alert.
+ Maybe(validate_selected_group(SelectedGroup, ClientGroups)),
+
+ Maybe(validate_cipher_suite(SelectedCipherSuite, ClientCiphers)),
+
+ %% Otherwise, when sending the new ClientHello, the client MUST
+ %% replace the original "key_share" extension with one containing only a
+ %% new KeyShareEntry for the group indicated in the selected_group field
+ %% of the triggering HelloRetryRequest.
+ ClientKeyShare = ssl_cipher:generate_client_shares([SelectedGroup]),
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert, ClientKeyShare),
+
+ HelloVersion = tls_record:hello_version(SslOpts#ssl_options.versions),
+
+ %% Update state
+ State1 = update_start_state(State0, SelectedCipherSuite, ClientKeyShare, SessionId,
+ SelectedGroup, undefined, undefined),
+
+ %% Replace ClientHello1 with a special synthetic handshake message
+ State2 = replace_ch1_with_message_hash(State1),
+ #state{handshake_env = #handshake_env{tls_handshake_history = HHistory}} = State2,
+
+ {BinMsg, ConnectionStates, Handshake} =
+ tls_connection:encode_handshake(Hello, HelloVersion, ConnectionStates0, HHistory),
+ tls_socket:send(Transport, Socket, BinMsg),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'handshake', Hello),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'record', BinMsg),
+
+ State = State2#state{
+ connection_states = ConnectionStates,
+ connection_env = CEnv#connection_env{negotiated_version = HelloVersion}, %% Requested version
+ session = Session0#session{session_id = Hello#client_hello.session_id},
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = Handshake},
+ key_share = ClientKeyShare},
+
+ {State, wait_sh}
+
+ catch
+ {Ref, {illegal_parameter, Reason}} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER, Reason)
end.
@@ -515,7 +622,7 @@ do_negotiated(start_handshake,
own_certificate = OwnCert,
ecc = SelectedGroup,
sign_alg = SignatureScheme,
- dh_public_value = ClientKey},
+ dh_public_value = ClientPublicKey},
ssl_options = #ssl_options{} = SslOpts,
key_share = KeyShare,
handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
@@ -526,6 +633,8 @@ do_negotiated(start_handshake,
socket = _Socket,
transport_cb = _Transport}
} = State0) ->
+ ServerPrivateKey = get_server_private_key(KeyShare),
+
{Ref,Maybe} = maybe(),
try
@@ -536,7 +645,7 @@ do_negotiated(start_handshake,
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
State2 =
- calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare, State1),
+ calculate_handshake_secrets(ClientPublicKey, ServerPrivateKey, SelectedGroup, State1),
State3 = ssl_record:step_encryption_state(State2),
@@ -550,7 +659,7 @@ do_negotiated(start_handshake,
{State5, NextState} = maybe_send_certificate_request(State4, SslOpts),
%% Create Certificate
- Certificate = certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, server),
+ Certificate = Maybe(certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, server)),
%% Encode Certificate
State6 = tls_connection:queue_handshake(Certificate, State5),
@@ -574,14 +683,16 @@ do_negotiated(start_handshake,
catch
{Ref, badarg} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg})
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg});
+ {Ref, {no_suitable_certificates, Reason}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {no_suitable_certificates, Reason})
end.
do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
{Ref,Maybe} = maybe(),
try
- Maybe(process_client_certificate(Certificate, State0))
+ Maybe(process_certificate(Certificate, State0))
catch
{Ref, {certificate_required, State}} ->
{?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required), State};
@@ -599,8 +710,8 @@ do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
do_wait_cv(#certificate_verify_1_3{} = CertificateVerify, State0) ->
{Ref,Maybe} = maybe(),
try
- Maybe(verify_signature_algorithm(State0, CertificateVerify)),
- Maybe(verify_certificate_verify(State0, CertificateVerify))
+ State1 = Maybe(verify_signature_algorithm(State0, CertificateVerify)),
+ Maybe(verify_certificate_verify(State1, CertificateVerify))
catch
{Ref, {{bad_certificate, Reason}, State}} ->
{?ALERT_REC(?FATAL, ?BAD_CERTIFICATE, {bad_certificate, Reason}), State};
@@ -610,20 +721,9 @@ do_wait_cv(#certificate_verify_1_3{} = CertificateVerify, State0) ->
{?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {handshake_failure, Reason}), State}
end.
-
+%% TLS Server
do_wait_finished(#finished{verify_data = VerifyData},
- #state{connection_states = _ConnectionStates0,
- session = #session{session_id = _SessionId,
- own_certificate = _OwnCert},
- ssl_options = #ssl_options{} = _SslOpts,
- key_share = _KeyShare,
- handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
- static_env = #static_env{
- cert_db = _CertDbHandle,
- cert_db_ref = _CertDbRef,
- socket = _Socket,
- transport_cb = _Transport}
- } = State0) ->
+ #state{static_env = #static_env{role = server}} = State0) ->
{Ref,Maybe} = maybe(),
@@ -639,19 +739,224 @@ do_wait_finished(#finished{verify_data = VerifyData},
catch
{Ref, decrypt_error} ->
?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error)
+ end;
+%% TLS Client
+do_wait_finished(#finished{verify_data = _VerifyData},
+ #state{static_env = #static_env{role = client}} = State0) ->
+
+ {Ref,Maybe} = maybe(),
+
+ try
+ %% Maybe(validate_client_finished(State0, VerifyData)),
+
+ %% Maybe send Certificate + CertificateVerify
+ State1 = Maybe(maybe_queue_cert_cert_cv(State0)),
+
+ Finished = finished(State1),
+
+ %% Encode Finished
+ State2 = tls_connection:queue_handshake(Finished, State1),
+
+ %% Send first flight
+ {State3, _} = tls_connection:send_handshake_flight(State2),
+
+ State4 = calculate_traffic_secrets(State3),
+
+ %% Configure traffic keys
+ ssl_record:step_encryption_state(State4)
+
+ catch
+ {Ref, decrypt_error} ->
+ ?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error);
+ {Ref, badarg} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg});
+ {Ref, {no_suitable_certificates, Reason}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {no_suitable_certificates, Reason})
end.
+do_wait_sh(#server_hello{cipher_suite = SelectedCipherSuite,
+ session_id = SessionId,
+ extensions = Extensions} = ServerHello,
+ #state{key_share = ClientKeyShare0,
+ ssl_options = #ssl_options{ciphers = ClientCiphers,
+ supported_groups = ClientGroups0}} = State0) ->
+ ClientGroups = get_supported_groups(ClientGroups0),
+ ServerKeyShare0 = maps:get(key_share, Extensions, undefined),
+ ClientKeyShare = get_key_shares(ClientKeyShare0),
+
+ {Ref,Maybe} = maybe(),
+ try
+ %% Go to state 'start' if server replies with 'HelloRetryRequest'.
+ Maybe(maybe_hello_retry_request(ServerHello, State0)),
+
+ ServerKeyShare = get_key_shares(ServerKeyShare0),
+
+ Maybe(validate_cipher_suite(SelectedCipherSuite, ClientCiphers)),
+ Maybe(validate_server_key_share(ClientGroups, ServerKeyShare)),
+
+ %% Get server public key
+ {SelectedGroup, ServerPublicKey} = get_server_public_key(ServerKeyShare),
+
+ {_, ClientPrivateKey} = get_client_private_key([SelectedGroup], ClientKeyShare),
+
+ %% Update state
+ State1 = update_start_state(State0, SelectedCipherSuite, ClientKeyShare0, SessionId,
+ SelectedGroup, undefined, ServerPublicKey),
+
+ State2 = calculate_handshake_secrets(ServerPublicKey, ClientPrivateKey, SelectedGroup, State1),
+
+ State3 = ssl_record:step_encryption_state(State2),
+
+ {State3, wait_ee}
+
+ catch
+ {Ref, {State, StateName, ServerHello}} ->
+ {State, StateName, ServerHello};
+ {Ref, {insufficient_security, no_suitable_groups}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
+ {Ref, illegal_parameter} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ {Ref, no_suitable_cipher} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
+ {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
+ {Ref, {insufficient_security, no_suitable_public_key}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ end.
+
+
+do_wait_ee(#encrypted_extensions{extensions = _Extensions}, State0) ->
+
+ {Ref,_Maybe} = maybe(),
+
+ try
+ {State0, wait_cert_cr}
+ catch
+ {Ref, {insufficient_security, no_suitable_groups}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
+ {Ref, illegal_parameter} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ {Ref, no_suitable_cipher} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
+ {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
+ {Ref, {insufficient_security, no_suitable_public_key}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ end.
+
+
+do_wait_cert_cr(#certificate_1_3{} = Certificate, State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ Maybe(process_certificate(Certificate, State0))
+ catch
+ {Ref, {certificate_required, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required);
+ {Ref, {{certificate_unknown, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason);
+ {Ref, {{internal_error, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason);
+ {Ref, {{handshake_failure, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason)
+ end;
+do_wait_cert_cr(#certificate_request_1_3{} = CertificateRequest, State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ Maybe(process_certificate_request(CertificateRequest, State0))
+ catch
+ {Ref, {certificate_required, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required);
+ {Ref, {{certificate_unknown, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason);
+ {Ref, {illegal_parameter, Reason}} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER, Reason);
+ {Ref, {{internal_error, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason);
+ {Ref, {{handshake_failure, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason)
+ end.
+
+
+
%% TODO: Remove this function!
%% not_implemented(State, Reason) ->
%% {error, {not_implemented, State, Reason}}.
-%%
+
%% not_implemented(update_secrets, State0, Reason) ->
%% State1 = calculate_traffic_secrets(State0),
%% State = ssl_record:step_encryption_state(State1),
%% {error, {not_implemented, State, Reason}}.
+%% For reasons of backward compatibility with middleboxes (see
+%% Appendix D.4), the HelloRetryRequest message uses the same structure
+%% as the ServerHello, but with Random set to the special value of the
+%% SHA-256 of "HelloRetryRequest":
+%%
+%% CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
+%% C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
+%%
+%% Upon receiving a message with type server_hello, implementations MUST
+%% first examine the Random value and, if it matches this value, process
+%% it as described in Section 4.1.4).
+maybe_hello_retry_request(#server_hello{random = ?HELLO_RETRY_REQUEST_RANDOM} = ServerHello, State0) ->
+ {error, {State0, start, ServerHello}};
+maybe_hello_retry_request(_, _) ->
+ ok.
+
+
+maybe_queue_cert_cert_cv(#state{client_certificate_requested = false} = State) ->
+ {ok, State};
+maybe_queue_cert_cert_cv(#state{connection_states = _ConnectionStates0,
+ session = #session{session_id = _SessionId,
+ own_certificate = OwnCert},
+ ssl_options = #ssl_options{} = _SslOpts,
+ key_share = _KeyShare,
+ handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
+ static_env = #static_env{
+ role = client,
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef,
+ socket = _Socket,
+ transport_cb = _Transport}
+ } = State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ %% Create Certificate
+ Certificate = Maybe(certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, client)),
+
+ %% Encode Certificate
+ State1 = tls_connection:queue_handshake(Certificate, State0),
+
+ %% Maybe create and queue CertificateVerify
+ State = Maybe(maybe_queue_cert_verify(Certificate, State1)),
+ {ok, State}
+ catch
+ {Ref, badarg} ->
+ {error, badarg}
+ end.
+
+
+%% Clients MUST send this message whenever authenticating via a certificate
+%% (i.e., when the Certificate message is non-empty).
+maybe_queue_cert_verify(#certificate_1_3{certificate_list = []}, State) ->
+ {ok, State};
+maybe_queue_cert_verify(_Certificate,
+ #state{connection_states = _ConnectionStates0,
+ session = #session{sign_alg = SignatureScheme},
+ connection_env = #connection_env{private_key = CertPrivateKey},
+ static_env = #static_env{role = client}
+ } = State) ->
+ {Ref,Maybe} = maybe(),
+ try
+ CertificateVerify = Maybe(certificate_verify(CertPrivateKey, SignatureScheme, State, client)),
+ {ok, tls_connection:queue_handshake(CertificateVerify, State)}
+ catch
+ {Ref, badarg} ->
+ {error, badarg}
+ end.
+
%% Recipients of Finished messages MUST verify that the contents are
%% correct and if incorrect MUST terminate the connection with a
@@ -684,7 +989,7 @@ send_hello_retry_request(#state{connection_states = ConnectionStates0} = State0,
ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0),
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
- %% TODO: Fix handshake history!
+ %% Update handshake history
State2 = replace_ch1_with_message_hash(State1),
{ok, {State2, start}};
@@ -703,19 +1008,44 @@ maybe_send_certificate_request(State, #ssl_options{
{tls_connection:queue_handshake(CertificateRequest, State), wait_cert}.
-process_client_certificate(#certificate_1_3{
- certificate_request_context = <<>>,
- certificate_list = []},
- #state{ssl_options =
- #ssl_options{
- fail_if_no_peer_cert = false}} = State) ->
+process_certificate_request(#certificate_request_1_3{},
+ #state{session = #session{own_certificate = undefined}} = State) ->
+ {ok, {State#state{client_certificate_requested = true}, wait_cert}};
+
+process_certificate_request(#certificate_request_1_3{
+ extensions = Extensions},
+ #state{session = #session{own_certificate = Cert} = Session} = State) ->
+ ServerSignAlgs = get_signature_scheme_list(
+ maps:get(signature_algs, Extensions, undefined)),
+ ServerSignAlgsCert = get_signature_scheme_list(
+ maps:get(signature_algs_cert, Extensions, undefined)),
+
+ {_PublicKeyAlgo, SignAlgo, SignHash} = get_certificate_params(Cert),
+
+ %% Check if server supports signature algorithm of client certificate
+ case check_cert_sign_algo(SignAlgo, SignHash, ServerSignAlgs, ServerSignAlgsCert) of
+ ok ->
+ {ok, {State#state{client_certificate_requested = true}, wait_cert}};
+ {error, _} ->
+ %% Certificate not supported: send empty certificate in state 'wait_finished'
+ {ok, {State#state{client_certificate_requested = true,
+ session = Session#session{own_certificate = undefined}}, wait_cert}}
+ end.
+
+
+process_certificate(#certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []},
+ #state{ssl_options =
+ #ssl_options{
+ fail_if_no_peer_cert = false}} = State) ->
{ok, {State, wait_finished}};
-process_client_certificate(#certificate_1_3{
- certificate_request_context = <<>>,
- certificate_list = []},
- #state{ssl_options =
- #ssl_options{
- fail_if_no_peer_cert = true}} = State0) ->
+process_certificate(#certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []},
+ #state{ssl_options =
+ #ssl_options{
+ fail_if_no_peer_cert = true}} = State0) ->
%% At this point the client believes that the connection is up and starts using
%% its traffic secrets. In order to be able send an proper Alert to the client
@@ -724,19 +1054,18 @@ process_client_certificate(#certificate_1_3{
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
{error, {certificate_required, State}};
-process_client_certificate(#certificate_1_3{certificate_list = Certs0},
- #state{ssl_options =
- #ssl_options{signature_algs = SignAlgs,
- signature_algs_cert = SignAlgsCert} = SslOptions,
- static_env =
- #static_env{
- role = Role,
- host = Host,
- cert_db = CertDbHandle,
- cert_db_ref = CertDbRef,
- crl_db = CRLDbHandle}} = State0) ->
+process_certificate(#certificate_1_3{certificate_list = Certs0},
+ #state{ssl_options =
+ #ssl_options{signature_algs = SignAlgs,
+ signature_algs_cert = SignAlgsCert} = SslOptions,
+ static_env =
+ #static_env{
+ role = Role,
+ host = Host,
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef,
+ crl_db = CRLDbHandle}} = State0) ->
%% TODO: handle extensions!
-
%% Remove extensions from list of certificates!
Certs = convert_certificate_chain(Certs0),
case is_supported_signature_algorithm(Certs, SignAlgs, SignAlgsCert) of
@@ -861,7 +1190,7 @@ message_hash(ClientHello1, HKDFAlgo) ->
crypto:hash(HKDFAlgo, ClientHello1)].
-calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare,
+calculate_handshake_secrets(PublicKey, PrivateKey, SelectedGroup,
#state{connection_states = ConnectionStates,
handshake_env =
#handshake_env{
@@ -874,13 +1203,13 @@ calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare,
%% Calculate handshake_secret
PSK = binary:copy(<<0>>, ssl_cipher:hash_size(HKDFAlgo)),
EarlySecret = tls_v1:key_schedule(early_secret, HKDFAlgo , {psk, PSK}),
- PrivateKey = get_server_private_key(KeyShare), %% #'ECPrivateKey'{}
- IKM = calculate_shared_secret(ClientKey, PrivateKey, SelectedGroup),
+ IKM = calculate_shared_secret(PublicKey, PrivateKey, SelectedGroup),
HandshakeSecret = tls_v1:key_schedule(handshake_secret, HKDFAlgo, IKM, EarlySecret),
%% Calculate [sender]_handshake_traffic_secret
{Messages, _} = HHistory,
+
ClientHSTrafficSecret =
tls_v1:client_handshake_traffic_secret(HKDFAlgo, HandshakeSecret, lists:reverse(Messages)),
ServerHSTrafficSecret =
@@ -899,10 +1228,13 @@ calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare,
ReadKey, ReadIV, ReadFinishedKey,
WriteKey, WriteIV, WriteFinishedKey).
-calculate_traffic_secrets(#state{connection_states = ConnectionStates,
- handshake_env =
- #handshake_env{
- tls_handshake_history = HHistory}} = State0) ->
+
+calculate_traffic_secrets(#state{
+ static_env = #static_env{role = Role},
+ connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = HHistory}} = State0) ->
#{security_parameters := SecParamsR} =
ssl_record:pending_connection_state(ConnectionStates, read),
#security_parameters{prf_algorithm = HKDFAlgo,
@@ -913,7 +1245,7 @@ calculate_traffic_secrets(#state{connection_states = ConnectionStates,
tls_v1:key_schedule(master_secret, HKDFAlgo, HandshakeSecret),
%% Get the correct list messages for the handshake context.
- Messages = get_handshake_context(HHistory),
+ Messages = get_handshake_context(Role, HHistory),
%% Calculate [sender]_application_traffic_secret_0
ClientAppTrafficSecret0 =
@@ -966,9 +1298,11 @@ calculate_shared_secret(OthersKey, MyKey = #'ECPrivateKey'{}, _Group)
public_key:compute_key(Point, MyKey).
-update_pending_connection_states(#state{connection_states =
- CS = #{pending_read := PendingRead0,
- pending_write := PendingWrite0}} = State,
+update_pending_connection_states(#state{
+ static_env = #static_env{role = server},
+ connection_states =
+ CS = #{pending_read := PendingRead0,
+ pending_write := PendingWrite0}} = State,
HandshakeSecret,
ReadKey, ReadIV, ReadFinishedKey,
WriteKey, WriteIV, WriteFinishedKey) ->
@@ -977,8 +1311,23 @@ update_pending_connection_states(#state{connection_states =
PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret,
WriteKey, WriteIV, WriteFinishedKey),
State#state{connection_states = CS#{pending_read => PendingRead,
+ pending_write => PendingWrite}};
+update_pending_connection_states(#state{
+ static_env = #static_env{role = client},
+ connection_states =
+ CS = #{pending_read := PendingRead0,
+ pending_write := PendingWrite0}} = State,
+ HandshakeSecret,
+ ReadKey, ReadIV, ReadFinishedKey,
+ WriteKey, WriteIV, WriteFinishedKey) ->
+ PendingRead = update_connection_state(PendingRead0, HandshakeSecret,
+ WriteKey, WriteIV, WriteFinishedKey),
+ PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret,
+ ReadKey, ReadIV, ReadFinishedKey),
+ State#state{connection_states = CS#{pending_read => PendingRead,
pending_write => PendingWrite}}.
+
update_connection_state(ConnectionState = #{security_parameters := SecurityParameters0},
HandshakeSecret, Key, IV, FinishedKey) ->
%% Store secret
@@ -1071,25 +1420,41 @@ get_handshake_context_cv({[<<15,_/binary>>|Messages], _}) ->
%%
%% Drop all client messages from the front of the iolist using the property that
%% incoming messages are binaries.
-get_handshake_context({Messages, _}) ->
- get_handshake_context(Messages);
-get_handshake_context([H|T]) when is_binary(H) ->
- get_handshake_context(T);
-get_handshake_context(L) ->
+get_handshake_context(server, {Messages, _}) ->
+ get_handshake_context_server(Messages);
+get_handshake_context(client, {Messages, _}) ->
+ get_handshake_context_client(Messages).
+
+get_handshake_context_server([H|T]) when is_binary(H) ->
+ get_handshake_context_server(T);
+get_handshake_context_server(L) ->
L.
+get_handshake_context_client([H|T]) when is_list(H) ->
+ get_handshake_context_client(T);
+get_handshake_context_client(L) ->
+ L.
+
+
+%% If the CertificateVerify message is sent by a server, the signature
+%% algorithm MUST be one offered in the client's "signature_algorithms"
+%% extension unless no valid certificate chain can be produced without
+%% unsupported algorithms
+%%
%% If sent by a client, the signature algorithm used in the signature
%% MUST be one of those present in the supported_signature_algorithms
%% field of the "signature_algorithms" extension in the
%% CertificateRequest message.
-verify_signature_algorithm(#state{ssl_options =
- #ssl_options{
- signature_algs = ServerSignAlgs}} = State0,
- #certificate_verify_1_3{algorithm = ClientSignAlg}) ->
- case lists:member(ClientSignAlg, ServerSignAlgs) of
+verify_signature_algorithm(#state{
+ static_env = #static_env{role = Role},
+ ssl_options =
+ #ssl_options{
+ signature_algs = LocalSignAlgs}} = State0,
+ #certificate_verify_1_3{algorithm = PeerSignAlg}) ->
+ case lists:member(PeerSignAlg, LocalSignAlgs) of
true ->
- ok;
+ {ok, maybe_update_selected_sign_alg(State0, PeerSignAlg, Role)};
false ->
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
@@ -1098,11 +1463,19 @@ verify_signature_algorithm(#state{ssl_options =
end.
-verify_certificate_verify(#state{connection_states = ConnectionStates,
- handshake_env =
- #handshake_env{
- public_key_info = PublicKeyInfo,
- tls_handshake_history = HHistory}} = State0,
+maybe_update_selected_sign_alg(#state{session = Session} = State, SignAlg, client) ->
+ State#state{session = Session#session{sign_alg = SignAlg}};
+maybe_update_selected_sign_alg(State, _, _) ->
+ State.
+
+
+verify_certificate_verify(#state{
+ static_env = #static_env{role = Role},
+ connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ public_key_info = PublicKeyInfo,
+ tls_handshake_history = HHistory}} = State0,
#certificate_verify_1_3{
algorithm = SignatureScheme,
signature = Signature}) ->
@@ -1122,10 +1495,11 @@ verify_certificate_verify(#state{connection_states = ConnectionStates,
PublicKey = get_public_key(PublicKeyInfo),
+ ContextString = peer_context_string(Role),
+
%% Digital signatures use the hash function defined by the selected signature
%% scheme.
- case verify(THash, <<"TLS 1.3, client CertificateVerify">>,
- HashAlgo, Signature, PublicKey) of
+ case verify(THash, ContextString, HashAlgo, Signature, PublicKey) of
{ok, true} ->
{ok, {State0, wait_finished}};
{ok, false} ->
@@ -1139,6 +1513,19 @@ verify_certificate_verify(#state{connection_states = ConnectionStates,
end.
+context_string(server) ->
+ <<"TLS 1.3, server CertificateVerify">>;
+context_string(client) ->
+ <<"TLS 1.3, client CertificateVerify">>.
+
+
+%% Return context string for verifing peer signature
+peer_context_string(server) ->
+ <<"TLS 1.3, client CertificateVerify">>;
+peer_context_string(client) ->
+ <<"TLS 1.3, server CertificateVerify">>.
+
+
%% If there is no overlap between the received
%% "supported_groups" and the groups supported by the server, then the
%% server MUST abort the handshake with a "handshake_failure" or an
@@ -1172,14 +1559,36 @@ select_common_groups(ServerGroups, ClientGroups) ->
%% for groups not listed in the client's "supported_groups" extension.
%% Servers MAY check for violations of these rules and abort the
%% handshake with an "illegal_parameter" alert if one is violated.
-validate_key_share(_ ,[]) ->
+validate_client_key_share(_ ,[]) ->
ok;
-validate_key_share([], _) ->
+validate_client_key_share([], _) ->
{error, illegal_parameter};
-validate_key_share([G|ClientGroups], [{_, G, _}|ClientShares]) ->
- validate_key_share(ClientGroups, ClientShares);
-validate_key_share([_|ClientGroups], [_|_] = ClientShares) ->
- validate_key_share(ClientGroups, ClientShares).
+validate_client_key_share([G|ClientGroups], [{_, G, _}|ClientShares]) ->
+ validate_client_key_share(ClientGroups, ClientShares);
+validate_client_key_share([_|ClientGroups], [_|_] = ClientShares) ->
+ validate_client_key_share(ClientGroups, ClientShares).
+
+
+%% Verify that selected group is offered by the client.
+validate_server_key_share([G|_ClientGroups], {_, G, _}) ->
+ ok;
+validate_server_key_share([_|ClientGroups], {_, _, _} = ServerKeyShare) ->
+ validate_server_key_share(ClientGroups, ServerKeyShare).
+
+
+validate_selected_group(SelectedGroup, [SelectedGroup|_]) ->
+ {error, {illegal_parameter,
+ "Selected group sent by the server shall not correspond to a group"
+ " which was provided in the key_share extension"}};
+validate_selected_group(SelectedGroup, ClientGroups) ->
+ case lists:member(SelectedGroup, ClientGroups) of
+ true ->
+ ok;
+ false ->
+ {error, {illegal_parameter,
+ "Selected group sent by the server shall correspond to a group"
+ " which was provided in the supported_groups extension"}}
+ end.
get_client_public_key([Group|_] = Groups, ClientShares) ->
@@ -1197,6 +1606,27 @@ get_client_public_key([Group|Groups], ClientShares, PreferredGroup) ->
get_client_public_key(Groups, ClientShares, PreferredGroup)
end.
+get_client_private_key([Group|_] = Groups, ClientShares) ->
+ get_client_private_key(Groups, ClientShares, Group).
+%%
+get_client_private_key(_, [], PreferredGroup) ->
+ {PreferredGroup, no_suitable_key};
+get_client_private_key([], _, PreferredGroup) ->
+ {PreferredGroup, no_suitable_key};
+get_client_private_key([Group|Groups], ClientShares, PreferredGroup) ->
+ case lists:keysearch(Group, 2, ClientShares) of
+ {value, {_, _, {_, ClientPrivateKey}}} ->
+ {Group, ClientPrivateKey};
+ {value, {_, _, #'ECPrivateKey'{} = ClientPrivateKey}} ->
+ {Group, ClientPrivateKey};
+ false ->
+ get_client_private_key(Groups, ClientShares, PreferredGroup)
+ end.
+
+
+get_server_public_key({key_share_entry, Group, PublicKey}) ->
+ {Group, PublicKey}.
+
%% get_client_public_key(Group, ClientShares) ->
%% case lists:keysearch(Group, 2, ClientShares) of
@@ -1223,6 +1653,19 @@ select_cipher_suite([Cipher|ClientCiphers], ServerCiphers) ->
select_cipher_suite(ClientCiphers, ServerCiphers)
end.
+
+%% RFC 8446 4.1.3 ServerHello
+%% A client which receives a cipher suite that was not offered MUST abort the
+%% handshake with an "illegal_parameter" alert.
+validate_cipher_suite(Cipher, ClientCiphers) ->
+ case lists:member(Cipher, ClientCiphers) of
+ true ->
+ ok;
+ false ->
+ {error, illegal_parameter}
+ end.
+
+
%% RFC 8446 (TLS 1.3)
%% TLS 1.3 provides two extensions for indicating which signature
%% algorithms may be used in digital signatures. The
@@ -1331,7 +1774,12 @@ get_supported_groups(#supported_groups{supported_groups = Groups}) ->
Groups.
get_key_shares(#key_share_client_hello{client_shares = ClientShares}) ->
- ClientShares.
+ ClientShares;
+get_key_shares(#key_share_server_hello{server_share = ServerShare}) ->
+ ServerShare.
+
+get_selected_group(#key_share_hello_retry_request{selected_group = SelectedGroup}) ->
+ SelectedGroup.
maybe() ->
Ref = erlang:make_ref(),
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 20d9f28512..8cb98e7fa6 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -249,16 +249,28 @@ tls13_test_group() ->
tls13_finished_verify_data,
tls13_1_RTT_handshake,
tls13_basic_ssl_server_openssl_client,
+ tls13_basic_ssl_server_ssl_client,
+ tls13_basic_openssl_server_ssl_client,
tls13_custom_groups_ssl_server_openssl_client,
+ tls13_custom_groups_ssl_server_ssl_client,
tls13_hello_retry_request_ssl_server_openssl_client,
+ tls13_hello_retry_request_ssl_server_ssl_client,
tls13_client_auth_empty_cert_alert_ssl_server_openssl_client,
+ tls13_client_auth_empty_cert_alert_ssl_server_ssl_client,
tls13_client_auth_empty_cert_ssl_server_openssl_client,
+ tls13_client_auth_empty_cert_ssl_server_ssl_client,
tls13_client_auth_ssl_server_openssl_client,
+ tls13_client_auth_ssl_server_ssl_client,
tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client,
+ tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client,
tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client,
+ tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client,
tls13_hrr_client_auth_ssl_server_openssl_client,
+ tls13_hrr_client_auth_ssl_server_ssl_client,
tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client,
+ tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client,
tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client,
+ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client,
tls13_connection_information].
%%--------------------------------------------------------------------
@@ -5327,6 +5339,80 @@ tls13_basic_ssl_server_openssl_client(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+tls13_basic_ssl_server_ssl_client() ->
+ [{doc,"Test TLS 1.3 basic connection between ssl server and ssl client"}].
+
+tls13_basic_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_basic_openssl_server_ssl_client() ->
+ [{doc,"Test TLS 1.3 basic connection between openssl server and ssl client"}].
+
+tls13_basic_openssl_server_ssl_client(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ "-tls1_3",
+ "-cert", CertFile, "-CAfile", CaCertFile,
+ "-key", KeyFile, "-Verify", "2"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, tls),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, ClientOpts}]),
+ true = port_command(OpensslPort, Data),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
+
tls13_custom_groups_ssl_server_openssl_client() ->
[{doc,"Test that ssl server can select a common group for key-exchange"}].
@@ -5351,6 +5437,39 @@ tls13_custom_groups_ssl_server_openssl_client(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+
+tls13_custom_groups_ssl_server_ssl_client() ->
+ [{doc,"Test that ssl server can select a common group for key-exchange"}].
+
+tls13_custom_groups_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0],
+ ClientOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ ClientOpts = [{supported_groups,[secp384r1, secp256r1, x25519]}|ClientOpts1],
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_hello_retry_request_ssl_server_openssl_client() ->
[{doc,"Test that ssl server can request a new group when the client's first key share"
"is not supported"}].
@@ -5376,6 +5495,38 @@ tls13_hello_retry_request_ssl_server_openssl_client(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+
+tls13_hello_retry_request_ssl_server_ssl_client() ->
+ [{doc,"Test that ssl server can request a new group when the client's first key share"
+ "is not supported"}].
+
+tls13_hello_retry_request_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
tls13_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
@@ -5408,6 +5559,45 @@ tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+
+tls13_client_auth_empty_cert_alert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+tls13_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server,
+ {error,
+ {tls_alert,
+ {certificate_required,
+ "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_client_auth_empty_cert_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
@@ -5437,13 +5627,47 @@ tls13_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_client_auth_empty_cert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
+
+tls13_client_auth_empty_cert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication."}].
tls13_client_auth_ssl_server_openssl_client(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
%% Set versions
ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
{verify, verify_peer},
@@ -5463,6 +5687,38 @@ tls13_client_auth_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication."}].
+
+tls13_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ %%Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
[{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
@@ -5498,6 +5754,46 @@ tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server,
+ {error,
+ {tls_alert,
+ {certificate_required,
+ "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client() ->
[{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
@@ -5529,6 +5825,42 @@ tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
+
+tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_hrr_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}].
@@ -5557,6 +5889,39 @@ tls13_hrr_client_auth_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_hrr_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}].
+
+tls13_hrr_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
@@ -5591,9 +5956,49 @@ tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
-%% Triggers Client Alert as openssl s_client does not have a certificate with a
+tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
+
+tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(
+ Server,
+ {error,
+ {tls_alert,
+ {insufficient_security,
+ "received SERVER ALERT: Fatal - Insufficient Security - "
+ "\"No suitable signature algorithm\""}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+%% Triggers a Server Alert as openssl s_client does not have a certificate with a
%% signature algorithm supported by the server (signature_algorithms_cert extension
%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% openssl s_client sends an empty certificate.
tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
@@ -5623,8 +6028,52 @@ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) -
Server,
{error,
{tls_alert,
- {illegal_parameter,
- "received CLIENT ALERT: Fatal - Illegal Parameter"}}}),
+ {certificate_required,
+ "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+%% Triggers a Server Alert as ssl client does not have a certificate with a
+%% signature algorithm supported by the server (signature_algorithms_cert extension
+%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% ssl client sends an empty certificate.
+tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
+
+tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {log_level, debug},
+ {verify, verify_peer},
+ {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(
+ Server,
+ {error,
+ {tls_alert,
+ {certificate_required,
+ "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).