*Jakub Zelenka*
+ * Fixed TLS 1.3 servers to reject early data when the selected ciphersuite
+ differs from the ciphersuite associated with the selected PSK. Same-hash
+ PSK resumption can still continue without accepting 0-RTT data.
+
+ *Mounir IDRASSI*
+
* Added support for Ed25519 and Ed448 certificates in DTLS 1.2. Previously,
these certificate types were only supported in TLS 1.2 and TLS 1.3.
/*
* Check if this share is in supported_groups sent from client
- * RFC 8446 also mandates that clients send keyshares in the same
+ * RFC 9846 also mandates that clients send keyshares in the same
* order as listed in the supported groups extension, but its not
* required that the server check that, and some clients violate this
* so instead of failing the connection when that occurs, log a trace
}
if (key_share_pos < previous_key_share_pos)
- OSSL_TRACE1(TLS, "key share group id %d is out of RFC 8446 order\n", group_id);
+ OSSL_TRACE1(TLS, "key share group id %d is out of RFC 9846 order\n", group_id);
previous_key_share_pos = key_share_pos;
s->ext.ticket_expected = 1;
continue;
}
+ /*
+ * Same-hash ciphersuite changes are allowed for TLSv1.3 PSK
+ * resumption, but RFC 9846 Section 4.3.10 requires the selected
+ * ciphersuite to match the selected PSK before accepting early data.
+ */
+ if (sess->cipher->id != s->s3.tmp.new_cipher->id)
+ s->ext.early_data_ok = 0;
break;
}
}
/*
* decrypt_error here to keep the alert the same as if the binder
- * failed. See RFC8446 Appendix E.6. Note we make no attempt to do this
+ * failed. See RFC9846 Appendix F.6. Note we make no attempt to do this
* in constant time compared to verifying the binder. None of this code
* is constant time anyway.
*/
PACKET extpkt;
/*
- * Fulfilling RFC8446:4.6.1 requirement: Clients MUST NOT cache
+ * Fulfilling RFC9846:4.7.1 requirement: Clients MUST NOT cache
* tickets for longer than 7 days.
*/
if (ticket_lifetime_hint > 604800) {
* ----------------------------
* TLS 1.3 Certificate message:
* ----------------------------
- * https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2
+ * https://datatracker.ietf.org/doc/html/rfc9846#section-4.5.1
*
* enum {
* X509(0),
/*
* Prior to TLSv1.3 sig algs allowed any curve to be used. TLSv1.3 is
* more restrictive so check that our sig algs are consistent with this
- * EC cert. See section 4.2.3 of RFC8446.
+ * EC cert. See section 4.3.3 of RFC9846.
*/
curve = ssl_get_EC_curve_nid(s->cert->pkeys[SSL_PKEY_ECC].privatekey);
if (tls_check_sigalg_curve(s, curve))
#define KEY_UPDATE_MAX_LENGTH 1
#define CCS_MAX_LENGTH 1
-/* Max ServerHello size permitted by RFC 8446 */
+/* Max ServerHello size permitted by RFC 9846 */
#define SERVER_HELLO_MAX_LENGTH 65607
-/* Max CertificateVerify size permitted by RFC 8446 */
+/* Max CertificateVerify size permitted by RFC 9846 */
#define CERTIFICATE_VERIFY_MAX_LENGTH 65539
/* Max should actually be 36 but we are generous */
* parameters such as new_session_count = 0 or resumption_count = 0, is
* effectively signaling no interest in session tickets or resumption.
*
- * RFC 8446 section 4.2.9: Servers MUST NOT select a key exchange mode
+ * RFC 9846 section 4.3.9: Servers MUST NOT select a key exchange mode
* that is not listed by the client. This extension also restricts the
* modes for use with PSK resumption. Servers SHOULD NOT send
* NewSessionTicket with tickets that are not compatible with the
/*
* Ticket lifetime hint:
* In TLSv1.3 we reset the "time" field above, and always specify the
- * timeout, limited to a 1 week period per RFC8446.
+ * timeout, limited to a 1 week period per RFC9846.
* For TLSv1.2 this is advisory only and we leave this unspecified for
* resumed session (for simplicity).
*/
size_t sigalgslen;
/*-
- * RFC 8446, section 4.2.3:
+ * RFC 9846, section 4.3.3:
*
* The signatures on certificates that are self-signed or certificates
* that are trust anchors are not validated, since they begin a
return testresult;
}
+/*
+ * Locks in the requirement that a resumed PSK's exact ciphersuite, not
+ * merely a shared digest, must match the negotiated one before 0-RTT data
+ * is accepted: the client encrypts its early data with the AEAD bound to
+ * its own PSK session before it can know what cipher the server will
+ * negotiate, so a same-digest-but-different-cipher negotiation must fall
+ * back to an ordinary connection rather than attempt decryption with the
+ * wrong cipher.
+ */
+static int test_early_data_psk_cipher_mismatch(void)
+{
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess = NULL;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ if (is_fips) {
+ testresult = TEST_skip("CHACHA is not supported in FIPS");
+ return 1;
+ }
+
+ if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl,
+ &serverssl, &sess, 2, SHA256_DIGEST_LENGTH)))
+ goto end;
+
+ /*
+ * The PSK is bound to AES-128-GCM (SHA256 digest), but both ends can
+ * only negotiate ChaCha20-Poly1305 -- same digest, different cipher.
+ */
+ if (!TEST_true(SSL_set_ciphersuites(clientssl,
+ "TLS_CHACHA20_POLY1305_SHA256"))
+ || !TEST_true(SSL_set_ciphersuites(serverssl,
+ "TLS_CHACHA20_POLY1305_SHA256")))
+ goto end;
+
+ SSL_set_connect_state(clientssl);
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &written)))
+ goto end;
+
+ if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_FINISH)
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_REJECTED))
+ goto end;
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ testresult = 1;
+end:
+ SSL_SESSION_free(sess);
+ SSL_SESSION_free(clientpsk);
+ SSL_SESSION_free(serverpsk);
+ clientpsk = serverpsk = NULL;
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ return testresult;
+#else
+ return 1;
+#endif
+}
+
/*
* Test that a server that doesn't try to read early data can handle a
* client sending some.
ADD_ALL_TESTS(test_early_data_not_sent, 3);
ADD_ALL_TESTS(test_early_data_psk, 8);
ADD_ALL_TESTS(test_early_data_psk_with_all_ciphers, 7);
+ ADD_TEST(test_early_data_psk_cipher_mismatch);
ADD_ALL_TESTS(test_early_data_not_expected, 3);
#ifndef OPENSSL_NO_TLS1_2
ADD_ALL_TESTS(test_early_data_tls1_2, 3);