Commit cc62cf3e authored by Martin Thomson's avatar Martin Thomson

Bug 1343036 - Early data size limit, r=franziskus,ekr

--HG--
extra : rebase_source : 534c4b9c7eb8e00d24b4a838000cc6a48c12a42b
extra : amend_source : 98c7feaa2b8e9f701385de9305884e37c652b22d
parent b990eae1
......@@ -33,15 +33,8 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd,
return SECFailure;
}
SECStatus rv = ssl3_InitState(ss);
if (rv != SECSuccess) {
return rv;
}
rv = ssl3_RestartHandshakeHashes(ss);
if (rv != SECSuccess) {
return rv;
}
ssl3_InitState(ss);
ssl3_RestartHandshakeHashes(ss);
// Ensure we don't overrun hs.client_random.
rnd_len = PR_MIN(SSL3_RANDOM_LENGTH, rnd_len);
......@@ -66,11 +59,11 @@ void SSLInt_ClearSessionTicketKey() { ssl_ResetSessionTicketKeys(); }
SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu) {
sslSocket *ss = ssl_FindSocket(fd);
if (ss) {
ss->ssl3.mtu = mtu;
return SECSuccess;
if (!ss) {
return SECFailure;
}
return SECFailure;
ss->ssl3.mtu = mtu;
return SECSuccess;
}
PRInt32 SSLInt_CountTls13CipherSpecs(PRFileDesc *fd) {
......@@ -194,7 +187,9 @@ SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len) {
if (ss->xtnData.nextProto.data) {
SECITEM_FreeItem(&ss->xtnData.nextProto, PR_FALSE);
}
if (!SECITEM_AllocItem(NULL, &ss->xtnData.nextProto, len)) return SECFailure;
if (!SECITEM_AllocItem(NULL, &ss->xtnData.nextProto, len)) {
return SECFailure;
}
PORT_Memcpy(ss->xtnData.nextProto.data, data, len);
return SECSuccess;
......@@ -251,6 +246,7 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
return SECFailure;
}
if (to >= (1ULL << 48)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_GetSpecWriteLock(ss);
......@@ -262,6 +258,7 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
* scrub the entire structure on the assumption that the new sequence number
* is far enough past the last received sequence number. */
if (to <= spec->recvdRecords.right + DTLS_RECVD_RECORDS_WINDOW) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
dtls_RecordSetRecvd(&spec->recvdRecords, to);
......@@ -279,6 +276,7 @@ SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) {
return SECFailure;
}
if (to >= (1ULL << 48)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_GetSpecWriteLock(ss);
......@@ -364,10 +362,36 @@ SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result) {
}
*result = ss->ssl3.hs.shortHeaders;
return SECSuccess;
}
void SSLInt_SetTicketLifetime(uint32_t lifetime) {
ssl_ticket_lifetime = lifetime;
}
void SSLInt_SetMaxEarlyDataSize(uint32_t size) {
ssl_max_early_data_size = size;
}
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
sslSocket *ss;
ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure;
}
/* This only works when resuming. */
if (!ss->statelessResume) {
PORT_SetError(SEC_INTERNAL_ONLY);
return SECFailure;
}
/* Modifying both specs allows this to be used on either peer. */
ssl_GetSpecWriteLock(ss);
ss->ssl3.crSpec->earlyDataRemaining = size;
ss->ssl3.cwSpec->earlyDataRemaining = size;
ssl_ReleaseSpecWriteLock(ss);
return SECSuccess;
}
......@@ -50,5 +50,7 @@ unsigned char *SSLInt_CipherSpecToIv(PRBool isServer, ssl3CipherSpec *spec);
SECStatus SSLInt_EnableShortHeaders(PRFileDesc *fd);
SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result);
void SSLInt_SetTicketLifetime(uint32_t lifetime);
void SSLInt_SetMaxEarlyDataSize(uint32_t size);
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
#endif // ndef libssl_internals_h_
......@@ -282,4 +282,110 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngradeEarlyData) {
}
}
static void CheckEarlyDataLimit(const std::shared_ptr<TlsAgent>& agent,
size_t expected_size) {
SSLPreliminaryChannelInfo preinfo;
SECStatus rv =
SSL_GetPreliminaryChannelInfo(agent->ssl_fd(), &preinfo, sizeof(preinfo));
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(expected_size, static_cast<size_t>(preinfo.maxEarlyDataSize));
}
TEST_P(TlsConnectTls13, SendTooMuchEarlyData) {
const char* big_message = "0123456789abcdef";
const size_t short_size = strlen(big_message) - 1;
const PRInt32 short_length = static_cast<PRInt32>(short_size);
SSLInt_SetMaxEarlyDataSize(static_cast<PRUint32>(short_size));
SetupForZeroRtt();
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
ExpectResumption(RESUME_TICKET);
client_->SetExpectedAlertSentCount(1);
server_->SetExpectedAlertReceivedCount(1);
client_->Handshake();
CheckEarlyDataLimit(client_, short_size);
PRInt32 sent;
// Writing more than the limit will succeed in TLS, but fail in DTLS.
if (mode_ == STREAM) {
sent = PR_Write(client_->ssl_fd(), big_message,
static_cast<PRInt32>(strlen(big_message)));
} else {
sent = PR_Write(client_->ssl_fd(), big_message,
static_cast<PRInt32>(strlen(big_message)));
EXPECT_GE(0, sent);
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
// Try an exact-sized write now.
sent = PR_Write(client_->ssl_fd(), big_message, short_length);
}
EXPECT_EQ(short_length, sent);
// Even a single octet write should now fail.
sent = PR_Write(client_->ssl_fd(), big_message, 1);
EXPECT_GE(0, sent);
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
// Process the ClientHello and read 0-RTT.
server_->Handshake();
CheckEarlyDataLimit(server_, short_size);
std::vector<uint8_t> buf(short_size + 1);
PRInt32 read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity());
EXPECT_EQ(short_length, read);
EXPECT_EQ(0, memcmp(big_message, buf.data(), short_size));
// Second read fails.
read = PR_Read(server_->ssl_fd(), buf.data(), buf.capacity());
EXPECT_EQ(SECFailure, read);
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
Handshake();
ExpectEarlyDataAccepted(true);
CheckConnected();
SendReceive();
}
TEST_P(TlsConnectTls13, ReceiveTooMuchEarlyData) {
const size_t limit = 5;
SSLInt_SetMaxEarlyDataSize(limit);
SetupForZeroRtt();
client_->Set0RttEnabled(true);
server_->Set0RttEnabled(true);
ExpectResumption(RESUME_TICKET);
client_->Handshake(); // Send ClientHello
CheckEarlyDataLimit(client_, limit);
// Lift the limit on the client.
EXPECT_EQ(SECSuccess,
SSLInt_SetSocketMaxEarlyDataSize(client_->ssl_fd(), 1000));
// Send message
const char* message = "0123456789abcdef";
const PRInt32 message_len = static_cast<PRInt32>(strlen(message));
EXPECT_EQ(message_len, PR_Write(client_->ssl_fd(), message, message_len));
server_->Handshake(); // Process ClientHello, send server flight.
server_->Handshake(); // Just to make sure that we don't read ahead.
CheckEarlyDataLimit(server_, limit);
// Attempt to read early data.
std::vector<uint8_t> buf(strlen(message) + 1);
EXPECT_GT(0, PR_Read(server_->ssl_fd(), buf.data(), buf.capacity()));
if (mode_ == STREAM) {
// This error isn't fatal for DTLS.
server_->CheckErrorCode(SSL_ERROR_TOO_MUCH_EARLY_DATA);
}
client_->Handshake(); // Process the handshake.
client_->Handshake(); // Process the alert.
if (mode_ == STREAM) {
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
}
} // namespace nss_test
......@@ -175,6 +175,7 @@ void TlsConnectTestBase::SetUp() {
SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
SSLInt_ClearSessionTicketKey();
SSLInt_SetTicketLifetime(30);
SSLInt_SetMaxEarlyDataSize(1024);
ClearStats();
Init();
}
......
......@@ -508,3 +508,6 @@ ER3(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 159),
ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160),
"SSL got a pre-TLS 1.3 version even though we sent early data.")
ER3(SSL_ERROR_TOO_MUCH_EARLY_DATA, (SSL_ERROR_BASE + 161),
"SSL received more early data than permitted.")
......@@ -2726,10 +2726,7 @@ ssl3_SendRecord(sslSocket *ss,
** trying to send an alert.
*/
PR_ASSERT(type == content_alert);
rv = ssl3_InitState(ss);
if (rv != SECSuccess) {
return SECFailure; /* ssl3_InitState has set the error code. */
}
ssl3_InitState(ss);
}
/* check for Token Presence */
......@@ -2935,6 +2932,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
ssl_GetXmitBufLock(ss);
}
toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH);
/*
* Note that the 0 epoch is OK because flags will never require
* its use, as guaranteed by the PORT_Assert above.
......@@ -4101,11 +4099,9 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
return SECSuccess;
}
SECStatus
void
ssl3_RestartHandshakeHashes(sslSocket *ss)
{
SECStatus rv = SECSuccess;
SSL_TRC(30, ("%d: SSL3[%d]: reset handshake hashes",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.hashType = handshake_hash_unknown;
......@@ -4118,7 +4114,6 @@ ssl3_RestartHandshakeHashes(sslSocket *ss)
PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
ss->ssl3.hs.sha = NULL;
}
return rv;
}
/*
......@@ -5024,15 +5019,8 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
if (ss->ssl3.hs.helloRetry) {
PORT_Assert(type == client_hello_retry);
} else {
rv = ssl3_InitState(ss);
if (rv != SECSuccess) {
return rv; /* ssl3_InitState has set the error code. */
}
rv = ssl3_RestartHandshakeHashes(ss);
if (rv != SECSuccess) {
return rv;
}
ssl3_InitState(ss);
ssl3_RestartHandshakeHashes(ss);
}
/* These must be reset every handshake. */
......@@ -9164,16 +9152,8 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length,
goto loser;
}
rv = ssl3_InitState(ss);
if (rv != SECSuccess) {
ssl_ReleaseSSL3HandshakeLock(ss);
return rv; /* ssl3_InitState has set the error code. */
}
rv = ssl3_RestartHandshakeHashes(ss);
if (rv != SECSuccess) {
ssl_ReleaseSSL3HandshakeLock(ss);
return rv;
}
ssl3_InitState(ss);
ssl3_RestartHandshakeHashes(ss);
if (ss->ssl3.hs.ws != wait_client_hello) {
desc = unexpected_message;
......@@ -11795,10 +11775,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
/* Start new handshake hashes when we start a new handshake. Unless this is
* TLS 1.3 and we sent a HelloRetryRequest. */
if (ss->ssl3.hs.msg_type == client_hello && !ss->ssl3.hs.helloRetry) {
rv = ssl3_RestartHandshakeHashes(ss);
if (rv != SECSuccess) {
return rv;
}
ssl3_RestartHandshakeHashes(ss);
}
/* We should not include hello_request and hello_verify_request messages
* in the handshake hashes */
......@@ -12590,11 +12567,8 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
if (!ss->ssl3.initialized) {
ssl_GetSSL3HandshakeLock(ss);
rv = ssl3_InitState(ss);
ssl3_InitState(ss);
ssl_ReleaseSSL3HandshakeLock(ss);
if (rv != SECSuccess) {
return rv; /* ssl3_InitState has set the error code. */
}
}
/* check for Token Presence */
......@@ -12913,16 +12887,14 @@ ssl3_InitCipherSpec(ssl3CipherSpec *spec)
** ssl3_HandleRecord()
**
** This function should perhaps acquire and release the SpecWriteLock.
**
**
*/
SECStatus
void
ssl3_InitState(sslSocket *ss)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->ssl3.initialized)
return SECSuccess; /* Function should be idempotent */
return; /* Function should be idempotent */
ss->ssl3.policy = SSL_ALLOWED;
......@@ -12977,7 +12949,6 @@ ssl3_InitState(sslSocket *ss)
ssl_FilterSupportedGroups(ss);
ss->ssl3.initialized = PR_TRUE;
return SECSuccess;
}
/* record the export policy for this cipher suite */
......
......@@ -878,7 +878,7 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
#define TLS_EX_SESS_TICKET_VERSION (0x0103)
#define TLS_EX_SESS_TICKET_VERSION (0x0104)
/*
* Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
......@@ -1003,7 +1003,8 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
+ 1 /* extendedMasterSecretUsed */
+ sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */
+ sizeof(ticket->flags) /* ticket flags */
+ 1 + alpnSelection.len; /* npn value + length field. */
+ 1 + alpnSelection.len /* npn value + length field. */
+ 4; /* maxEarlyData */
#ifdef UNSAFE_FUZZER_MODE
padding_length = 0;
#else
......@@ -1152,6 +1153,10 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
goto loser;
}
rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4);
if (rv != SECSuccess)
goto loser;
PORT_Assert(plaintext.len == padding_length);
for (i = 0; i < padding_length; i++)
plaintext.data[i] = (unsigned char)padding_length;
......@@ -1608,6 +1613,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
goto no_ticket;
}
rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &buffer_len);
if (rv != SECSuccess) {
goto no_ticket;
}
parsed_session_ticket->maxEarlyData = temp;
#ifndef UNSAFE_FUZZER_MODE
/* Done parsing. Check that all bytes have been consumed. */
if (buffer_len != padding_length) {
......@@ -1642,6 +1653,8 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
&extension_data) != SECSuccess)
goto no_ticket;
sid->u.ssl3.locked.sessionTicket.flags = parsed_session_ticket->flags;
sid->u.ssl3.locked.sessionTicket.max_early_data_size =
parsed_session_ticket->maxEarlyData;
if (parsed_session_ticket->ms_length >
sizeof(sid->u.ssl3.keys.wrapped_master_secret))
......
......@@ -245,6 +245,7 @@ typedef enum {
SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 158),
SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 159),
SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA = (SSL_ERROR_BASE + 160),
SSL_ERROR_TOO_MUCH_EARLY_DATA = (SSL_ERROR_BASE + 161),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
......
......@@ -504,6 +504,9 @@ struct ssl3CipherSpecStr {
SECItem msItem;
DTLSEpoch epoch;
DTLSRecvdRecords recvdRecords;
/* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
* will be zero for everything but 0-RTT. */
PRUint32 earlyDataRemaining;
PRUint8 refCt;
const char *phase;
......@@ -1013,6 +1016,7 @@ typedef struct SessionTicketStr {
PRUint32 flags;
SECItem srvName; /* negotiated server name */
SECItem alpnSelection;
PRUint32 maxEarlyData;
} SessionTicket;
/*
......@@ -1231,6 +1235,7 @@ extern FILE *ssl_trace_iob;
extern FILE *ssl_keylog_iob;
extern PRUint32 ssl3_sid_timeout;
extern PRUint32 ssl_ticket_lifetime;
extern PRUint32 ssl_max_early_data_size;
extern const char *const ssl3_cipherName[];
......@@ -1350,8 +1355,8 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
extern SECStatus ssl3_ConstrainRangeByPolicy(void);
extern SECStatus ssl3_InitState(sslSocket *ss);
extern SECStatus ssl3_RestartHandshakeHashes(sslSocket *ss);
extern void ssl3_InitState(sslSocket *ss);
extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
const unsigned char *b,
unsigned int l);
......
......@@ -141,8 +141,19 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
inf.protocolVersion = ss->version;
inf.cipherSuite = ss->ssl3.hs.cipher_suite;
inf.canSendEarlyData = !ss->sec.isServer &&
(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) &&
!ss->firstHsDone;
(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted);
/* We shouldn't be able to send early data if the handshake is done. */
PORT_Assert(!ss->firstHsDone || !inf.canSendEarlyData);
if (ss->sec.ci.sid &&
(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) {
inf.maxEarlyDataSize =
ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
} else {
inf.maxEarlyDataSize = 0;
}
memcpy(info, &inf, inf.length);
return SECSuccess;
......
......@@ -884,6 +884,7 @@ int
ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
{
int rv = 0;
PRBool zeroRtt = PR_FALSE;
SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes",
SSL_GETPID(), ss->fd, len));
......@@ -923,19 +924,20 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
* Case 2: TLS 1.3 0-RTT
*/
if (!ss->firstHsDone) {
PRBool falseStart = PR_FALSE;
PRBool allowEarlySend = PR_FALSE;
ssl_Get1stHandshakeLock(ss);
if (ss->opt.enableFalseStart ||
(ss->opt.enable0RttData && !ss->sec.isServer)) {
ssl_GetSSL3HandshakeLock(ss);
/* The client can sometimes send before the handshake is fully
* complete. In TLS 1.2: false start; in TLS 1.3: 0-RTT. */
falseStart = ss->ssl3.hs.canFalseStart ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
zeroRtt = ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
allowEarlySend = ss->ssl3.hs.canFalseStart || zeroRtt;
ssl_ReleaseSSL3HandshakeLock(ss);
}
if (!falseStart && ss->handshake) {
if (!allowEarlySend && ss->handshake) {
rv = ssl_Do1stHandshake(ss);
}
ssl_Release1stHandshakeLock(ss);
......@@ -945,6 +947,20 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
goto done;
}
if (zeroRtt) {
/* There's a limit to the number of early data octets we can send.
*
* Note that taking this lock doesn't prevent the cipher specs from
* being changed out between here and when records are ultimately
* encrypted. The only effect of that is to occasionally do an
* unnecessary short write when data is identified as 0-RTT here but
* 1-RTT later.
*/
ssl_GetSpecReadLock(ss);
len = tls13_LimitEarlyData(ss, content_application_data, len);
ssl_ReleaseSpecReadLock(ss);
}
/* Check for zero length writes after we do housekeeping so we make forward
* progress.
*/
......@@ -959,19 +975,6 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
goto done;
}
if (!ss->firstHsDone) {
#ifdef DEBUG
ssl_GetSSL3HandshakeLock(ss);
PORT_Assert(!ss->sec.isServer &&
(ss->ssl3.hs.canFalseStart ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted));
ssl_ReleaseSSL3HandshakeLock(ss);
#endif
SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start",
SSL_GETPID(), ss->fd));
}
ssl_GetXmitBufLock(ss);
rv = ssl3_SendApplicationData(ss, buf, len, flags);
ssl_ReleaseXmitBufLock(ss);
......
......@@ -304,6 +304,15 @@ typedef struct SSLPreliminaryChannelInfoStr {
*/
PRBool canSendEarlyData;
/* The following fields were added in NSS 3.31. */
/* The number of early data octets that a client is permitted to send on
* this connection. The value will be zero if the connection was not
* resumed or early data is not permitted. For a client, this value only
* has meaning if |canSendEarlyData| is true. For a server, this indicates
* the value that was advertised in the session ticket that was used to
* resume this session. */
PRUint32 maxEarlyDataSize;
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLPreliminaryChannelInfo;
......
......@@ -2769,6 +2769,11 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
dtls_InitRecvdRecords(&spec->recvdRecords);
}
if (type == TrafficKeyEarlyApplicationData) {
spec->earlyDataRemaining =
ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
}
/* Now that we've set almost everything up, finally cut over. */
ssl_GetSpecWriteLock(ss);
tls13_CipherSpecRelease(*specp); /* May delete old cipher. */
......@@ -3775,7 +3780,7 @@ tls13_SendClientSecondRound(sslSocket *ss)
* } NewSessionTicket;
*/
#define MAX_EARLY_DATA_SIZE (2 << 16) /* Arbitrary limit. */
PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */
SECStatus
tls13_SendNewSessionTicket(sslSocket *ss)
......@@ -3845,7 +3850,7 @@ tls13_SendNewSessionTicket(sslSocket *ss)
if (rv != SECSuccess)
goto loser;
rv = ssl3_AppendHandshakeNumber(ss, MAX_EARLY_DATA_SIZE, 4);
rv = ssl3_AppendHandshakeNumber(ss, ssl_max_early_data_size, 4);
if (rv != SECSuccess)
goto loser;
}
......@@ -4089,6 +4094,28 @@ tls13_FormatAdditionalData(PRUint8 *aad, unsigned int length,
PORT_Assert((ptr - aad) == length);
}
PRInt32
tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend)
{
PRInt32 reduced;
PORT_Assert(type == content_application_data);
PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
PORT_Assert(!ss->firstHsDone);
if (ss->ssl3.cwSpec->epoch != TrafficKeyEarlyApplicationData) {
return toSend;
}
if (IS_DTLS(ss) && toSend > ss->ssl3.cwSpec->earlyDataRemaining) {
/* Don't split application data records in DTLS. */
return 0;
}
reduced = PR_MIN(toSend, ss->ssl3.cwSpec->earlyDataRemaining);
ss->ssl3.cwSpec->earlyDataRemaining -= reduced;
return reduced;
}
SECStatus
tls13_ProtectRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec,
......@@ -4240,6 +4267,17 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext
cText->type = plaintext->buf[plaintext->len - 1];
--plaintext->len;
/* Check that we haven't received too much 0-RTT data. */
if (crSpec->epoch == TrafficKeyEarlyApplicationData &&
cText->type == content_application_data) {
if (plaintext->len > crSpec->earlyDataRemaining) {
*alert = unexpected_message;
PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA);
return SECFailure;
}
crSpec->earlyDataRemaining -= plaintext->len;
}
SSL_TRC(10,
("%d: TLS13[%d]: %s received record of length=%d type=%d",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
......
......@@ -45,6 +45,7 @@ void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
SSL3AlertDescription desc);
SECStatus tls13_SetupClientHello(sslSocket *ss);
SECStatus tls13_MaybeDo0RTTHandshake(sslSocket *ss);
PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend);
PRBool tls13_AllowPskCipher(const sslSocket *ss,
const ssl3CipherSuiteDef *cipher_def);
PRBool tls13_PskSuiteEnabled(sslSocket *ss);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment