diff options
Diffstat (limited to 'security/nss/lib/ssl')
25 files changed, 958 insertions, 532 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index d3f0875442..f01d165833 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 aba0f62ab8..de6cb47ca2 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 bf14d3bd2e..ca48ef3638 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 2f335f9247..a82295c668 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 d094380f8c..45fc069b97 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 25aabbaa21..ecc4f95066 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 2593bbaccb..466fc296ff 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 913a14f637..f8b9a94000 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 5a50779989..9b6c719f88 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 d0f75a599a..6d77c7459e 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 e6388945e1..d1f286dc3c 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 b84bd074c0..eaf7f0081c 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 8b323bb054..5ea7cc249e 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 d1f46db971..8e6cf27456 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 6cd02e4025..1c3ddb0e75 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 b94d0cc62e..518a2b8875 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 10d0333d9e..a2209e90a1 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 f09ec067ce..a1d3892145 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 e08d5e2326..33595ffae9 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 26c3eb5462..7833eeab69 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 729ac1006f..b256017553 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 e2b80fb436..bb1bec7a3d 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 c06acc83a9..4d9170fb01 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 1aaffb651d..f35b20023d 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 899f238276..1ab8a8e597 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; } |