summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-09-17 08:51:49 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-09-17 08:51:49 +0200
commit882aaf5b1fda7b216051b55e268de78fd5126f42 (patch)
treeccb3f6f6299a5d1c603e6b73d3892f635bb96a8e /security/nss/lib/ssl
parent8ee235ca5df26f39ca3066935bef90c4d28dd61a (diff)
parentd118d486a680ed42030b1bdee263a29831da3e86 (diff)
downloadUXP-882aaf5b1fda7b216051b55e268de78fd5126f42.tar
UXP-882aaf5b1fda7b216051b55e268de78fd5126f42.tar.gz
UXP-882aaf5b1fda7b216051b55e268de78fd5126f42.tar.lz
UXP-882aaf5b1fda7b216051b55e268de78fd5126f42.tar.xz
UXP-882aaf5b1fda7b216051b55e268de78fd5126f42.zip
Merge branch 'master' into Pale_Moon-release
# Conflicts: # application/palemoon/config/version.txt # js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h # toolkit/components/search/orginal/nsSearchService.js
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r--security/nss/lib/ssl/SSLerrs.h11
-rw-r--r--security/nss/lib/ssl/dtls13con.c59
-rw-r--r--security/nss/lib/ssl/dtls13con.h4
-rw-r--r--security/nss/lib/ssl/dtlscon.c116
-rw-r--r--security/nss/lib/ssl/dtlscon.h2
-rw-r--r--security/nss/lib/ssl/ssl.h81
-rw-r--r--security/nss/lib/ssl/ssl3con.c430
-rw-r--r--security/nss/lib/ssl/ssl3ecc.c6
-rw-r--r--security/nss/lib/ssl/ssl3ext.c13
-rw-r--r--security/nss/lib/ssl/ssl3ext.h3
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c181
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.h7
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c109
-rw-r--r--security/nss/lib/ssl/ssl3prot.h2
-rw-r--r--security/nss/lib/ssl/sslcert.c3
-rw-r--r--security/nss/lib/ssl/sslerr.h2
-rw-r--r--security/nss/lib/ssl/sslimpl.h39
-rw-r--r--security/nss/lib/ssl/sslsecur.c19
-rw-r--r--security/nss/lib/ssl/sslsock.c123
-rw-r--r--security/nss/lib/ssl/sslspec.c1
-rw-r--r--security/nss/lib/ssl/sslspec.h8
-rw-r--r--security/nss/lib/ssl/sslt.h3
-rw-r--r--security/nss/lib/ssl/tls13con.c262
-rw-r--r--security/nss/lib/ssl/tls13con.h2
-rw-r--r--security/nss/lib/ssl/tls13exthandle.c4
25 files changed, 958 insertions, 532 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h
index d3f087544..f01d16583 100644
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -374,7 +374,7 @@ ER3(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY, (SSL_ERROR_BASE + 115),
"SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.")
ER3(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID, (SSL_ERROR_BASE + 116),
- "SSL received invalid NPN extension data.")
+ "SSL received invalid ALPN extension data.")
ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2, (SSL_ERROR_BASE + 117),
"SSL feature not supported for SSL 2.0 connections.")
@@ -543,3 +543,12 @@ ER3(SSL_ERROR_TOO_MANY_KEY_UPDATES, (SSL_ERROR_BASE + 171),
ER3(SSL_ERROR_HANDSHAKE_FAILED, (SSL_ERROR_BASE + 172),
"SSL handshake has already failed. No more operations possible.")
+
+ER3(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, (SSL_ERROR_BASE + 173),
+ "SSL received an invalid resumption token.")
+
+ER3(SSL_ERROR_RX_MALFORMED_DTLS_ACK, (SSL_ERROR_BASE + 174),
+ "SSL received a malformed DTLS ACK")
+
+ER3(SSL_ERROR_DH_KEY_TOO_LONG, (SSL_ERROR_BASE + 175),
+ "SSL received a DH key share that's too long (>8192 bit).")
diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c
index aba0f62ab..de6cb47ca 100644
--- a/security/nss/lib/ssl/dtls13con.c
+++ b/security/nss/lib/ssl/dtls13con.c
@@ -11,6 +11,43 @@
#include "sslimpl.h"
#include "sslproto.h"
+SECStatus
+dtls13_InsertCipherTextHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
+ sslBuffer *wrBuf, PRBool *needsLength)
+{
+ PRUint32 seq;
+ SECStatus rv;
+
+ /* Avoid using short records for the handshake. We pack multiple records
+ * into the one datagram for the handshake. */
+ if (ss->opt.enableDtlsShortHeader &&
+ cwSpec->epoch != TrafficKeyHandshake) {
+ *needsLength = PR_FALSE;
+ /* The short header is comprised of two octets in the form
+ * 0b001essssssssssss where 'e' is the low bit of the epoch and 's' is
+ * the low 12 bits of the sequence number. */
+ seq = 0x2000 |
+ (((uint64_t)cwSpec->epoch & 1) << 12) |
+ (cwSpec->nextSeqNum & 0xfff);
+ return sslBuffer_AppendNumber(wrBuf, seq, 2);
+ }
+
+ rv = sslBuffer_AppendNumber(wrBuf, content_application_data, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* The epoch and sequence number are encoded on 4 octets, with the epoch
+ * consuming the first two bits. */
+ seq = (((uint64_t)cwSpec->epoch & 3) << 30) | (cwSpec->nextSeqNum & 0x3fffffff);
+ rv = sslBuffer_AppendNumber(wrBuf, seq, 4);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ *needsLength = PR_TRUE;
+ return SECSuccess;
+}
+
/* DTLS 1.3 Record map for ACK processing.
* This represents a single fragment, so a record which includes
* multiple fragments will have one entry for each fragment on the
@@ -82,10 +119,15 @@ dtls13_SendAck(sslSocket *ss)
SECStatus rv = SECSuccess;
PRCList *cursor;
PRInt32 sent;
+ unsigned int offset;
SSL_TRC(10, ("%d: SSL3[%d]: Sending ACK",
SSL_GETPID(), ss->fd));
+ rv = sslBuffer_Skip(&buf, 2, &offset);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsRcvdHandshake);
cursor != &ss->ssl3.hs.dtlsRcvdHandshake;
cursor = PR_NEXT_LINK(cursor)) {
@@ -99,6 +141,11 @@ dtls13_SendAck(sslSocket *ss)
}
}
+ rv = sslBuffer_InsertLength(&buf, offset, 2);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
ssl_GetXmitBufLock(ss);
sent = ssl3_SendRecord(ss, NULL, content_ack,
buf.buf, buf.len, 0);
@@ -364,6 +411,7 @@ dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
{
PRUint8 *b = databuf->buf;
PRUint32 l = databuf->len;
+ unsigned int length;
SECStatus rv;
/* Ensure we don't loop. */
@@ -372,10 +420,19 @@ dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
PORT_Assert(IS_DTLS(ss));
if (!tls13_MaybeTls13(ss)) {
tls13_FatalError(ss, SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, illegal_parameter);
- return SECSuccess;
+ return SECFailure;
}
SSL_TRC(10, ("%d: SSL3[%d]: Handling ACK", SSL_GETPID(), ss->fd));
+ rv = ssl3_ConsumeHandshakeNumber(ss, &length, 2, &b, &l);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (length != l) {
+ tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_DTLS_ACK, decode_error);
+ return SECFailure;
+ }
+
while (l > 0) {
PRUint64 seq;
PRCList *cursor;
diff --git a/security/nss/lib/ssl/dtls13con.h b/security/nss/lib/ssl/dtls13con.h
index bf14d3bd2..ca48ef363 100644
--- a/security/nss/lib/ssl/dtls13con.h
+++ b/security/nss/lib/ssl/dtls13con.h
@@ -9,6 +9,10 @@
#ifndef __dtls13con_h_
#define __dtls13con_h_
+SECStatus dtls13_InsertCipherTextHeader(const sslSocket *ss,
+ ssl3CipherSpec *cwSpec,
+ sslBuffer *wrBuf,
+ PRBool *needsLength);
SECStatus dtls13_RememberFragment(sslSocket *ss, PRCList *list,
PRUint32 sequence, PRUint32 offset,
PRUint32 length, DTLSEpoch epoch,
diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c
index 2f335f924..a82295c66 100644
--- a/security/nss/lib/ssl/dtlscon.c
+++ b/security/nss/lib/ssl/dtlscon.c
@@ -724,13 +724,16 @@ dtls_FragmentHandshake(sslSocket *ss, DTLSQueuedMessage *msg)
PORT_Assert(end <= contentLen);
fragmentLen = PR_MIN(end, contentLen) - fragmentOffset;
- /* Reduce to the space remaining in the MTU. Allow for any existing
- * messages, record expansion, and the handshake header. */
+ /* Limit further by the record size limit. Account for the header. */
+ fragmentLen = PR_MIN(fragmentLen,
+ msg->cwSpec->recordSizeLimit - DTLS_HS_HDR_LEN);
+
+ /* Reduce to the space remaining in the MTU. */
fragmentLen = PR_MIN(fragmentLen,
ss->ssl3.mtu - /* MTU estimate. */
- ss->pendingBuf.len - /* Less unsent records. */
+ ss->pendingBuf.len - /* Less any unsent records. */
DTLS_MAX_EXPANSION - /* Allow for expansion. */
- DTLS_HS_HDR_LEN); /* + handshake header. */
+ DTLS_HS_HDR_LEN); /* And the handshake header. */
PORT_Assert(fragmentLen > 0 || fragmentOffset == 0);
/* Make totally sure that we will fit in the buffer. This should be
@@ -776,7 +779,7 @@ dtls_FragmentHandshake(sslSocket *ss, DTLSQueuedMessage *msg)
rv = dtls13_RememberFragment(ss, &ss->ssl3.hs.dtlsSentHandshake,
msgSeq, fragmentOffset, fragmentLen,
msg->cwSpec->epoch,
- msg->cwSpec->seqNum);
+ msg->cwSpec->nextSeqNum);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -1319,6 +1322,107 @@ DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout)
return SECSuccess;
}
+PRBool
+dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet)
+{
+#ifndef UNSAFE_FUZZER_MODE
+ return version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ firstOctet == content_handshake ||
+ firstOctet == content_ack ||
+ firstOctet == content_alert;
+#else
+ return PR_TRUE;
+#endif
+}
+
+DTLSEpoch
+dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr)
+{
+ DTLSEpoch epoch;
+ DTLSEpoch maxEpoch;
+ DTLSEpoch partial;
+
+ if (dtls_IsLongHeader(crSpec->version, hdr[0])) {
+ return ((DTLSEpoch)hdr[3] << 8) | hdr[4];
+ }
+
+ /* A lot of how we recover the epoch here will depend on how we plan to
+ * manage KeyUpdate. In the case that we decide to install a new read spec
+ * as a KeyUpdate is handled, crSpec will always be the highest epoch we can
+ * possibly receive. That makes this easier to manage. */
+ if ((hdr[0] & 0xe0) == 0x20) {
+ /* Use crSpec->epoch, or crSpec->epoch - 1 if the last bit differs. */
+ if (((hdr[0] >> 4) & 1) == (crSpec->epoch & 1)) {
+ return crSpec->epoch;
+ }
+ return crSpec->epoch - 1;
+ }
+
+ /* dtls_GatherData should ensure that this works. */
+ PORT_Assert(hdr[0] == content_application_data);
+
+ /* This uses the same method as is used to recover the sequence number in
+ * dtls_ReadSequenceNumber, except that the maximum value is set to the
+ * current epoch. */
+ partial = hdr[1] >> 6;
+ maxEpoch = PR_MAX(crSpec->epoch, 3);
+ epoch = (maxEpoch & 0xfffc) | partial;
+ if (partial > (maxEpoch & 0x03)) {
+ epoch -= 4;
+ }
+ return epoch;
+}
+
+static sslSequenceNumber
+dtls_ReadSequenceNumber(const ssl3CipherSpec *spec, const PRUint8 *hdr)
+{
+ sslSequenceNumber cap;
+ sslSequenceNumber partial;
+ sslSequenceNumber seqNum;
+ sslSequenceNumber mask;
+
+ if (dtls_IsLongHeader(spec->version, hdr[0])) {
+ static const unsigned int seqNumOffset = 5; /* type, version, epoch */
+ static const unsigned int seqNumLength = 6;
+ sslReader r = SSL_READER(hdr + seqNumOffset, seqNumLength);
+ (void)sslRead_ReadNumber(&r, seqNumLength, &seqNum);
+ return seqNum;
+ }
+
+ /* Only the least significant bits of the sequence number is available here.
+ * This recovers the value based on the next expected sequence number.
+ *
+ * This works by determining the maximum possible sequence number, which is
+ * half the range of possible values above the expected next value (the
+ * expected next value is in |spec->seqNum|). Then, the last part of the
+ * sequence number is replaced. If that causes the value to exceed the
+ * maximum, subtract an entire range.
+ */
+ if ((hdr[0] & 0xe0) == 0x20) {
+ /* A 12-bit sequence number. */
+ cap = spec->nextSeqNum + (1ULL << 11);
+ partial = (((sslSequenceNumber)hdr[0] & 0xf) << 8) |
+ (sslSequenceNumber)hdr[1];
+ mask = (1ULL << 12) - 1;
+ } else {
+ /* A 30-bit sequence number. */
+ cap = spec->nextSeqNum + (1ULL << 29);
+ partial = (((sslSequenceNumber)hdr[1] & 0x3f) << 24) |
+ ((sslSequenceNumber)hdr[2] << 16) |
+ ((sslSequenceNumber)hdr[3] << 8) |
+ (sslSequenceNumber)hdr[4];
+ mask = (1ULL << 30) - 1;
+ }
+ seqNum = (cap & ~mask) | partial;
+ /* The second check prevents the value from underflowing if we get a large
+ * gap at the start of a connection, where this subtraction would cause the
+ * sequence number to wrap to near UINT64_MAX. */
+ if ((partial > (cap & mask)) && (seqNum > mask)) {
+ seqNum -= mask + 1;
+ }
+ return seqNum;
+}
+
/*
* DTLS relevance checks:
* Note that this code currently ignores all out-of-epoch packets,
@@ -1336,7 +1440,7 @@ dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec,
const SSL3Ciphertext *cText,
sslSequenceNumber *seqNumOut)
{
- sslSequenceNumber seqNum = cText->seq_num & RECORD_SEQ_MASK;
+ sslSequenceNumber seqNum = dtls_ReadSequenceNumber(spec, cText->hdr);
if (dtls_RecordGetRecvd(&spec->recvdRecords, seqNum) != 0) {
SSL_TRC(10, ("%d: SSL3[%d]: dtls_IsRelevant, rejecting "
"potentially replayed packet",
diff --git a/security/nss/lib/ssl/dtlscon.h b/security/nss/lib/ssl/dtlscon.h
index d094380f8..45fc069b9 100644
--- a/security/nss/lib/ssl/dtlscon.h
+++ b/security/nss/lib/ssl/dtlscon.h
@@ -41,8 +41,10 @@ extern SSL3ProtocolVersion
dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv);
extern SSL3ProtocolVersion
dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv);
+DTLSEpoch dtls_ReadEpoch(const ssl3CipherSpec *crSpec, const PRUint8 *hdr);
extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec,
const SSL3Ciphertext *cText,
sslSequenceNumber *seqNum);
void dtls_ReceivedFirstMessageInFlight(sslSocket *ss);
+PRBool dtls_IsLongHeader(SSL3ProtocolVersion version, PRUint8 firstOctet);
#endif
diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h
index 25aabbaa2..ecc4f9506 100644
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -158,23 +158,18 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
#define SSL_CBC_RANDOM_IV 23
#define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */
-/* SSL_ENABLE_NPN controls whether the NPN extension is enabled for the initial
- * handshake when application layer protocol negotiation is used.
- * SSL_SetNextProtoCallback or SSL_SetNextProtoNego must be used to control the
- * application layer protocol negotiation; otherwise, the NPN extension will
- * not be negotiated. SSL_ENABLE_NPN is currently enabled by default but this
- * may change in future versions.
- */
+/* SSL_ENABLE_NPN is defunct and defaults to false.
+ * Using this option will not have any effect but won't produce an error. */
#define SSL_ENABLE_NPN 25
/* SSL_ENABLE_ALPN controls whether the ALPN extension is enabled for the
* initial handshake when application layer protocol negotiation is used.
- * SSL_SetNextProtoNego (not SSL_SetNextProtoCallback) must be used to control
- * the application layer protocol negotiation; otherwise, the ALPN extension
- * will not be negotiated. ALPN is not negotiated for renegotiation handshakes,
- * even though the ALPN specification defines a way to use ALPN during
- * renegotiations. SSL_ENABLE_ALPN is currently disabled by default, but this
- * may change in future versions.
+ * SSL_SetNextProtoNego or SSL_SetNextProtoCallback can be used to control
+ * the application layer protocol negotiation;
+ * ALPN is not negotiated for renegotiation handshakes, even though the ALPN
+ * specification defines a way to use ALPN during renegotiations.
+ * SSL_ENABLE_ALPN is currently enabled by default, but this may change in
+ * future versions.
*/
#define SSL_ENABLE_ALPN 26
@@ -248,12 +243,45 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
*/
#define SSL_ENABLE_0RTT_DATA 33
+/* Sets a limit to the size of encrypted records (see
+ * draft-ietf-tls-record-limit). This is the value that is advertised to peers,
+ * not a limit on the size of records that will be created. Setting this value
+ * reduces the size of records that will be received (not sent).
+ *
+ * This limit applies to the plaintext, but the records that appear on the wire
+ * will be bigger. This doesn't include record headers, IVs, block cipher
+ * padding, and authentication tags or MACs.
+ *
+ * NSS always advertises the record size limit extension. If this option is not
+ * set, the extension will contain the maximum allowed size for the selected TLS
+ * version (currently this is 16384 or 2^14 for TLS 1.2 and lower and 16385 for
+ * TLS 1.3).
+ *
+ * By default, NSS creates records that are the maximum size possible, using all
+ * the data that was written by the application. Writes larger than the maximum
+ * are split into maximum sized records, and any remainder (unless
+ * SSL_CBC_RANDOM_IV is enabled and active). If a peer advertises a record size
+ * limit then that value is used instead.
+ */
+#define SSL_RECORD_SIZE_LIMIT 34
+
/* Enables TLS 1.3 compatibility mode. In this mode, the client includes a fake
* session ID in the handshake and sends a ChangeCipherSpec. A server will
* always use the setting chosen by the client, so the value of this option has
* no effect for a server. This setting is ignored for DTLS. */
#define SSL_ENABLE_TLS13_COMPAT_MODE 35
+/* Enables the sending of DTLS records using the short (two octet) record
+ * header. Only do this if there are 2^10 or fewer packets in flight at a time;
+ * using this with a larger number of packets in flight could mean that packets
+ * are dropped if there is reordering.
+ *
+ * This applies to TLS 1.3 only. This is not a parameter that is negotiated
+ * during the TLS handshake. Unlike other socket options, this option can be
+ * changed after a handshake is complete.
+ */
+#define SSL_ENABLE_DTLS_SHORT_HEADER 36
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
@@ -272,10 +300,10 @@ SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRIntn val);
SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRIntn *val);
SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle);
-/* SSLNextProtoCallback is called during the handshake for the client, when a
- * Next Protocol Negotiation (NPN) extension has been received from the server.
- * |protos| and |protosLen| define a buffer which contains the server's
- * advertisement. This data is guaranteed to be well formed per the NPN spec.
+/* SSLNextProtoCallback is called during the handshake for the server, when an
+ * Application-Layer Protocol Negotiation (ALPN) extension has been received
+ * from the client. |protos| and |protosLen| define a buffer which contains the
+ * client's advertisement.
* |protoOut| is a buffer provided by the caller, of length 255 (the maximum
* allowed by the protocol). On successful return, the protocol to be announced
* to the server will be in |protoOut| and its length in |*protoOutLen|.
@@ -291,27 +319,24 @@ typedef SECStatus(PR_CALLBACK *SSLNextProtoCallback)(
unsigned int *protoOutLen,
unsigned int protoMaxOut);
-/* SSL_SetNextProtoCallback sets a callback function to handle Next Protocol
- * Negotiation. It causes a client to advertise NPN. */
+/* SSL_SetNextProtoCallback sets a callback function to handle ALPN Negotiation.
+ * It causes a client to advertise ALPN. */
SSL_IMPORT SECStatus SSL_SetNextProtoCallback(PRFileDesc *fd,
SSLNextProtoCallback callback,
void *arg);
/* SSL_SetNextProtoNego can be used as an alternative to
- * SSL_SetNextProtoCallback. It also causes a client to advertise NPN and
- * installs a default callback function which selects the first supported
- * protocol in server-preference order. If no matching protocol is found it
- * selects the first supported protocol.
+ * SSL_SetNextProtoCallback.
*
- * Using this function also allows the client to transparently support ALPN.
+ * Using this function allows client and server to transparently support ALPN.
* The same set of protocols will be advertised via ALPN and, if the server
* uses ALPN to select a protocol, SSL_GetNextProto will return
* SSL_NEXT_PROTO_SELECTED as the state.
*
- * Since NPN uses the first protocol as the fallback protocol, when sending an
- * ALPN extension, the first protocol is moved to the end of the list. This
- * indicates that the fallback protocol is the least preferred. The other
- * protocols should be in preference order.
+ * Because the predecessor to ALPN, NPN, used the first protocol as the fallback
+ * protocol, when sending an ALPN extension, the first protocol is moved to the
+ * end of the list. This indicates that the fallback protocol is the least
+ * preferred. The other protocols should be in preference order.
*
* The supported protocols are specified in |data| in wire-format (8-bit
* length-prefixed). For example: "\010http/1.1\006spdy/2". */
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 2593bbacc..466fc296f 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -990,27 +990,22 @@ ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b, unsigned int *len,
if (rv != SECSuccess) {
return SECFailure; /* alert has been sent */
}
-
-#ifdef TLS_1_3_DRAFT_VERSION
- if (temp == SSL_LIBRARY_VERSION_TLS_1_3) {
- (void)SSL3_SendAlert(ss, alert_fatal, protocol_version);
- PORT_SetError(SSL_ERROR_UNSUPPORTED_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
if (IS_DTLS(ss)) {
- /* If this fails, we get 0 back and the next check to fails. */
v = dtls_DTLSVersionToTLSVersion(v);
+ /* Check for failure. */
+ if (!v || v > SSL_LIBRARY_VERSION_MAX_SUPPORTED) {
+ SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+ return SECFailure;
+ }
}
+ /* You can't negotiate TLS 1.3 this way. */
+ if (v >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+ return SECFailure;
+ }
*version = v;
return SECSuccess;
}
@@ -1415,7 +1410,7 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction,
spec->macDef = ssl_GetMacDef(ss, suiteDef);
spec->epoch = prev->epoch + 1;
- spec->seqNum = 0;
+ spec->nextSeqNum = 0;
if (IS_DTLS(ss) && direction == CipherSpecRead) {
dtls_InitRecvdRecords(&spec->recvdRecords);
}
@@ -1481,6 +1476,13 @@ ssl3_SetupBothPendingCipherSpecs(sslSocket *ss)
goto loser;
}
+ if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
+ ss->ssl3.prSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
+ ss->opt.recordSizeLimit);
+ ss->ssl3.pwSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
+ ss->xtnData.recordSizeLimit);
+ }
+
ssl_ReleaseSpecWriteLock(ss); /*******************************/
return SECSuccess;
@@ -2004,6 +2006,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
unsigned int ivLen = 0;
unsigned char pseudoHeaderBuf[13];
sslBuffer pseudoHeader = SSL_BUFFER(pseudoHeaderBuf);
+ int len;
if (cwSpec->cipherDef->type == type_block &&
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
@@ -2013,29 +2016,32 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
* record.
*/
ivLen = cwSpec->cipherDef->iv_size;
- if (ivLen > wrBuf->space) {
+ if (ivLen > SSL_BUFFER_SPACE(wrBuf)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
- rv = PK11_GenerateRandom(wrBuf->buf, ivLen);
+ rv = PK11_GenerateRandom(SSL_BUFFER_NEXT(wrBuf), ivLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
return rv;
}
rv = cwSpec->cipher(cwSpec->cipherContext,
- wrBuf->buf, /* output */
- (int *)&wrBuf->len, /* outlen */
- ivLen, /* max outlen */
- wrBuf->buf, /* input */
- ivLen); /* input len */
- if (rv != SECSuccess || wrBuf->len != ivLen) {
+ SSL_BUFFER_NEXT(wrBuf), /* output */
+ &len, /* outlen */
+ ivLen, /* max outlen */
+ SSL_BUFFER_NEXT(wrBuf), /* input */
+ ivLen); /* input len */
+ if (rv != SECSuccess || len != ivLen) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
+
+ rv = sslBuffer_Skip(wrBuf, len, NULL);
+ PORT_Assert(rv == SECSuccess); /* Can't fail. */
}
rv = ssl3_BuildRecordPseudoHeader(
- cwSpec->epoch, cwSpec->seqNum, type,
+ cwSpec->epoch, cwSpec->nextSeqNum, type,
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->recordVersion,
isDTLS, contentLen, &pseudoHeader);
PORT_Assert(rv == SECSuccess);
@@ -2043,23 +2049,26 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
const int nonceLen = cwSpec->cipherDef->explicit_nonce_size;
const int tagLen = cwSpec->cipherDef->tag_size;
- if (nonceLen + contentLen + tagLen > wrBuf->space) {
+ if (nonceLen + contentLen + tagLen > SSL_BUFFER_SPACE(wrBuf)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = cwSpec->aead(
&cwSpec->keyMaterial,
- PR_FALSE, /* do encrypt */
- wrBuf->buf, /* output */
- (int *)&wrBuf->len, /* out len */
- wrBuf->space, /* max out */
- pIn, contentLen, /* input */
+ PR_FALSE, /* do encrypt */
+ SSL_BUFFER_NEXT(wrBuf), /* output */
+ &len, /* out len */
+ SSL_BUFFER_SPACE(wrBuf), /* max out */
+ pIn, contentLen, /* input */
SSL_BUFFER_BASE(&pseudoHeader), SSL_BUFFER_LEN(&pseudoHeader));
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
+
+ rv = sslBuffer_Skip(wrBuf, len, NULL);
+ PORT_Assert(rv == SECSuccess); /* Can't fail. */
} else {
int blockSize = cwSpec->cipherDef->block_size;
@@ -2069,7 +2078,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
rv = ssl3_ComputeRecordMAC(cwSpec, SSL_BUFFER_BASE(&pseudoHeader),
SSL_BUFFER_LEN(&pseudoHeader),
pIn, contentLen,
- wrBuf->buf + ivLen + contentLen, &macLen);
+ SSL_BUFFER_NEXT(wrBuf) + contentLen, &macLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
return SECFailure;
@@ -2095,7 +2104,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
PORT_Assert((fragLen % blockSize) == 0);
/* Pad according to TLS rules (also acceptable to SSL3). */
- pBuf = &wrBuf->buf[ivLen + fragLen - 1];
+ pBuf = SSL_BUFFER_NEXT(wrBuf) + fragLen - 1;
for (i = padding_length + 1; i > 0; --i) {
*pBuf-- = padding_length;
}
@@ -2112,14 +2121,14 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
p2Len += oddLen;
PORT_Assert((blockSize < 2) ||
(p2Len % blockSize) == 0);
- memmove(wrBuf->buf + ivLen + p1Len, pIn + p1Len, oddLen);
+ memmove(SSL_BUFFER_NEXT(wrBuf) + p1Len, pIn + p1Len, oddLen);
}
if (p1Len > 0) {
int cipherBytesPart1 = -1;
rv = cwSpec->cipher(cwSpec->cipherContext,
- wrBuf->buf + ivLen, /* output */
- &cipherBytesPart1, /* actual outlen */
- p1Len, /* max outlen */
+ SSL_BUFFER_NEXT(wrBuf), /* output */
+ &cipherBytesPart1, /* actual outlen */
+ p1Len, /* max outlen */
pIn,
p1Len); /* input, and inputlen */
PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int)p1Len);
@@ -2127,22 +2136,24 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
- wrBuf->len += cipherBytesPart1;
+ rv = sslBuffer_Skip(wrBuf, p1Len, NULL);
+ PORT_Assert(rv == SECSuccess);
}
if (p2Len > 0) {
int cipherBytesPart2 = -1;
rv = cwSpec->cipher(cwSpec->cipherContext,
- wrBuf->buf + ivLen + p1Len,
+ SSL_BUFFER_NEXT(wrBuf),
&cipherBytesPart2, /* output and actual outLen */
p2Len, /* max outlen */
- wrBuf->buf + ivLen + p1Len,
+ SSL_BUFFER_NEXT(wrBuf),
p2Len); /* input and inputLen*/
PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int)p2Len);
if (rv != SECSuccess || cipherBytesPart2 != (int)p2Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
- wrBuf->len += cipherBytesPart2;
+ rv = sslBuffer_Skip(wrBuf, p2Len, NULL);
+ PORT_Assert(rv == SECSuccess);
}
}
@@ -2150,16 +2161,20 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
}
/* Note: though this can report failure, it shouldn't. */
-static SECStatus
+SECStatus
ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
- SSL3ContentType contentType, unsigned int len,
- sslBuffer *wrBuf)
+ SSL3ContentType contentType, sslBuffer *wrBuf,
+ PRBool *needsLength)
{
SECStatus rv;
#ifndef UNSAFE_FUZZER_MODE
if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
- cwSpec->cipherDef->calg != ssl_calg_null) {
+ cwSpec->epoch > TrafficKeyClearText) {
+ if (IS_DTLS(ss)) {
+ return dtls13_InsertCipherTextHeader(ss, cwSpec, wrBuf,
+ needsLength);
+ }
contentType = content_application_data;
}
#endif
@@ -2177,16 +2192,12 @@ ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
if (rv != SECSuccess) {
return SECFailure;
}
- rv = sslBuffer_AppendNumber(wrBuf, cwSpec->seqNum, 6);
+ rv = sslBuffer_AppendNumber(wrBuf, cwSpec->nextSeqNum, 6);
if (rv != SECSuccess) {
return SECFailure;
}
}
- rv = sslBuffer_AppendNumber(wrBuf, len, 2);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
+ *needsLength = PR_TRUE;
return SECSuccess;
}
@@ -2194,66 +2205,67 @@ SECStatus
ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type,
const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf)
{
- unsigned int headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH
- : SSL3_RECORD_HEADER_LENGTH;
- sslBuffer protBuf = SSL_BUFFER_FIXED(SSL_BUFFER_BASE(wrBuf) + headerLen,
- SSL_BUFFER_SPACE(wrBuf) - headerLen);
- PRBool isTLS13;
+ PRBool needsLength;
+ unsigned int lenOffset;
SECStatus rv;
PORT_Assert(cwSpec->direction == CipherSpecWrite);
PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0);
PORT_Assert(cwSpec->cipherDef->max_records <= RECORD_SEQ_MAX);
- if (cwSpec->seqNum >= cwSpec->cipherDef->max_records) {
+
+ if (cwSpec->nextSeqNum >= cwSpec->cipherDef->max_records) {
/* We should have automatically updated before here in TLS 1.3. */
PORT_Assert(cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3);
SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx",
- SSL_GETPID(), cwSpec->seqNum));
+ SSL_GETPID(), cwSpec->nextSeqNum));
PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS);
return SECFailure;
}
- isTLS13 = (PRBool)(cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+ rv = ssl_InsertRecordHeader(ss, cwSpec, type, wrBuf, &needsLength);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (needsLength) {
+ rv = sslBuffer_Skip(wrBuf, 2, &lenOffset);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
#ifdef UNSAFE_FUZZER_MODE
{
int len;
- rv = Null_Cipher(NULL, SSL_BUFFER_BASE(&protBuf), &len,
- SSL_BUFFER_SPACE(&protBuf), pIn, contentLen);
+ rv = Null_Cipher(NULL, SSL_BUFFER_NEXT(wrBuf), &len,
+ SSL_BUFFER_SPACE(wrBuf), pIn, contentLen);
if (rv != SECSuccess) {
return SECFailure; /* error was set */
}
- rv = sslBuffer_Skip(&protBuf, len, NULL);
+ rv = sslBuffer_Skip(wrBuf, len, NULL);
PORT_Assert(rv == SECSuccess); /* Can't fail. */
}
#else
- if (isTLS13) {
- rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, &protBuf);
+ if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, wrBuf);
} else {
rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), type,
- pIn, contentLen, &protBuf);
+ pIn, contentLen, wrBuf);
}
#endif
if (rv != SECSuccess) {
return SECFailure; /* error was set */
}
- PORT_Assert(protBuf.len <= MAX_FRAGMENT_LENGTH + (isTLS13 ? 256 : 1024));
-
- rv = ssl_InsertRecordHeader(ss, cwSpec, type, SSL_BUFFER_LEN(&protBuf),
- wrBuf);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
- PORT_Assert(SSL_BUFFER_LEN(wrBuf) == headerLen);
- rv = sslBuffer_Skip(wrBuf, SSL_BUFFER_LEN(&protBuf), NULL);
- if (rv != SECSuccess) {
- PORT_Assert(0); /* Can't fail. */
- return SECFailure;
+ if (needsLength) {
+ /* Insert the length. */
+ rv = sslBuffer_InsertLength(wrBuf, lenOffset, 2);
+ if (rv != SECSuccess) {
+ PORT_Assert(0); /* Can't fail. */
+ return SECFailure;
+ }
}
- ++cwSpec->seqNum;
+ ++cwSpec->nextSeqNum;
return SECSuccess;
}
@@ -2267,7 +2279,7 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type,
unsigned int spaceNeeded;
SECStatus rv;
- contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH);
+ contentLen = PR_MIN(nIn, spec->recordSizeLimit);
spaceNeeded = contentLen + SSL3_BUFFER_FUDGE;
if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
spec->cipherDef->type == type_block) {
@@ -2291,6 +2303,7 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type,
*written = contentLen;
return SECSuccess;
}
+
/* Process the plain text before sending it.
* Returns the number of bytes of plaintext that were successfully sent
* plus the number of bytes of plaintext that were copied into the
@@ -2368,7 +2381,7 @@ ssl3_SendRecord(sslSocket *ss,
rv = ssl_ProtectNextRecord(ss, spec, type, pIn, nIn, &written);
ssl_ReleaseSpecReadLock(ss);
if (rv != SECSuccess) {
- return SECFailure;
+ goto loser;
}
PORT_Assert(written > 0);
@@ -3034,7 +3047,6 @@ ssl3_SendChangeCipherSpecsInt(sslSocket *ss)
return SECFailure; /* error code set by ssl3_SendRecord */
}
} else {
- SECStatus rv;
rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
if (rv != SECSuccess) {
return SECFailure;
@@ -5567,13 +5579,20 @@ ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
}
/* Get the wrapped (encrypted) pre-master secret, enc_pms */
- enc_pms.len = SECKEY_PublicKeyStrength(svrPubKey);
+ unsigned int svrPubKeyBits = SECKEY_PublicKeyStrengthInBits(svrPubKey);
+ enc_pms.len = (svrPubKeyBits + 7) / 8;
+ /* Check that the RSA key isn't larger than 8k bit. */
+ if (svrPubKeyBits > SSL_MAX_RSA_KEY_BITS) {
+ (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+ ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
+ goto loser;
+ }
enc_pms.data = (unsigned char *)PORT_Alloc(enc_pms.len);
if (enc_pms.data == NULL) {
goto loser; /* err set by PORT_Alloc */
}
- /* wrap pre-master secret in server's public key. */
+ /* Wrap pre-master secret in server's public key. */
rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, pms, &enc_pms);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
@@ -5676,7 +5695,7 @@ ssl3_SendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
};
sslEphemeralKeyPair *keyPair = NULL;
SECKEYPublicKey *pubKey;
- PRUint8 dhData[1026]; /* Enough for the 8192-bit group. */
+ PRUint8 dhData[SSL_MAX_DH_KEY_BITS / 8 + 2];
sslBuffer dhBuf = SSL_BUFFER(dhData);
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -6208,7 +6227,6 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
SECItem sidBytes = { siBuffer, NULL, 0 };
PRBool isHelloRetry;
SSL3AlertDescription desc = illegal_parameter;
- TLSExtension *versionExtension;
const PRUint8 *savedMsg = b;
const PRUint32 savedLength = length;
#ifndef TLS_1_3_DRAFT_VERSION
@@ -6299,16 +6317,10 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
}
- /* Update the version based on the extension, as necessary. */
- versionExtension = ssl3_FindExtension(ss, ssl_tls13_supported_versions_xtn);
- if (versionExtension) {
- rv = ssl_ClientReadVersion(ss, &versionExtension->data.data,
- &versionExtension->data.len,
- &ss->version);
- if (rv != SECSuccess) {
- errCode = PORT_GetError();
- goto loser; /* An alert is sent by ssl_ClientReadVersion */
- }
+ /* Read supported_versions if present. */
+ rv = tls13_ClientReadSupportedVersion(ss);
+ if (rv != SECSuccess) {
+ goto loser;
}
PORT_Assert(!SSL_ALL_VERSIONS_DISABLED(&ss->vrange));
@@ -6332,7 +6344,7 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* The server didn't pick 1.3 although we either received a
* HelloRetryRequest, or we prepared to send early app data. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- if (ss->ssl3.hs.helloRetry) {
+ if (isHelloRetry || ss->ssl3.hs.helloRetry) {
/* SSL3_SendAlert() will uncache the SID. */
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
@@ -6393,8 +6405,9 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
/* Finally, now all the version-related checks have passed. */
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
/* Update the write cipher spec to match the version. But not after
- * HelloRetryRequest, because cwSpec might be a 0-RTT cipher spec. */
- if (!ss->firstHsDone && !ss->ssl3.hs.helloRetry) {
+ * HelloRetryRequest, because cwSpec might be a 0-RTT cipher spec,
+ * in which case this is a no-op. */
+ if (!ss->firstHsDone && !isHelloRetry) {
ssl_GetSpecWriteLock(ss);
ssl_SetSpecVersions(ss, ss->ssl3.cwSpec);
ssl_ReleaseSpecWriteLock(ss);
@@ -6729,6 +6742,10 @@ ssl_HandleDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length)
errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
goto alert_loser;
}
+ if (dh_p_bits > SSL_MAX_DH_KEY_BITS) {
+ errCode = SSL_ERROR_DH_KEY_TOO_LONG;
+ goto alert_loser;
+ }
rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
@@ -6938,8 +6955,10 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length,
goto alert_loser; /* malformed */
remaining -= 2;
+ if (SECITEM_MakeItem(ca_list->arena, &node->name, *b, len) != SECSuccess) {
+ goto no_mem;
+ }
node->name.len = len;
- node->name.data = *b;
*b += len;
*length -= len;
remaining -= len;
@@ -6967,7 +6986,6 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length,
return SECSuccess;
no_mem:
- PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
alert_loser:
@@ -7332,10 +7350,6 @@ ssl3_SendClientSecondRound(sslSocket *ss)
* certificate to an attacker that does not have a valid cert for the
* domain we are connecting to.
*
- * XXX: We should do the same for the NPN extension, but for that we
- * need an option to give the application the ability to leak the NPN
- * information to get better performance.
- *
* During the initial handshake on a connection, we never send/receive
* application data until we have authenticated the server's certificate;
* i.e. we have fully authenticated the handshake before using the cipher
@@ -7409,14 +7423,6 @@ ssl3_SendClientSecondRound(sslSocket *ss)
ss->enoughFirstHsDone = PR_TRUE;
if (!ss->firstHsDone) {
- /* XXX: If the server's certificate hasn't been authenticated by this
- * point, then we may be leaking this NPN message to an attacker.
- */
- rv = ssl3_SendNextProto(ss);
- if (rv != SECSuccess) {
- goto loser; /* err code was set. */
- }
-
if (ss->opt.enableFalseStart) {
if (!ss->ssl3.hs.authCertificatePending) {
/* When we fix bug 589047, we will need to know whether we are
@@ -8879,12 +8885,10 @@ ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry,
SSL3ProtocolVersion version;
sslSessionID *sid = ss->sec.ci.sid;
- if (IS_DTLS(ss) && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- version = dtls_TLSVersionToDTLSVersion(ss->version);
- } else {
- version = PR_MIN(ss->version, SSL_LIBRARY_VERSION_TLS_1_2);
+ version = PR_MIN(ss->version, SSL_LIBRARY_VERSION_TLS_1_2);
+ if (IS_DTLS(ss)) {
+ version = dtls_TLSVersionToDTLSVersion(version);
}
-
rv = sslBuffer_AppendNumber(messageBuf, version, 2);
if (rv != SECSuccess) {
return SECFailure;
@@ -11404,6 +11408,10 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
/* Increment the expected sequence number */
ss->ssl3.hs.recvMessageSeq++;
}
+
+ /* Taint the message so that it's easier to detect UAFs. */
+ PORT_Memset(b, 'N', length);
+
return rv;
}
@@ -11738,7 +11746,7 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize)
}
for (i = 0; i < toCheck; i++) {
- unsigned int t = paddingLength - i;
+ t = paddingLength - i;
/* If i <= paddingLength then the MSB of t is zero and mask is
* 0xff. Otherwise, mask is 0. */
unsigned char mask = DUPLICATE_MSB_TO_ALL(~t);
@@ -11878,6 +11886,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
unsigned int good;
unsigned int ivLen = 0;
SSL3ContentType rType;
+ SSL3ProtocolVersion rVersion;
unsigned int minLength;
unsigned int originalLen = 0;
PRUint8 headerBuf[13];
@@ -11950,7 +11959,9 @@ ssl3_UnprotectRecord(sslSocket *ss,
return SECFailure;
}
- rType = cText->type;
+ rType = (SSL3ContentType)cText->hdr[0];
+ rVersion = ((SSL3ProtocolVersion)cText->hdr[1] << 8) |
+ (SSL3ProtocolVersion)cText->hdr[2];
if (cipher_def->type == type_aead) {
/* XXX For many AEAD ciphers, the plaintext is shorter than the
* ciphertext by a fixed byte count, but it is not true in general.
@@ -11960,8 +11971,8 @@ ssl3_UnprotectRecord(sslSocket *ss,
cText->buf->len - cipher_def->explicit_nonce_size -
cipher_def->tag_size;
rv = ssl3_BuildRecordPseudoHeader(
- spec->epoch, IS_DTLS(ss) ? cText->seq_num : spec->seqNum,
- rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen, &header);
+ spec->epoch, cText->seqNum,
+ rType, isTLS, rVersion, IS_DTLS(ss), decryptedLen, &header);
PORT_Assert(rv == SECSuccess);
rv = spec->aead(&spec->keyMaterial,
PR_TRUE, /* do decrypt */
@@ -12008,8 +12019,8 @@ ssl3_UnprotectRecord(sslSocket *ss,
/* compute the MAC */
rv = ssl3_BuildRecordPseudoHeader(
- spec->epoch, IS_DTLS(ss) ? cText->seq_num : spec->seqNum,
- rType, isTLS, cText->version, IS_DTLS(ss),
+ spec->epoch, cText->seqNum,
+ rType, isTLS, rVersion, IS_DTLS(ss),
plaintext->len - spec->macDef->mac_size, &header);
PORT_Assert(rv == SECSuccess);
if (cipher_def->type == type_block) {
@@ -12059,13 +12070,19 @@ ssl3_UnprotectRecord(sslSocket *ss,
return SECSuccess;
}
-static SECStatus
+SECStatus
ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType,
DTLSEpoch epoch, sslSequenceNumber seqNum,
sslBuffer *databuf)
{
SECStatus rv;
+ /* check for Token Presence */
+ if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
+ PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
+ return SECFailure;
+ }
+
ssl_GetSSL3HandshakeLock(ss);
/* All the functions called in this switch MUST set error code if
@@ -12111,15 +12128,16 @@ ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType,
* Returns NULL if no appropriate cipher spec is found.
*/
static ssl3CipherSpec *
-ssl3_GetCipherSpec(sslSocket *ss, sslSequenceNumber seq)
+ssl3_GetCipherSpec(sslSocket *ss, SSL3Ciphertext *cText)
{
ssl3CipherSpec *crSpec = ss->ssl3.crSpec;
ssl3CipherSpec *newSpec = NULL;
- DTLSEpoch epoch = seq >> 48;
+ DTLSEpoch epoch;
if (!IS_DTLS(ss)) {
return crSpec;
}
+ epoch = dtls_ReadEpoch(crSpec, cText->hdr);
if (crSpec->epoch == epoch) {
return crSpec;
}
@@ -12136,6 +12154,11 @@ ssl3_GetCipherSpec(sslSocket *ss, sslSequenceNumber seq)
return NULL;
}
+/* MAX_EXPANSION is the amount by which a record might plausibly be expanded
+ * when protected. It's the worst case estimate, so the sum of block cipher
+ * padding (up to 256 octets) and HMAC (48 octets for SHA-384). */
+#define MAX_EXPANSION (256 + 48)
+
/* if cText is non-null, then decipher and check the MAC of the
* SSL record from cText->buf (typically gs->inbuf)
* into databuf (typically gs->buf), and any previous contents of databuf
@@ -12159,16 +12182,16 @@ ssl3_GetCipherSpec(sslSocket *ss, sslSequenceNumber seq)
* Application Data records.
*/
SECStatus
-ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
+ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
{
SECStatus rv;
PRBool isTLS;
DTLSEpoch epoch;
- sslSequenceNumber seqNum = 0;
ssl3CipherSpec *spec = NULL;
+ PRUint16 recordSizeLimit;
PRBool outOfOrderSpec = PR_FALSE;
SSL3ContentType rType;
- sslBuffer *plaintext;
+ sslBuffer *plaintext = &ss->gs.buf;
SSL3AlertDescription alert = internal_error;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
@@ -12178,27 +12201,23 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
return SECFailure;
}
- /* cText is NULL when we're called from ssl3_RestartHandshakeAfterXXX().
- * This implies that databuf holds a previously deciphered SSL Handshake
- * message.
- */
- if (cText == NULL) {
- SSL_DBG(("%d: SSL3[%d]: HandleRecord, resuming handshake",
- SSL_GETPID(), ss->fd));
- /* Note that this doesn't pass the epoch and sequence number of the
- * record through, which DTLS 1.3 depends on. DTLS doesn't support
- * asynchronous certificate validation, so that should be OK. */
- PORT_Assert(!IS_DTLS(ss));
- return ssl3_HandleNonApplicationData(ss, content_handshake,
- 0, 0, databuf);
+ /* Clear out the buffer in case this exits early. Any data then won't be
+ * processed twice. */
+ plaintext->len = 0;
+
+ /* We're waiting for another ClientHello, which will appear unencrypted.
+ * Use the content type to tell whether this should be discarded. */
+ if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr &&
+ cText->hdr[0] == content_application_data) {
+ PORT_Assert(ss->ssl3.hs.ws == wait_client_hello);
+ return SECSuccess;
}
ssl_GetSpecReadLock(ss); /******************************************/
- spec = ssl3_GetCipherSpec(ss, cText->seq_num);
+ spec = ssl3_GetCipherSpec(ss, cText);
if (!spec) {
PORT_Assert(IS_DTLS(ss));
ssl_ReleaseSpecReadLock(ss); /*****************************/
- databuf->len = 0; /* Needed to ensure data not left around */
return SECSuccess;
}
if (spec != ss->ssl3.crSpec) {
@@ -12209,66 +12228,68 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
}
isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0);
if (IS_DTLS(ss)) {
- if (!dtls_IsRelevant(ss, spec, cText, &seqNum)) {
+ if (!dtls_IsRelevant(ss, spec, cText, &cText->seqNum)) {
ssl_ReleaseSpecReadLock(ss); /*****************************/
- databuf->len = 0; /* Needed to ensure data not left around */
-
return SECSuccess;
}
} else {
- seqNum = spec->seqNum + 1;
+ cText->seqNum = spec->nextSeqNum;
}
- if (seqNum >= spec->cipherDef->max_records) {
+ if (cText->seqNum >= spec->cipherDef->max_records) {
ssl_ReleaseSpecReadLock(ss); /*****************************/
SSL_TRC(3, ("%d: SSL[%d]: read sequence number at limit 0x%0llx",
- SSL_GETPID(), ss->fd, seqNum));
+ SSL_GETPID(), ss->fd, cText->seqNum));
PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS);
return SECFailure;
}
- plaintext = databuf;
- plaintext->len = 0; /* filled in by Unprotect call below. */
-
- /* We're waiting for another ClientHello, which will appear unencrypted.
- * Use the content type to tell whether this is should be discarded.
- *
- * XXX If we decide to remove the content type from encrypted records, this
- * will become much more difficult to manage. */
- if (ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_hrr &&
- cText->type == content_application_data) {
+ recordSizeLimit = spec->recordSizeLimit;
+ if (cText->buf->len > recordSizeLimit + MAX_EXPANSION) {
ssl_ReleaseSpecReadLock(ss); /*****************************/
- PORT_Assert(ss->ssl3.hs.ws == wait_client_hello);
- databuf->len = 0;
- return SECSuccess;
+ SSL3_SendAlert(ss, alert_fatal, record_overflow);
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
}
- if (plaintext->space < MAX_FRAGMENT_LENGTH) {
- rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048);
+ if (plaintext->space < recordSizeLimit + MAX_EXPANSION) {
+ rv = sslBuffer_Grow(plaintext, recordSizeLimit + MAX_EXPANSION);
if (rv != SECSuccess) {
ssl_ReleaseSpecReadLock(ss); /*************************/
SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes",
- SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048));
+ SSL_GETPID(), ss->fd, recordSizeLimit + MAX_EXPANSION));
/* sslBuffer_Grow has set a memory error code. */
/* Perhaps we should send an alert. (but we have no memory!) */
return SECFailure;
}
}
+ /* Most record types aside from protected TLS 1.3 records carry the content
+ * type in the first octet. TLS 1.3 will override this value later. */
+ rType = cText->hdr[0];
+ /* Encrypted application data records could arrive before the handshake
+ * completes in DTLS 1.3. These can look like valid TLS 1.2 application_data
+ * records in epoch 0, which is never valid. Pretend they didn't decrypt. */
+ if (spec->epoch == 0 && rType == content_application_data) {
+ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
+ alert = unexpected_message;
+ rv = SECFailure;
+ } else {
#ifdef UNSAFE_FUZZER_MODE
- rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
- plaintext->space, cText->buf->buf, cText->buf->len);
+ rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
+ plaintext->space, cText->buf->buf, cText->buf->len);
#else
- /* IMPORTANT: Unprotect functions MUST NOT send alerts
- * because we still hold the spec read lock. Instead, if they
- * return SECFailure, they set *alert to the alert to be sent. */
- if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
- spec->cipherDef->calg == ssl_calg_null) {
- /* Unencrypted TLS 1.3 records use the pre-TLS 1.3 format. */
- rv = ssl3_UnprotectRecord(ss, spec, cText, plaintext, &alert);
- } else {
- rv = tls13_UnprotectRecord(ss, spec, cText, plaintext, &alert);
- }
+ /* IMPORTANT: Unprotect functions MUST NOT send alerts
+ * because we still hold the spec read lock. Instead, if they
+ * return SECFailure, they set *alert to the alert to be sent. */
+ if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+ spec->epoch == 0) {
+ rv = ssl3_UnprotectRecord(ss, spec, cText, plaintext, &alert);
+ } else {
+ rv = tls13_UnprotectRecord(ss, spec, cText, plaintext, &rType,
+ &alert);
+ }
#endif
+ }
if (rv != SECSuccess) {
ssl_ReleaseSpecReadLock(ss); /***************************/
@@ -12276,39 +12297,45 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd));
/* Ensure that we don't process this data again. */
- databuf->len = 0;
+ plaintext->len = 0;
- /* Ignore a CCS if the alternative handshake is negotiated. Note that
- * this will fail if the server fails to negotiate the alternative
- * handshake type in a 0-RTT session that is resumed from a session that
- * did negotiate it. We don't care about that corner case right now. */
+ /* Ignore a CCS if compatibility mode is negotiated. Note that this
+ * will fail if the server fails to negotiate compatibility mode in a
+ * 0-RTT session that is resumed from a session that did negotiate it.
+ * We don't care about that corner case right now. */
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
- cText->type == content_change_cipher_spec &&
+ cText->hdr[0] == content_change_cipher_spec &&
ss->ssl3.hs.ws != idle_handshake &&
cText->buf->len == 1 &&
cText->buf->buf[0] == change_cipher_spec_choice) {
/* Ignore the CCS. */
return SECSuccess;
}
+
if (IS_DTLS(ss) ||
(ss->sec.isServer &&
ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
- /* Silently drop the packet */
+ /* Silently drop the packet unless we sent a fatal alert. */
+ if (ss->ssl3.fatalAlertSent) {
+ return SECFailure;
+ }
return SECSuccess;
- } else {
- int errCode = PORT_GetError();
- SSL3_SendAlert(ss, alert_fatal, alert);
- /* Reset the error code in case SSL3_SendAlert called
- * PORT_SetError(). */
- PORT_SetError(errCode);
- return SECFailure;
}
+
+ int errCode = PORT_GetError();
+ SSL3_SendAlert(ss, alert_fatal, alert);
+ /* Reset the error code in case SSL3_SendAlert called
+ * PORT_SetError(). */
+ PORT_SetError(errCode);
+ return SECFailure;
}
/* SECSuccess */
- spec->seqNum = PR_MAX(spec->seqNum, seqNum);
if (IS_DTLS(ss)) {
- dtls_RecordSetRecvd(&spec->recvdRecords, seqNum);
+ dtls_RecordSetRecvd(&spec->recvdRecords, cText->seqNum);
+ spec->nextSeqNum = PR_MAX(spec->nextSeqNum, cText->seqNum + 1);
+ } else {
+ ++spec->nextSeqNum;
}
epoch = spec->epoch;
@@ -12317,19 +12344,18 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
/*
* The decrypted data is now in plaintext.
*/
- rType = cText->type; /* This must go after decryption because TLS 1.3
- * has encrypted content types. */
/* IMPORTANT: We are in DTLS 1.3 mode and we have processed something
* from the wrong epoch. Divert to a divert processing function to make
* sure we don't accidentally use the data unsafely. */
if (outOfOrderSpec) {
PORT_Assert(IS_DTLS(ss) && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
- return dtls13_HandleOutOfEpochRecord(ss, spec, rType, databuf);
+ return dtls13_HandleOutOfEpochRecord(ss, spec, rType, plaintext);
}
/* Check the length of the plaintext. */
- if (isTLS && databuf->len > MAX_FRAGMENT_LENGTH) {
+ if (isTLS && plaintext->len > recordSizeLimit) {
+ plaintext->len = 0;
SSL3_SendAlert(ss, alert_fatal, record_overflow);
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
return SECFailure;
@@ -12344,14 +12370,16 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
ss->sec.isServer &&
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
- return tls13_HandleEarlyApplicationData(ss, databuf);
+ return tls13_HandleEarlyApplicationData(ss, plaintext);
}
+ plaintext->len = 0;
(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
return SECFailure;
}
- return ssl3_HandleNonApplicationData(ss, rType, epoch, seqNum, databuf);
+ return ssl3_HandleNonApplicationData(ss, rType, epoch, cText->seqNum,
+ plaintext);
}
/*
diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c
index 913a14f63..f8b9a9400 100644
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -548,12 +548,14 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) {
rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme);
if (rv != SECSuccess) {
- goto loser; /* malformed or unsupported. */
+ errCode = PORT_GetError();
+ goto alert_loser; /* malformed or unsupported. */
}
rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme,
ss->sec.peerCert);
if (rv != SECSuccess) {
- goto loser;
+ errCode = PORT_GetError();
+ goto alert_loser;
}
hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
} else {
diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c
index 5a5077998..9b6c719f8 100644
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -39,7 +39,6 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn },
{ ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
{ ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
- { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
@@ -51,6 +50,7 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
{ ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
+ { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
{ 0, NULL }
};
@@ -61,7 +61,6 @@ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
/* TODO: add a handler for ssl_ec_point_formats_xtn */
{ ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn },
{ ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
- { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
@@ -70,6 +69,7 @@ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
{ ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
{ ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
+ { ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
{ 0, NULL }
};
@@ -122,7 +122,6 @@ static const sslExtensionBuilder clientHelloSendersTLS[] =
{ ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
{ ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
{ ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn },
- { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
@@ -137,6 +136,7 @@ static const sslExtensionBuilder clientHelloSendersTLS[] =
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
+ { ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn },
/* The pre_shared_key extension MUST be last. */
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
{ 0, NULL }
@@ -183,7 +183,6 @@ static const struct {
{ ssl_tls13_psk_key_exchange_modes_xtn, ssl_ext_native_only },
{ ssl_tls13_ticket_early_data_info_xtn, ssl_ext_native_only },
{ ssl_tls13_certificate_authorities_xtn, ssl_ext_native },
- { ssl_next_proto_nego_xtn, ssl_ext_none },
{ ssl_renegotiation_info_xtn, ssl_ext_native }
};
@@ -681,7 +680,11 @@ ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf,
}
}
- sslBuffer_Append(buf, tail.buf, tail.len);
+ rv = sslBuffer_Append(buf, tail.buf, tail.len);
+ if (rv != SECSuccess) {
+ goto loser; /* Code already set. */
+ }
+
sslBuffer_Clear(&tail);
return SECSuccess;
diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h
index d0f75a599..6d77c7459 100644
--- a/security/nss/lib/ssl/ssl3ext.h
+++ b/security/nss/lib/ssl/ssl3ext.h
@@ -98,6 +98,9 @@ struct TLSExtensionDataStr {
/* The application token contains a value that was passed to the client via
* a session ticket, or the cookie in a HelloRetryRequest. */
SECItem applicationToken;
+
+ /* The record size limit set by the peer. Our value is kept in ss->opt. */
+ PRUint16 recordSizeLimit;
};
typedef struct TLSExtensionStr {
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c
index e6388945e..d1f286dc3 100644
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -242,33 +242,11 @@ ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag)
return PR_FALSE;
}
-/* handle an incoming Next Protocol Negotiation extension. */
-SECStatus
-ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
- SECItem *data)
-{
- PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
-
- if (ss->firstHsDone || data->len != 0) {
- /* Clients MUST send an empty NPN extension, if any. */
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
- return SECFailure;
- }
-
- xtnData->negotiated[xtnData->numNegotiated++] = ssl_next_proto_nego_xtn;
-
- /* TODO: server side NPN support would require calling
- * ssl3_RegisterServerHelloExtensionSender here in order to echo the
- * extension back to the client. */
-
- return SECSuccess;
-}
-
-/* ssl3_ValidateNextProtoNego checks that the given block of data is valid: none
+/* ssl3_ValidateAppProtocol checks that the given block of data is valid: none
* of the lengths may be 0 and the sum of the lengths must equal the length of
* the block. */
SECStatus
-ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length)
+ssl3_ValidateAppProtocol(const unsigned char *data, unsigned int length)
{
unsigned int offset = 0;
@@ -286,7 +264,7 @@ ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length)
return SECSuccess;
}
-/* protocol selection handler for ALPN (server side) and NPN (client side) */
+/* Protocol selection handler for ALPN. */
static SECStatus
ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 extension, SECItem *data)
@@ -295,7 +273,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
unsigned char resultBuffer[255];
SECItem result = { siBuffer, resultBuffer, 0 };
- rv = ssl3_ValidateNextProtoNego(data->data, data->len);
+ rv = ssl3_ValidateAppProtocol(data->data, data->len);
if (rv != SECSuccess) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
@@ -303,11 +281,13 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
}
PORT_Assert(ss->nextProtoCallback);
- /* For ALPN, the cipher suite isn't selected yet. Note that extensions
+ /* The cipher suite isn't selected yet. Note that extensions
* sometimes affect what cipher suite is selected, e.g., for ECC. */
PORT_Assert((ss->ssl3.hs.preliminaryInfo &
ssl_preinfo_all & ~ssl_preinfo_cipher_suite) ==
(ssl_preinfo_all & ~ssl_preinfo_cipher_suite));
+ /* The callback has to make sure that either rv != SECSuccess or that result
+ * is not set if there is no common protocol. */
rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
result.data, &result.len, sizeof(resultBuffer));
if (rv != SECSuccess) {
@@ -320,21 +300,20 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
* stack. */
if (result.len > sizeof(resultBuffer)) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
- /* TODO: crash */
+ PORT_Assert(PR_FALSE);
return SECFailure;
}
SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
- if (extension == ssl_app_layer_protocol_xtn &&
- xtnData->nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) {
- /* The callback might say OK, but then it picks a default value - one
- * that was not listed. That's OK for NPN, but not ALPN. */
+ if (result.len < 1 || !result.data) {
+ /* Check that we actually got a result. */
ssl3_ExtSendAlert(ss, alert_fatal, no_application_protocol);
PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
return SECFailure;
}
+ xtnData->nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
xtnData->negotiated[xtnData->numNegotiated++] = extension;
return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result);
}
@@ -356,7 +335,7 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
- /* Unlike NPN, ALPN has extra redundant length information so that
+ /* ALPN has extra redundant length information so that
* the extension is the same in both ClientHello and ServerHello. */
rv = ssl3_ExtConsumeHandshakeNumber(ss, &count, 2, &data->data, &data->len);
if (rv != SECSuccess || count != data->len) {
@@ -389,39 +368,6 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
SECStatus
-ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
- SECItem *data)
-{
- PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
- PORT_Assert(!ss->firstHsDone);
-
- if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) {
- /* If the server negotiated ALPN then it has already told us what
- * protocol to use, so it doesn't make sense for us to try to negotiate
- * a different one by sending the NPN handshake message. However, if
- * we've negotiated NPN then we're required to send the NPN handshake
- * message. Thus, these two extensions cannot both be negotiated on the
- * same connection. */
- ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
- PORT_SetError(SSL_ERROR_BAD_SERVER);
- return SECFailure;
- }
-
- /* We should only get this call if we sent the extension, so
- * ss->nextProtoCallback needs to be non-NULL. However, it is possible
- * that an application erroneously cleared the callback between the time
- * we sent the ClientHello and now. */
- if (!ss->nextProtoCallback) {
- PORT_Assert(0);
- ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
- PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK);
- return SECFailure;
- }
-
- return ssl3_SelectAppProtocol(ss, xtnData, ssl_next_proto_nego_xtn, data);
-}
-
-SECStatus
ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data)
{
@@ -475,19 +421,6 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
SECStatus
-ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
- sslBuffer *buf, PRBool *added)
-{
- /* Renegotiations do not send this extension. */
- if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) {
- return SECSuccess;
- }
-
- *added = PR_TRUE;
- return SECSuccess;
-}
-
-SECStatus
ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
@@ -499,35 +432,15 @@ ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
- /* NPN requires that the client's fallback protocol is first in the
- * list. However, ALPN sends protocols in preference order. So move the
- * first protocol to the end of the list. */
-
if (len > 0) {
/* Each protocol string is prefixed with a single byte length. */
- unsigned int i;
-
rv = sslBuffer_AppendNumber(buf, len, 2);
if (rv != SECSuccess) {
return SECFailure;
}
-
- i = ss->opt.nextProtoNego.data[0] + 1;
- if (i <= len) {
- rv = sslBuffer_Append(buf, &ss->opt.nextProtoNego.data[i], len - i);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, i);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- } else {
- /* This seems to be invalid data so we'll send as-is. */
- rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len);
- if (rv != SECSuccess) {
- return SECFailure;
- }
+ rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len);
+ if (rv != SECSuccess) {
+ return SECFailure;
}
}
@@ -1955,3 +1868,67 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
+
+SECStatus
+ssl_HandleRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ SECItem *data)
+{
+ SECStatus rv;
+ PRUint32 limit;
+ PRUint32 maxLimit = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)
+ ? (MAX_FRAGMENT_LENGTH + 1)
+ : MAX_FRAGMENT_LENGTH;
+
+ rv = ssl3_ExtConsumeHandshakeNumber(ss, &limit, 2, &data->data, &data->len);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ if (data->len != 0 || limit < 64) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+ return SECFailure;
+ }
+
+ if (ss->sec.isServer) {
+ rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_record_size_limit_xtn,
+ &ssl_SendRecordSizeLimitXtn);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error already set. */
+ }
+ } else if (limit > maxLimit) {
+ /* The client can sensibly check the maximum. */
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+ return SECFailure;
+ }
+
+ /* We can't enforce the maximum on a server. But we do need to ensure
+ * that we don't apply a limit that is too large. */
+ xtnData->recordSizeLimit = PR_MIN(maxLimit, limit);
+ xtnData->negotiated[xtnData->numNegotiated++] = ssl_record_size_limit_xtn;
+ return SECSuccess;
+}
+
+SECStatus
+ssl_SendRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ PRUint32 maxLimit;
+ if (ss->sec.isServer) {
+ maxLimit = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)
+ ? (MAX_FRAGMENT_LENGTH + 1)
+ : MAX_FRAGMENT_LENGTH;
+ } else {
+ maxLimit = (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3)
+ ? (MAX_FRAGMENT_LENGTH + 1)
+ : MAX_FRAGMENT_LENGTH;
+ }
+ PRUint32 limit = PR_MIN(ss->opt.recordSizeLimit, maxLimit);
+ SECStatus rv = sslBuffer_AppendNumber(buf, limit, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ *added = PR_TRUE;
+ return SECSuccess;
+}
diff --git a/security/nss/lib/ssl/ssl3exthandle.h b/security/nss/lib/ssl/ssl3exthandle.h
index b84bd074c..eaf7f0081 100644
--- a/security/nss/lib/ssl/ssl3exthandle.h
+++ b/security/nss/lib/ssl/ssl3exthandle.h
@@ -119,4 +119,11 @@ SECStatus ssl_SendSupportedGroupsXtn(const sslSocket *ss,
SECStatus ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
+SECStatus ssl_HandleRecordSizeLimitXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ SECItem *data);
+SECStatus ssl_SendRecordSizeLimitXtn(const sslSocket *ss,
+ TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added);
+
#endif
diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c
index 8b323bb05..5ea7cc249 100644
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -158,6 +158,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
* the length of the following encrypted data, and then
* read in the rest of the record into gs->inbuf. */
gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4];
+ gs->hdrLen = SSL3_RECORD_HEADER_LENGTH;
} else {
/* Probably an SSLv2 record header. No need to handle any
* security escapes (gs->hdr[0] & 0x40) as we wouldn't get
@@ -264,8 +265,9 @@ static int
dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
{
int nb;
- int err;
- int rv = 1;
+ PRUint8 contentType;
+ unsigned int headerLen;
+ SECStatus rv;
SSL_TRC(30, ("dtls_GatherData"));
@@ -285,81 +287,97 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
** to 13 (the size of the record header).
*/
if (gs->dtlsPacket.space < MAX_FRAGMENT_LENGTH + 2048 + 13) {
- err = sslBuffer_Grow(&gs->dtlsPacket,
- MAX_FRAGMENT_LENGTH + 2048 + 13);
- if (err) { /* realloc has set error code to no mem. */
- return err;
+ rv = sslBuffer_Grow(&gs->dtlsPacket,
+ MAX_FRAGMENT_LENGTH + 2048 + 13);
+ if (rv != SECSuccess) {
+ return -1; /* Code already set. */
}
}
/* recv() needs to read a full datagram at a time */
nb = ssl_DefRecv(ss, gs->dtlsPacket.buf, gs->dtlsPacket.space, flags);
-
if (nb > 0) {
PRINT_BUF(60, (ss, "raw gather data:", gs->dtlsPacket.buf, nb));
} else if (nb == 0) {
/* EOF */
SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd));
- rv = 0;
- return rv;
+ return 0;
} else /* if (nb < 0) */ {
SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd,
PR_GetError()));
- rv = SECFailure;
- return rv;
+ return -1;
}
gs->dtlsPacket.len = nb;
}
+ contentType = gs->dtlsPacket.buf[gs->dtlsPacketOffset];
+ if (dtls_IsLongHeader(ss->version, contentType)) {
+ headerLen = 13;
+ } else if (contentType == content_application_data) {
+ headerLen = 7;
+ } else if ((contentType & 0xe0) == 0x20) {
+ headerLen = 2;
+ } else {
+ SSL_DBG(("%d: SSL3[%d]: invalid first octet (%d) for DTLS",
+ SSL_GETPID(), ss->fd, contentType));
+ PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE);
+ gs->dtlsPacketOffset = 0;
+ gs->dtlsPacket.len = 0;
+ return -1;
+ }
+
/* At this point we should have >=1 complete records lined up in
* dtlsPacket. Read off the header.
*/
- if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < 13) {
+ if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < headerLen) {
SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet "
"too short to contain header",
SSL_GETPID(), ss->fd));
- PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
gs->dtlsPacketOffset = 0;
gs->dtlsPacket.len = 0;
- rv = SECFailure;
- return rv;
+ return -1;
}
- memcpy(gs->hdr, gs->dtlsPacket.buf + gs->dtlsPacketOffset, 13);
- gs->dtlsPacketOffset += 13;
+ memcpy(gs->hdr, SSL_BUFFER_BASE(&gs->dtlsPacket) + gs->dtlsPacketOffset,
+ headerLen);
+ gs->hdrLen = headerLen;
+ gs->dtlsPacketOffset += headerLen;
/* Have received SSL3 record header in gs->hdr. */
- gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12];
+ if (headerLen == 13) {
+ gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12];
+ } else if (headerLen == 7) {
+ gs->remainder = (gs->hdr[5] << 8) | gs->hdr[6];
+ } else {
+ PORT_Assert(headerLen == 2);
+ gs->remainder = gs->dtlsPacket.len - gs->dtlsPacketOffset;
+ }
if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < gs->remainder) {
SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet too short "
"to contain rest of body",
SSL_GETPID(), ss->fd));
- PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
+ PORT_SetError(PR_WOULD_BLOCK_ERROR);
gs->dtlsPacketOffset = 0;
gs->dtlsPacket.len = 0;
- rv = SECFailure;
- return rv;
+ return -1;
}
/* OK, we have at least one complete packet, copy into inbuf */
- if (gs->remainder > gs->inbuf.space) {
- err = sslBuffer_Grow(&gs->inbuf, gs->remainder);
- if (err) { /* realloc has set error code to no mem. */
- return err;
- }
+ gs->inbuf.len = 0;
+ rv = sslBuffer_Append(&gs->inbuf,
+ SSL_BUFFER_BASE(&gs->dtlsPacket) + gs->dtlsPacketOffset,
+ gs->remainder);
+ if (rv != SECSuccess) {
+ return -1; /* code already set. */
}
-
- SSL_TRC(20, ("%d: SSL3[%d]: dtls gathered record type=%d len=%d",
- SSL_GETPID(), ss->fd, gs->hdr[0], gs->inbuf.len));
-
- memcpy(gs->inbuf.buf, gs->dtlsPacket.buf + gs->dtlsPacketOffset,
- gs->remainder);
- gs->inbuf.len = gs->remainder;
gs->offset = gs->remainder;
gs->dtlsPacketOffset += gs->remainder;
gs->state = GS_INIT;
+ SSL_TRC(20, ("%d: SSL3[%d]: dtls gathered record type=%d len=%d",
+ SSL_GETPID(), ss->fd, contentType, gs->inbuf.len));
return 1;
}
@@ -442,7 +460,11 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
* We need to process it now before we overwrite it with the next
* handshake record.
*/
- rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
+ SSL_DBG(("%d: SSL3[%d]: resuming handshake",
+ SSL_GETPID(), ss->fd));
+ PORT_Assert(!IS_DTLS(ss));
+ rv = ssl3_HandleNonApplicationData(ss, content_handshake,
+ 0, 0, &ss->gs.buf);
} else {
/* State for SSLv2 client hello support. */
ssl2Gather ssl2gs = { PR_FALSE, 0 };
@@ -495,20 +517,14 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
* If it's application data, ss->gs.buf will not be empty upon return.
* If it's a change cipher spec, alert, or handshake message,
* ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
+ *
+ * cText only needs to be valid for this next function call, so
+ * it can borrow gs.hdr.
*/
- cText.type = (SSL3ContentType)ss->gs.hdr[0];
- cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
-
- if (IS_DTLS(ss)) {
- sslSequenceNumber seq_num;
-
- /* DTLS sequence number */
- PORT_Memcpy(&seq_num, &ss->gs.hdr[3], sizeof(seq_num));
- cText.seq_num = PR_ntohll(seq_num);
- }
-
+ cText.hdr = ss->gs.hdr;
+ cText.hdrLen = ss->gs.hdrLen;
cText.buf = &ss->gs.inbuf;
- rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
+ rv = ssl3_HandleRecord(ss, &cText);
}
}
if (rv < 0) {
@@ -520,7 +536,6 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
* completing any renegotiation handshake we may be doing.
*/
PORT_Assert(ss->firstHsDone);
- PORT_Assert(cText.type == content_application_data);
break;
}
diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h
index d1f46db97..8e6cf2745 100644
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -16,7 +16,7 @@ typedef PRUint16 SSL3ProtocolVersion;
/* The TLS 1.3 draft version. Used to avoid negotiating
* between incompatible pre-standard TLS 1.3 drafts.
* TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */
-#define TLS_1_3_DRAFT_VERSION 23
+#define TLS_1_3_DRAFT_VERSION 28
typedef PRUint16 ssl3CipherSuite;
/* The cipher suites are defined in sslproto.h */
diff --git a/security/nss/lib/ssl/sslcert.c b/security/nss/lib/ssl/sslcert.c
index 6cd02e402..1c3ddb0e7 100644
--- a/security/nss/lib/ssl/sslcert.c
+++ b/security/nss/lib/ssl/sslcert.c
@@ -256,7 +256,8 @@ ssl_PopulateKeyPair(sslServerCert *sc, sslKeyPair *keyPair)
/* Get the size of the cert's public key, and remember it. */
sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
- if (sc->serverKeyBits == 0) {
+ if (sc->serverKeyBits == 0 ||
+ (keyType == rsaKey && sc->serverKeyBits > SSL_MAX_RSA_KEY_BITS)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h
index b94d0cc62..518a2b887 100644
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -262,6 +262,8 @@ typedef enum {
SSL_ERROR_TOO_MANY_KEY_UPDATES = (SSL_ERROR_BASE + 171),
SSL_ERROR_HANDSHAKE_FAILED = (SSL_ERROR_BASE + 172),
SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173),
+ SSL_ERROR_RX_MALFORMED_DTLS_ACK = (SSL_ERROR_BASE + 174),
+ SSL_ERROR_DH_KEY_TOO_LONG = (SSL_ERROR_BASE + 175),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index 10d0333d9..a2209e90a 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -121,6 +121,10 @@ typedef enum { SSLAppOpRead = 0,
/* default number of entries in namedGroupPreferences */
#define SSL_NAMED_GROUP_COUNT 31
+/* The maximum DH and RSA bit-length supported. */
+#define SSL_MAX_DH_KEY_BITS 8192
+#define SSL_MAX_RSA_KEY_BITS 8192
+
/* Types and names of elliptic curves used in TLS */
typedef enum {
ec_type_explicitPrime = 1, /* not supported */
@@ -232,6 +236,7 @@ typedef struct sslOptionsStr {
/* If SSL_SetNextProtoNego has been called, then this contains the
* list of supported protocols. */
SECItem nextProtoNego;
+ PRUint16 recordSizeLimit;
PRUint32 maxEarlyDataSize;
unsigned int useSecurity : 1;
@@ -251,7 +256,6 @@ typedef struct sslOptionsStr {
unsigned int enableFalseStart : 1;
unsigned int cbcRandomIV : 1;
unsigned int enableOCSPStapling : 1;
- unsigned int enableNPN : 1;
unsigned int enableALPN : 1;
unsigned int reuseServerECDHEKey : 1;
unsigned int enableFallbackSCSV : 1;
@@ -261,6 +265,7 @@ typedef struct sslOptionsStr {
unsigned int requireDHENamedGroups : 1;
unsigned int enable0RttData : 1;
unsigned int enableTls13CompatMode : 1;
+ unsigned int enableDtlsShortHeader : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -325,9 +330,11 @@ struct sslGatherStr {
** than into buf or inbuf, while in the GS_HEADER state.
** The portion of the SSL record header put here always comes off the wire
** as plaintext, never ciphertext.
- ** For SSL3/TLS, the plaintext portion is 5 bytes long. For DTLS it is 13.
+ ** For SSL3/TLS, the plaintext portion is 5 bytes long. For DTLS it
+ ** varies based on version and header type.
*/
unsigned char hdr[13];
+ unsigned int hdrLen;
/* Buffer for DTLS data read off the wire as a single datagram */
sslBuffer dtlsPacket;
@@ -440,7 +447,7 @@ struct sslSessionIDStr {
*/
SECItem signedCertTimestamps;
- /* The NPN/ALPN value negotiated in the original connection.
+ /* The ALPN value negotiated in the original connection.
* Used for TLS 1.3. */
SECItem alpnSelection;
@@ -780,9 +787,13 @@ struct ssl3StateStr {
#define IS_DTLS(ss) (ss->protocolVariant == ssl_variant_datagram)
typedef struct {
- SSL3ContentType type;
- SSL3ProtocolVersion version;
- sslSequenceNumber seq_num; /* DTLS only */
+ /* |seqNum| eventually contains the reconstructed sequence number. */
+ sslSequenceNumber seqNum;
+ /* The header of the cipherText. */
+ const PRUint8 *hdr;
+ unsigned int hdrLen;
+
+ /* |buf| is the payload of the ciphertext. */
sslBuffer *buf;
} SSL3Ciphertext;
@@ -805,7 +816,7 @@ struct ssl3DHParamsStr {
};
typedef struct SSLWrappedSymWrappingKeyStr {
- PRUint8 wrappedSymmetricWrappingkey[512];
+ PRUint8 wrappedSymmetricWrappingkey[SSL_MAX_RSA_KEY_BITS / 8];
CK_MECHANISM_TYPE symWrapMechanism;
/* unwrapped symmetric wrapping key uses this mechanism */
CK_MECHANISM_TYPE asymWrapMechanism;
@@ -1375,8 +1386,11 @@ SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type);
/*
* input into the SSL3 machinery from the actualy network reading code
*/
-SECStatus ssl3_HandleRecord(
- sslSocket *ss, SSL3Ciphertext *cipher, sslBuffer *out);
+SECStatus ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cipher);
+SECStatus ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType,
+ DTLSEpoch epoch,
+ sslSequenceNumber seqNum,
+ sslBuffer *databuf);
SECStatus ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize);
int ssl3_GatherAppDataRecord(sslSocket *ss, int flags);
@@ -1537,8 +1551,8 @@ SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName,
PK11SymKey **encKey, PK11SymKey **macKey);
void ssl_ResetSelfEncryptKeys();
-extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data,
- unsigned int length);
+extern SECStatus ssl3_ValidateAppProtocol(const unsigned char *data,
+ unsigned int length);
/* Construct a new NSPR socket for the app to use */
extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd);
@@ -1636,6 +1650,9 @@ SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme);
KeyType ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme);
SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes);
+SECStatus ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
+ SSL3ContentType contentType, sslBuffer *wrBuf,
+ PRBool *needsLength);
/* Pull in DTLS functions */
#include "dtlscon.h"
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index f09ec067c..a1d389214 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -791,7 +791,7 @@ tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
spec = ss->ssl3.cwSpec;
margin = spec->cipherDef->max_records / 4;
}
- seqNum = spec->seqNum;
+ seqNum = spec->nextSeqNum;
keyUpdate = seqNum > spec->cipherDef->max_records - margin;
ssl_ReleaseSpecReadLock(ss);
if (!keyUpdate) {
@@ -922,21 +922,30 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
*/
if (!ss->firstHsDone) {
PRBool allowEarlySend = PR_FALSE;
+ PRBool firstClientWrite = PR_FALSE;
ssl_Get1stHandshakeLock(ss);
- if (ss->opt.enableFalseStart ||
- (ss->opt.enable0RttData && !ss->sec.isServer)) {
+ /* The client can sometimes send before the handshake is fully
+ * complete. In TLS 1.2: false start; in TLS 1.3: 0-RTT. */
+ if (!ss->sec.isServer &&
+ (ss->opt.enableFalseStart || ss->opt.enable0RttData)) {
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. */
zeroRtt = ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
allowEarlySend = ss->ssl3.hs.canFalseStart || zeroRtt;
+ firstClientWrite = ss->ssl3.hs.ws == idle_handshake;
ssl_ReleaseSSL3HandshakeLock(ss);
}
if (!allowEarlySend && ss->handshake) {
rv = ssl_Do1stHandshake(ss);
}
+ if (firstClientWrite) {
+ /* Wait until after sending ClientHello and double-check 0-RTT. */
+ ssl_GetSSL3HandshakeLock(ss);
+ zeroRtt = ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ }
ssl_Release1stHandshakeLock(ss);
}
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index e08d5e232..33595ffae 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -55,6 +55,7 @@ static const sslSocketOps ssl_secure_ops = { /* SSL. */
static sslOptions ssl_defaults = {
.nextProtoNego = { siBuffer, NULL, 0 },
.maxEarlyDataSize = 1 << 16,
+ .recordSizeLimit = MAX_FRAGMENT_LENGTH + 1,
.useSecurity = PR_TRUE,
.useSocks = PR_FALSE,
.requestCertificate = PR_FALSE,
@@ -72,7 +73,6 @@ static sslOptions ssl_defaults = {
.enableFalseStart = PR_FALSE,
.cbcRandomIV = PR_TRUE,
.enableOCSPStapling = PR_FALSE,
- .enableNPN = PR_FALSE,
.enableALPN = PR_TRUE,
.reuseServerECDHEKey = PR_TRUE,
.enableFallbackSCSV = PR_FALSE,
@@ -81,7 +81,8 @@ static sslOptions ssl_defaults = {
.enableSignedCertTimestamps = PR_FALSE,
.requireDHENamedGroups = PR_FALSE,
.enable0RttData = PR_FALSE,
- .enableTls13CompatMode = PR_FALSE
+ .enableTls13CompatMode = PR_FALSE,
+ .enableDtlsShortHeader = PR_FALSE
};
/*
@@ -803,10 +804,23 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
ss->opt.enable0RttData = val;
break;
+ case SSL_RECORD_SIZE_LIMIT:
+ if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ } else {
+ ss->opt.recordSizeLimit = val;
+ }
+ break;
+
case SSL_ENABLE_TLS13_COMPAT_MODE:
ss->opt.enableTls13CompatMode = val;
break;
+ case SSL_ENABLE_DTLS_SHORT_HEADER:
+ ss->opt.enableDtlsShortHeader = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -914,7 +928,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
val = ss->opt.enableOCSPStapling;
break;
case SSL_ENABLE_NPN:
- val = ss->opt.enableNPN;
+ val = PR_FALSE;
break;
case SSL_ENABLE_ALPN:
val = ss->opt.enableALPN;
@@ -940,9 +954,15 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_0RTT_DATA:
val = ss->opt.enable0RttData;
break;
+ case SSL_RECORD_SIZE_LIMIT:
+ val = ss->opt.recordSizeLimit;
+ break;
case SSL_ENABLE_TLS13_COMPAT_MODE:
val = ss->opt.enableTls13CompatMode;
break;
+ case SSL_ENABLE_DTLS_SHORT_HEADER:
+ val = ss->opt.enableDtlsShortHeader;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1037,7 +1057,7 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
val = ssl_defaults.enableOCSPStapling;
break;
case SSL_ENABLE_NPN:
- val = ssl_defaults.enableNPN;
+ val = PR_FALSE;
break;
case SSL_ENABLE_ALPN:
val = ssl_defaults.enableALPN;
@@ -1060,9 +1080,15 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
case SSL_ENABLE_0RTT_DATA:
val = ssl_defaults.enable0RttData;
break;
+ case SSL_RECORD_SIZE_LIMIT:
+ val = ssl_defaults.recordSizeLimit;
+ break;
case SSL_ENABLE_TLS13_COMPAT_MODE:
val = ssl_defaults.enableTls13CompatMode;
break;
+ case SSL_ENABLE_DTLS_SHORT_HEADER:
+ val = ssl_defaults.enableDtlsShortHeader;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -1242,10 +1268,22 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
ssl_defaults.enable0RttData = val;
break;
+ case SSL_RECORD_SIZE_LIMIT:
+ if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ ssl_defaults.recordSizeLimit = val;
+ break;
+
case SSL_ENABLE_TLS13_COMPAT_MODE:
ssl_defaults.enableTls13CompatMode = val;
break;
+ case SSL_ENABLE_DTLS_SHORT_HEADER:
+ ssl_defaults.enableDtlsShortHeader = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -1895,10 +1933,7 @@ DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd)
}
/* SSL_SetNextProtoCallback is used to select an application protocol
- * for ALPN and NPN. For ALPN, this runs on the server; for NPN it
- * runs on the client. */
-/* Note: The ALPN version doesn't allow for the use of a default, setting a
- * status of SSL_NEXT_PROTO_NO_OVERLAP is treated as a failure. */
+ * for ALPN. */
SECStatus
SSL_SetNextProtoCallback(PRFileDesc *fd, SSLNextProtoCallback callback,
void *arg)
@@ -1919,7 +1954,7 @@ SSL_SetNextProtoCallback(PRFileDesc *fd, SSLNextProtoCallback callback,
return SECSuccess;
}
-/* ssl_NextProtoNegoCallback is set as an ALPN/NPN callback when
+/* ssl_NextProtoNegoCallback is set as an ALPN callback when
* SSL_SetNextProtoNego is used.
*/
static SECStatus
@@ -1929,7 +1964,6 @@ ssl_NextProtoNegoCallback(void *arg, PRFileDesc *fd,
unsigned int protoMaxLen)
{
unsigned int i, j;
- const unsigned char *result;
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
@@ -1937,37 +1971,29 @@ ssl_NextProtoNegoCallback(void *arg, PRFileDesc *fd,
SSL_GETPID(), fd));
return SECFailure;
}
+ PORT_Assert(protoMaxLen <= 255);
+ if (protoMaxLen > 255) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
- /* For each protocol in server preference, see if we support it. */
- for (i = 0; i < protos_len;) {
- for (j = 0; j < ss->opt.nextProtoNego.len;) {
+ /* For each protocol in client preference, see if we support it. */
+ for (j = 0; j < ss->opt.nextProtoNego.len;) {
+ for (i = 0; i < protos_len;) {
if (protos[i] == ss->opt.nextProtoNego.data[j] &&
PORT_Memcmp(&protos[i + 1], &ss->opt.nextProtoNego.data[j + 1],
protos[i]) == 0) {
/* We found a match. */
- ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
- result = &protos[i];
- goto found;
+ const unsigned char *result = &protos[i];
+ memcpy(protoOut, result + 1, result[0]);
+ *protoOutLen = result[0];
+ return SECSuccess;
}
- j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j];
+ i += 1 + (unsigned int)protos[i];
}
- i += 1 + (unsigned int)protos[i];
+ j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j];
}
- /* The other side supports the extension, and either doesn't have any
- * protocols configured, or none of its options match ours. In this case we
- * request our favoured protocol. */
- /* This will be treated as a failure for ALPN. */
- ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP;
- result = ss->opt.nextProtoNego.data;
-
-found:
- if (protoMaxLen < result[0]) {
- PORT_SetError(SEC_ERROR_OUTPUT_LEN);
- return SECFailure;
- }
- memcpy(protoOut, result + 1, result[0]);
- *protoOutLen = result[0];
return SECSuccess;
}
@@ -1976,8 +2002,6 @@ SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data,
unsigned int length)
{
sslSocket *ss;
- SECStatus rv;
- SECItem dataItem = { siBuffer, (unsigned char *)data, length };
ss = ssl_FindSocket(fd);
if (!ss) {
@@ -1986,17 +2010,22 @@ SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data,
return SECFailure;
}
- if (ssl3_ValidateNextProtoNego(data, length) != SECSuccess)
+ if (ssl3_ValidateAppProtocol(data, length) != SECSuccess) {
return SECFailure;
+ }
+ /* NPN required that the client's fallback protocol is first in the
+ * list. However, ALPN sends protocols in preference order. So move the
+ * first protocol to the end of the list. */
ssl_GetSSL3HandshakeLock(ss);
SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
- rv = SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &dataItem);
+ SECITEM_AllocItem(NULL, &ss->opt.nextProtoNego, length);
+ size_t firstLen = data[0] + 1;
+ /* firstLen <= length is ensured by ssl3_ValidateAppProtocol. */
+ PORT_Memcpy(ss->opt.nextProtoNego.data + (length - firstLen), data, firstLen);
+ PORT_Memcpy(ss->opt.nextProtoNego.data, data + firstLen, length - firstLen);
ssl_ReleaseSSL3HandshakeLock(ss);
- if (rv != SECSuccess)
- return rv;
-
return SSL_SetNextProtoCallback(fd, ssl_NextProtoNegoCallback, NULL);
}
@@ -3034,26 +3063,27 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
} else { /* handshaking as server */
new_flags |= PR_POLL_READ;
}
- } else
+ } else if (ss->lastWriteBlocked) {
/* First handshake is in progress */
- if (ss->lastWriteBlocked) {
if (new_flags & PR_POLL_READ) {
/* The caller is waiting for data to be received,
** but the initial handshake is blocked on write, or the
** client's first handshake record has not been written.
** The code should select on write, not read.
*/
- new_flags ^= PR_POLL_READ; /* don't select on read. */
+ new_flags &= ~PR_POLL_READ; /* don't select on read. */
new_flags |= PR_POLL_WRITE; /* do select on write. */
}
} else if (new_flags & PR_POLL_WRITE) {
/* The caller is trying to write, but the handshake is
** blocked waiting for data to read, and the first
** handshake has been sent. So do NOT to poll on write
- ** unless we did false start.
+ ** unless we did false start or we are doing 0-RTT.
*/
- if (!ss->ssl3.hs.canFalseStart) {
- new_flags ^= PR_POLL_WRITE; /* don't select on write. */
+ if (!(ss->ssl3.hs.canFalseStart ||
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_sent ||
+ ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) {
+ new_flags &= ~PR_POLL_WRITE; /* don't select on write. */
}
new_flags |= PR_POLL_READ; /* do select on read. */
}
@@ -3093,6 +3123,9 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
}
}
+ SSL_TRC(20, ("%d: SSL[%d]: ssl_Poll flags %x -> %x",
+ SSL_GETPID(), fd, how_flags, new_flags));
+
if (new_flags && (fd->lower->methods->poll != NULL)) {
PRInt16 lower_out_flags = 0;
PRInt16 lower_new_flags;
diff --git a/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c
index 26c3eb546..7833eeab6 100644
--- a/security/nss/lib/ssl/sslspec.c
+++ b/security/nss/lib/ssl/sslspec.c
@@ -143,6 +143,7 @@ ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction)
spec->refCt = 1;
spec->version = ss->version;
spec->direction = direction;
+ spec->recordSizeLimit = MAX_FRAGMENT_LENGTH;
SSL_TRC(10, ("%d: SSL[%d]: new %s spec %d ct=%d",
SSL_GETPID(), ss->fd, SPEC_DIR(spec), spec,
spec->refCt));
diff --git a/security/nss/lib/ssl/sslspec.h b/security/nss/lib/ssl/sslspec.h
index 729ac1006..b25601755 100644
--- a/security/nss/lib/ssl/sslspec.h
+++ b/security/nss/lib/ssl/sslspec.h
@@ -162,12 +162,18 @@ struct ssl3CipherSpecStr {
DTLSEpoch epoch;
const char *phase;
- sslSequenceNumber seqNum;
+
+ /* The next sequence number to be sent or received. */
+ sslSequenceNumber nextSeqNum;
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;
+ /* The maximum plaintext length. This differs from the configured or
+ * negotiated value for TLS 1.3; it is reduced by one to account for the
+ * content type octet. */
+ PRUint16 recordSizeLimit;
};
typedef void (*sslCipherSpecChangedFunc)(void *arg,
diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h
index e2b80fb43..bb1bec7a3 100644
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -432,6 +432,7 @@ typedef enum {
ssl_signed_cert_timestamp_xtn = 18,
ssl_padding_xtn = 21,
ssl_extended_master_secret_xtn = 23,
+ ssl_record_size_limit_xtn = 28,
ssl_session_ticket_xtn = 35,
/* 40 was used in draft versions of TLS 1.3; it is now reserved. */
ssl_tls13_pre_shared_key_xtn = 41,
@@ -454,7 +455,7 @@ typedef enum {
/* SSL_MAX_EXTENSIONS includes the maximum number of extensions that are
* supported for any single message type. That is, a ClientHello; ServerHello
* and TLS 1.3 NewSessionTicket and HelloRetryRequest extensions have fewer. */
-#define SSL_MAX_EXTENSIONS 20
+#define SSL_MAX_EXTENSIONS 21
/* Deprecated */
typedef enum {
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)
diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h
index 1aaffb651..f35b20023 100644
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -28,6 +28,7 @@ typedef enum {
SECStatus tls13_UnprotectRecord(
sslSocket *ss, ssl3CipherSpec *spec,
SSL3Ciphertext *cText, sslBuffer *plaintext,
+ SSL3ContentType *innerType,
SSL3AlertDescription *alert);
#if defined(WIN32)
@@ -101,6 +102,7 @@ PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
+SECStatus tls13_ClientReadSupportedVersion(sslSocket *ss);
SECStatus tls13_NegotiateVersion(sslSocket *ss,
const TLSExtension *supported_versions);
diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c
index 899f23827..1ab8a8e59 100644
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -860,12 +860,12 @@ tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
if (xtnData->cookie.len == 0) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
return SECFailure;
}
if (data->len) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
return SECFailure;
}