summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/tls13con.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/tls13con.c')
-rw-r--r--security/nss/lib/ssl/tls13con.c262
1 files changed, 190 insertions, 72 deletions
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index c06acc83a..4d9170fb0 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -792,7 +792,7 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
/* Only send an update if we have sent with the current spec. This
* prevents us from being forced to crank forward pointlessly. */
ssl_GetSpecReadLock(ss);
- sendUpdate = ss->ssl3.cwSpec->seqNum > 0;
+ sendUpdate = ss->ssl3.cwSpec->nextSeqNum > 0;
ssl_ReleaseSpecReadLock(ss);
} else {
sendUpdate = PR_TRUE;
@@ -1620,7 +1620,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
ssl_GetSpecWriteLock(ss);
/* Increase the write sequence number. The read sequence number
* will be reset after this to early data or handshake. */
- ss->ssl3.cwSpec->seqNum = 1;
+ ss->ssl3.cwSpec->nextSeqNum = 1;
ssl_ReleaseSpecWriteLock(ss);
}
@@ -2007,7 +2007,7 @@ tls13_SendHelloRetryRequest(sslSocket *ss,
/* We depend on this being exactly one record and one message. */
PORT_Assert(!IS_DTLS(ss) || (ss->ssl3.hs.sendMessageSeq == 1 &&
- ss->ssl3.cwSpec->seqNum == 1));
+ ss->ssl3.cwSpec->nextSeqNum == 1));
ssl_ReleaseXmitBufLock(ss);
ss->ssl3.hs.helloRetry = PR_TRUE;
@@ -2209,6 +2209,8 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
} else {
PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none);
}
+ /* Set the spec version, because we want to send CH now with 0303 */
+ tls13_SetSpecRecordVersion(ss, ss->ssl3.cwSpec);
/* Extensions must contain more than just supported_versions. This will
* ensure that a HelloRetryRequest isn't a no-op: we must have at least two
@@ -2248,6 +2250,7 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
goto loser;
}
}
+
rv = ssl3_SendClientHello(ss, client_hello_retry);
if (rv != SECSuccess) {
goto loser;
@@ -3251,6 +3254,17 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
}
tls13_SetSpecRecordVersion(ss, spec);
+
+ /* The record size limit is reduced by one so that the remainder of the
+ * record handling code can use the same checks for all versions. */
+ if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
+ spec->recordSizeLimit = ((spec->direction == CipherSpecRead)
+ ? ss->opt.recordSizeLimit
+ : ss->xtnData.recordSizeLimit) -
+ 1;
+ } else {
+ spec->recordSizeLimit = MAX_FRAGMENT_LENGTH;
+ }
return SECSuccess;
}
@@ -3316,7 +3330,7 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
return SECFailure;
}
spec->epoch = epoch;
- spec->seqNum = 0;
+ spec->nextSeqNum = 0;
if (IS_DTLS(ss)) {
dtls_InitRecvdRecords(&spec->recvdRecords);
}
@@ -3536,14 +3550,15 @@ tls13_AESGCM(ssl3KeyMaterial *keys,
CK_GCM_PARAMS gcmParams;
unsigned char nonce[12];
+ PORT_Assert(additionalDataLen > 8);
memset(&gcmParams, 0, sizeof(gcmParams));
gcmParams.pIv = nonce;
gcmParams.ulIvLen = sizeof(nonce);
- gcmParams.pAAD = NULL;
- gcmParams.ulAADLen = 0;
+ gcmParams.pAAD = (PRUint8 *)(additionalData + 8);
+ gcmParams.ulAADLen = additionalDataLen - 8;
gcmParams.ulTagBits = 128; /* GCM measures tag length in bits. */
- tls13_WriteNonce(keys, additionalData, additionalDataLen,
+ tls13_WriteNonce(keys, additionalData, 8,
nonce, sizeof(nonce));
return tls13_AEAD(keys, doDecrypt, out, outlen, maxout, in, inlen,
CKM_AES_GCM,
@@ -3560,14 +3575,15 @@ tls13_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
CK_NSS_AEAD_PARAMS aeadParams;
unsigned char nonce[12];
+ PORT_Assert(additionalDataLen > 8);
memset(&aeadParams, 0, sizeof(aeadParams));
aeadParams.pNonce = nonce;
aeadParams.ulNonceLen = sizeof(nonce);
- aeadParams.pAAD = NULL; /* No AAD in TLS 1.3. */
- aeadParams.ulAADLen = 0;
+ aeadParams.pAAD = (PRUint8 *)(additionalData + 8);
+ aeadParams.ulAADLen = additionalDataLen - 8;
aeadParams.ulTagLen = 16; /* The Poly1305 tag is 16 octets. */
- tls13_WriteNonce(keys, additionalData, additionalDataLen,
+ tls13_WriteNonce(keys, additionalData, 8,
nonce, sizeof(nonce));
return tls13_AEAD(keys, doDecrypt, out, outlen, maxout, in, inlen,
CKM_NSS_CHACHA20_POLY1305,
@@ -3579,7 +3595,7 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
SECStatus rv;
PRUint32 innerLength;
- SECItem oldNpn = { siBuffer, NULL, 0 };
+ SECItem oldAlpn = { siBuffer, NULL, 0 };
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -3603,11 +3619,11 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
- /* If we are doing 0-RTT, then we already have an NPN value. Stash
+ /* If we are doing 0-RTT, then we already have an ALPN value. Stash
* it for comparison. */
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent &&
ss->xtnData.nextProtoState == SSL_NEXT_PROTO_EARLY_VALUE) {
- oldNpn = ss->xtnData.nextProto;
+ oldAlpn = ss->xtnData.nextProto;
ss->xtnData.nextProto.data = NULL;
ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT;
}
@@ -3627,8 +3643,8 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
/* Check that the server negotiated the same ALPN (if any). */
- if (SECITEM_CompareItem(&oldNpn, &ss->xtnData.nextProto)) {
- SECITEM_FreeItem(&oldNpn, PR_FALSE);
+ if (SECITEM_CompareItem(&oldAlpn, &ss->xtnData.nextProto)) {
+ SECITEM_FreeItem(&oldAlpn, PR_FALSE);
FATAL_ERROR(ss, SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID,
illegal_parameter);
return SECFailure;
@@ -3650,7 +3666,7 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored));
}
- SECITEM_FreeItem(&oldNpn, PR_FALSE);
+ SECITEM_FreeItem(&oldAlpn, PR_FALSE);
if (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk) {
TLS13_SET_HS_STATE(ss, wait_finished);
} else {
@@ -3815,13 +3831,14 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
if (rv != SECSuccess) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, illegal_parameter);
return SECFailure;
}
rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, ss->sec.peerCert);
if (rv != SECSuccess) {
/* Error set already */
+ FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
@@ -4740,7 +4757,8 @@ static const struct {
{ ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
{ ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
{ ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
- hello_retry_request) }
+ hello_retry_request) },
+ { ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) }
};
tls13ExtensionStatus
@@ -4780,19 +4798,20 @@ tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message)
#undef _M2
#undef _M3
-/* TLS 1.3 doesn't actually have additional data but the aead function
- * signature overloads additional data to carry the record sequence
- * number and that's what we put here. The TLS 1.3 AEAD functions
- * just use this input as the sequence number and not as additional
- * data. */
+/* We cheat a bit on additional data because the AEAD interface
+ * which doesn't have room for the record number. The AAD we
+ * format is serialized record number followed by the true AD
+ * (i.e., the record header) plus the serialized record number. */
static SECStatus
-tls13_FormatAdditionalData(sslSocket *ss, PRUint8 *aad, unsigned int length,
- DTLSEpoch epoch, sslSequenceNumber seqNum)
+tls13_FormatAdditionalData(
+ sslSocket *ss,
+ const PRUint8 *header, unsigned int headerLen,
+ DTLSEpoch epoch, sslSequenceNumber seqNum,
+ PRUint8 *aad, unsigned int *aadLength, unsigned int maxLength)
{
SECStatus rv;
- sslBuffer buf = SSL_BUFFER_FIXED(aad, length);
+ sslBuffer buf = SSL_BUFFER_FIXED(aad, maxLength);
- PORT_Assert(length == 8);
if (IS_DTLS(ss)) {
rv = sslBuffer_AppendNumber(&buf, epoch, 2);
if (rv != SECSuccess) {
@@ -4803,6 +4822,14 @@ tls13_FormatAdditionalData(sslSocket *ss, PRUint8 *aad, unsigned int length,
if (rv != SECSuccess) {
return SECFailure;
}
+
+ rv = sslBuffer_Append(&buf, header, headerLen);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ *aadLength = buf.len;
+
return SECSuccess;
}
@@ -4843,43 +4870,68 @@ tls13_ProtectRecord(sslSocket *ss,
PORT_Assert(cwSpec->direction == CipherSpecWrite);
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) protect 0x%0llx len=%u",
SSL_GETPID(), ss->fd, cwSpec, cwSpec->epoch, cwSpec->phase,
- cwSpec->seqNum, contentLen));
+ cwSpec->nextSeqNum, contentLen));
- if (contentLen + 1 + tagLen > wrBuf->space) {
+ if (contentLen + 1 + tagLen > SSL_BUFFER_SPACE(wrBuf)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* Copy the data into the wrBuf. We're going to encrypt in-place
* in the AEAD branch anyway */
- PORT_Memcpy(wrBuf->buf, pIn, contentLen);
+ PORT_Memcpy(SSL_BUFFER_NEXT(wrBuf), pIn, contentLen);
if (cipher_def->calg == ssl_calg_null) {
/* Shortcut for plaintext */
- wrBuf->len = contentLen;
+ rv = sslBuffer_Skip(wrBuf, contentLen, NULL);
+ PORT_Assert(rv == SECSuccess);
} else {
- PRUint8 aad[8];
+ PRUint8 hdr[13];
+ sslBuffer buf = SSL_BUFFER_FIXED(hdr, sizeof(hdr));
+ PRBool needsLength;
+ PRUint8 aad[21];
+ unsigned int aadLen;
+ int len;
+
PORT_Assert(cipher_def->type == type_aead);
/* Add the content type at the end. */
- wrBuf->buf[contentLen] = type;
+ *(SSL_BUFFER_NEXT(wrBuf) + contentLen) = type;
- rv = tls13_FormatAdditionalData(ss, aad, sizeof(aad), cwSpec->epoch,
- cwSpec->seqNum);
+ /* Create the header (ugly that we have to do it twice). */
+ rv = ssl_InsertRecordHeader(ss, cwSpec, content_application_data,
+ &buf, &needsLength);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (needsLength) {
+ rv = sslBuffer_AppendNumber(&buf, contentLen + 1 +
+ cwSpec->cipherDef->tag_size,
+ 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ rv = tls13_FormatAdditionalData(ss, SSL_BUFFER_BASE(&buf), SSL_BUFFER_LEN(&buf),
+ cwSpec->epoch, cwSpec->nextSeqNum,
+ aad, &aadLen, sizeof(aad));
if (rv != SECSuccess) {
return SECFailure;
}
rv = cwSpec->aead(&cwSpec->keyMaterial,
- PR_FALSE, /* do encrypt */
- wrBuf->buf, /* output */
- (int *)&wrBuf->len, /* out len */
- wrBuf->space, /* max out */
- wrBuf->buf, contentLen + 1, /* input */
- aad, sizeof(aad));
+ PR_FALSE, /* do encrypt */
+ SSL_BUFFER_NEXT(wrBuf), /* output */
+ &len, /* out len */
+ SSL_BUFFER_SPACE(wrBuf), /* max out */
+ SSL_BUFFER_NEXT(wrBuf), /* input */
+ contentLen + 1, /* input len */
+ aad, aadLen);
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
+ rv = sslBuffer_Skip(wrBuf, len, NULL);
+ PORT_Assert(rv == SECSuccess);
}
return SECSuccess;
@@ -4897,25 +4949,22 @@ tls13_ProtectRecord(sslSocket *ss,
SECStatus
tls13_UnprotectRecord(sslSocket *ss,
ssl3CipherSpec *spec,
- SSL3Ciphertext *cText, sslBuffer *plaintext,
+ SSL3Ciphertext *cText,
+ sslBuffer *plaintext,
+ SSL3ContentType *innerType,
SSL3AlertDescription *alert)
{
const ssl3BulkCipherDef *cipher_def = spec->cipherDef;
- sslSequenceNumber seqNum;
- PRUint8 aad[8];
+ PRUint8 aad[21];
+ unsigned int aadLen;
SECStatus rv;
*alert = bad_record_mac; /* Default alert for most issues. */
PORT_Assert(spec->direction == CipherSpecRead);
- if (IS_DTLS(ss)) {
- seqNum = cText->seq_num & RECORD_SEQ_MASK;
- } else {
- seqNum = spec->seqNum;
- }
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) unprotect 0x%0llx len=%u",
- SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase, seqNum,
- cText->buf->len));
+ SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase,
+ cText->seqNum, cText->buf->len));
/* We can perform this test in variable time because the record's total
* length and the ciphersuite are both public knowledge. */
@@ -4927,28 +4976,38 @@ tls13_UnprotectRecord(sslSocket *ss,
return SECFailure;
}
- /* Verify that the content type is right, even though we overwrite it. */
- if (cText->type != content_application_data) {
+ /* Verify that the content type is right, even though we overwrite it.
+ * Also allow the DTLS short header in TLS 1.3. */
+ if (!(cText->hdr[0] == content_application_data ||
+ (IS_DTLS(ss) &&
+ ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ (cText->hdr[0] & 0xe0) == 0x20))) {
SSL_TRC(3,
- ("%d: TLS13[%d]: record has invalid exterior content type=%d",
- SSL_GETPID(), ss->fd, cText->type));
+ ("%d: TLS13[%d]: record has invalid exterior type=%2.2x",
+ SSL_GETPID(), ss->fd, cText->hdr[0]));
/* Do we need a better error here? */
PORT_SetError(SSL_ERROR_BAD_MAC_READ);
return SECFailure;
}
- /* Check the version number in the record. */
- if (cText->version != spec->recordVersion) {
- /* Do we need a better error here? */
- SSL_TRC(3,
- ("%d: TLS13[%d]: record has bogus version",
- SSL_GETPID(), ss->fd));
- return SECFailure;
+ /* Check the version number in the record. Stream only. */
+ if (!IS_DTLS(ss)) {
+ SSL3ProtocolVersion version =
+ ((SSL3ProtocolVersion)cText->hdr[1] << 8) |
+ (SSL3ProtocolVersion)cText->hdr[2];
+ if (version != spec->recordVersion) {
+ /* Do we need a better error here? */
+ SSL_TRC(3, ("%d: TLS13[%d]: record has bogus version",
+ SSL_GETPID(), ss->fd));
+ return SECFailure;
+ }
}
/* Decrypt */
PORT_Assert(cipher_def->type == type_aead);
- rv = tls13_FormatAdditionalData(ss, aad, sizeof(aad), spec->epoch, seqNum);
+ rv = tls13_FormatAdditionalData(ss, cText->hdr, cText->hdrLen,
+ spec->epoch, cText->seqNum,
+ aad, &aadLen, sizeof(aad));
if (rv != SECSuccess) {
return SECFailure;
}
@@ -4959,7 +5018,7 @@ tls13_UnprotectRecord(sslSocket *ss,
plaintext->space, /* maxout */
cText->buf->buf, /* in */
cText->buf->len, /* inlen */
- aad, sizeof(aad));
+ aad, aadLen);
if (rv != SECSuccess) {
SSL_TRC(3,
("%d: TLS13[%d]: record has bogus MAC",
@@ -4968,6 +5027,16 @@ tls13_UnprotectRecord(sslSocket *ss,
return SECFailure;
}
+ /* There is a similar test in ssl3_HandleRecord, but this test is needed to
+ * account for padding. It's safe to do this here (including the alert),
+ * because it only confirms that the record exceeded the size limit, which
+ * is apparent from the size of the ciphertext. */
+ if (plaintext->len > spec->recordSizeLimit + 1) {
+ SSL3_SendAlert(ss, alert_fatal, record_overflow);
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
+ }
+
/* The record is right-padded with 0s, followed by the true
* content type, so read from the right until we receive a
* nonzero byte. */
@@ -4977,9 +5046,7 @@ tls13_UnprotectRecord(sslSocket *ss,
/* Bogus padding. */
if (plaintext->len < 1) {
- SSL_TRC(3,
- ("%d: TLS13[%d]: empty record",
- SSL_GETPID(), ss->fd, cText->type));
+ SSL_TRC(3, ("%d: TLS13[%d]: empty record", SSL_GETPID(), ss->fd));
/* It's safe to report this specifically because it happened
* after the MAC has been verified. */
PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING);
@@ -4987,12 +5054,12 @@ tls13_UnprotectRecord(sslSocket *ss,
}
/* Record the type. */
- cText->type = plaintext->buf[plaintext->len - 1];
+ *innerType = (SSL3ContentType)plaintext->buf[plaintext->len - 1];
--plaintext->len;
/* Check that we haven't received too much 0-RTT data. */
if (spec->epoch == TrafficKeyEarlyApplicationData &&
- cText->type == content_application_data) {
+ *innerType == content_application_data) {
if (plaintext->len > spec->earlyDataRemaining) {
*alert = unexpected_message;
PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA);
@@ -5002,9 +5069,8 @@ tls13_UnprotectRecord(sslSocket *ss,
}
SSL_TRC(10,
- ("%d: TLS13[%d]: %s received record of length=%d type=%d",
- SSL_GETPID(), ss->fd, SSL_ROLE(ss),
- plaintext->len, cText->type));
+ ("%d: TLS13[%d]: %s received record of length=%d, type=%d",
+ SSL_GETPID(), ss->fd, SSL_ROLE(ss), plaintext->len, *innerType));
return SECSuccess;
}
@@ -5227,6 +5293,58 @@ tls13_EncodeDraftVersion(SSL3ProtocolVersion version)
return (PRUint16)version;
}
+SECStatus
+tls13_ClientReadSupportedVersion(sslSocket *ss)
+{
+ PRUint32 temp;
+ SSL3ProtocolVersion v;
+ TLSExtension *versionExtension;
+ SECItem it;
+ SECStatus rv;
+
+ /* Update the version based on the extension, as necessary. */
+ versionExtension = ssl3_FindExtension(ss, ssl_tls13_supported_versions_xtn);
+ if (!versionExtension) {
+ return SECSuccess;
+ }
+
+ /* Struct copy so we don't damage the extension. */
+ it = versionExtension->data;
+
+ rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &it.data, &it.len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (it.len) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter);
+ return SECFailure;
+ }
+ v = (SSL3ProtocolVersion)temp;
+
+ /* You cannot negotiate < TLS 1.3 with supported_versions. */
+ if (v < SSL_LIBRARY_VERSION_TLS_1_3) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, illegal_parameter);
+ return SECFailure;
+ }
+
+#ifdef TLS_1_3_DRAFT_VERSION
+ if (temp == SSL_LIBRARY_VERSION_TLS_1_3) {
+ FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
+ return SECFailure;
+ }
+ if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
+ v = SSL_LIBRARY_VERSION_TLS_1_3;
+ } else {
+ v = (SSL3ProtocolVersion)temp;
+ }
+#else
+ v = (SSL3ProtocolVersion)temp;
+#endif
+
+ ss->version = v;
+ return SECSuccess;
+}
+
/* Pick the highest version we support that is also advertised. */
SECStatus
tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions)