diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-02-23 11:04:39 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-06-05 22:24:08 +0200 |
commit | e10349ab8dda8a3f11be6aa19f2b6e29fe814044 (patch) | |
tree | 1a9b078b06a76af06839d407b7267880890afccc /security/nss/lib/ssl | |
parent | 75b3dd4cbffb6e4534128278300ed6c8a3ab7506 (diff) | |
download | UXP-e10349ab8dda8a3f11be6aa19f2b6e29fe814044.tar UXP-e10349ab8dda8a3f11be6aa19f2b6e29fe814044.tar.gz UXP-e10349ab8dda8a3f11be6aa19f2b6e29fe814044.tar.lz UXP-e10349ab8dda8a3f11be6aa19f2b6e29fe814044.tar.xz UXP-e10349ab8dda8a3f11be6aa19f2b6e29fe814044.zip |
Update NSS to 3.35-RTM
Diffstat (limited to 'security/nss/lib/ssl')
48 files changed, 9107 insertions, 6309 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index b73fb6bd0..c95fe661a 100644 --- a/security/nss/lib/ssl/SSLerrs.h +++ b/security/nss/lib/ssl/SSLerrs.h @@ -473,8 +473,7 @@ ER3(SSL_ERROR_RX_MALFORMED_PRE_SHARED_KEY, (SSL_ERROR_BASE + 147), ER3(SSL_ERROR_RX_MALFORMED_EARLY_DATA, (SSL_ERROR_BASE + 148), "SSL received an invalid EarlyData extension.") -ER3(SSL_ERROR_END_OF_EARLY_DATA_ALERT, (SSL_ERROR_BASE + 149), - "SSL received an unexpected end of early data alert.") +UNUSED_ERROR(149) ER3(SSL_ERROR_MISSING_ALPN_EXTENSION, (SSL_ERROR_BASE + 150), "SSL didn't receive an expected ALPN extension.") @@ -511,3 +510,33 @@ ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160), ER3(SSL_ERROR_TOO_MUCH_EARLY_DATA, (SSL_ERROR_BASE + 161), "SSL received more early data than permitted.") + +ER3(SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA, (SSL_ERROR_BASE + 162), + "SSL received an unexpected End of Early Data message.") + +ER3(SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA, (SSL_ERROR_BASE + 163), + "SSL received a malformed End of Early Data message.") + +ER3(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, (SSL_ERROR_BASE + 164), + "An experimental API was called, but not supported.") + +ER3(SSL_ERROR_APPLICATION_ABORT, (SSL_ERROR_BASE + 165), + "SSL handshake aborted by the application.") + +ER3(SSL_ERROR_APP_CALLBACK_ERROR, (SSL_ERROR_BASE + 166), + "An application callback produced an invalid response.") + +ER3(SSL_ERROR_NO_TIMERS_ERROR, (SSL_ERROR_BASE + 167), + "No timers are currently running.") + +ER3(SSL_ERROR_MISSING_COOKIE_EXTENSION, (SSL_ERROR_BASE + 168), + "A second ClientHello was received without a cookie extension.") + +ER3(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, (SSL_ERROR_BASE + 169), + "SSL received an unexpected key update message.") + +ER3(SSL_ERROR_RX_MALFORMED_KEY_UPDATE, (SSL_ERROR_BASE + 170), + "SSL received a malformed key update message.") + +ER3(SSL_ERROR_TOO_MANY_KEY_UPDATES, (SSL_ERROR_BASE + 171), + "SSL attempted too many key updates.") diff --git a/security/nss/lib/ssl/authcert.c b/security/nss/lib/ssl/authcert.c index 88c7c084a..2765c8342 100644 --- a/security/nss/lib/ssl/authcert.c +++ b/security/nss/lib/ssl/authcert.c @@ -17,6 +17,7 @@ #include "nss.h" #include "ssl.h" #include "pk11func.h" /* for PK11_ function calls */ +#include "sslimpl.h" /* * This callback used by SSL to pull client sertificate upon @@ -63,7 +64,7 @@ NSS_GetClientAuthData(void *arg, if (!cert) continue; /* Only check unexpired certs */ - if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != + if (CERT_CheckCertValidTimes(cert, ssl_TimeUsec(), PR_TRUE) != secCertTimeValid) { CERT_DestroyCertificate(cert); continue; diff --git a/security/nss/lib/ssl/config.mk b/security/nss/lib/ssl/config.mk index c8b053cab..d13613f78 100644 --- a/security/nss/lib/ssl/config.mk +++ b/security/nss/lib/ssl/config.mk @@ -57,11 +57,6 @@ endif endif -ifdef NSS_SSL_ENABLE_ZLIB -DEFINES += -DNSS_SSL_ENABLE_ZLIB -include $(CORE_DEPTH)/coreconf/zlib.mk -endif - ifdef NSS_DISABLE_TLS_1_3 DEFINES += -DNSS_DISABLE_TLS_1_3 endif diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c new file mode 100644 index 000000000..aba0f62ab --- /dev/null +++ b/security/nss/lib/ssl/dtls13con.c @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * DTLS 1.3 Protocol + */ + +#include "ssl.h" +#include "sslimpl.h" +#include "sslproto.h" + +/* 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 + * sender. We use the same structure on the receiver for convenience + * but the only value we actually use is |record|. + */ +typedef struct DTLSHandshakeRecordEntryStr { + PRCList link; + PRUint16 messageSeq; /* The handshake message sequence number. */ + PRUint32 offset; /* The offset into the handshake message. */ + PRUint32 length; /* The length of the fragment. */ + sslSequenceNumber record; /* The record (includes epoch). */ + PRBool acked; /* Has this packet been acked. */ +} DTLSHandshakeRecordEntry; + +/* Combine the epoch and sequence number into a single value. */ +static inline sslSequenceNumber +dtls_CombineSequenceNumber(DTLSEpoch epoch, sslSequenceNumber seqNum) +{ + PORT_Assert(seqNum <= RECORD_SEQ_MAX); + return ((sslSequenceNumber)epoch << 48) | seqNum; +} + +SECStatus +dtls13_RememberFragment(sslSocket *ss, + PRCList *list, + PRUint32 sequence, + PRUint32 offset, + PRUint32 length, + DTLSEpoch epoch, + sslSequenceNumber record) +{ + DTLSHandshakeRecordEntry *entry; + + PORT_Assert(IS_DTLS(ss)); + /* We should never send an empty fragment with offset > 0. */ + PORT_Assert(length || !offset); + + if (!tls13_MaybeTls13(ss)) { + return SECSuccess; + } + + SSL_TRC(20, ("%d: SSL3[%d]: %s remembering %s record=%llx msg=%d offset=%d", + SSL_GETPID(), ss->fd, + SSL_ROLE(ss), + list == &ss->ssl3.hs.dtlsSentHandshake ? "sent" : "received", + dtls_CombineSequenceNumber(epoch, record), sequence, offset)); + + entry = PORT_ZAlloc(sizeof(DTLSHandshakeRecordEntry)); + if (!entry) { + return SECFailure; + } + + entry->messageSeq = sequence; + entry->offset = offset; + entry->length = length; + entry->record = dtls_CombineSequenceNumber(epoch, record); + entry->acked = PR_FALSE; + + PR_APPEND_LINK(&entry->link, list); + + return SECSuccess; +} + +SECStatus +dtls13_SendAck(sslSocket *ss) +{ + sslBuffer buf = SSL_BUFFER_EMPTY; + SECStatus rv = SECSuccess; + PRCList *cursor; + PRInt32 sent; + + SSL_TRC(10, ("%d: SSL3[%d]: Sending ACK", + SSL_GETPID(), ss->fd)); + + for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsRcvdHandshake); + cursor != &ss->ssl3.hs.dtlsRcvdHandshake; + cursor = PR_NEXT_LINK(cursor)) { + DTLSHandshakeRecordEntry *entry = (DTLSHandshakeRecordEntry *)cursor; + + SSL_TRC(10, ("%d: SSL3[%d]: ACK for record=%llx", + SSL_GETPID(), ss->fd, entry->record)); + rv = sslBuffer_AppendNumber(&buf, entry->record, 8); + if (rv != SECSuccess) { + goto loser; + } + } + + ssl_GetXmitBufLock(ss); + sent = ssl3_SendRecord(ss, NULL, content_ack, + buf.buf, buf.len, 0); + ssl_ReleaseXmitBufLock(ss); + if (sent != buf.len) { + rv = SECFailure; + if (sent != -1) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + } + } + +loser: + sslBuffer_Clear(&buf); + return rv; +} + +void +dtls13_SendAckCb(sslSocket *ss) +{ + if (!IS_DTLS(ss)) { + return; + } + (void)dtls13_SendAck(ss); +} + +/* Zero length messages are very simple to check. */ +static PRBool +dtls_IsEmptyMessageAcknowledged(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset) +{ + PRCList *cursor; + + for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsSentHandshake); + cursor != &ss->ssl3.hs.dtlsSentHandshake; + cursor = PR_NEXT_LINK(cursor)) { + DTLSHandshakeRecordEntry *entry = (DTLSHandshakeRecordEntry *)cursor; + if (!entry->acked || msgSeq != entry->messageSeq) { + continue; + } + /* Empty fragments are always offset 0. */ + if (entry->length == 0) { + PORT_Assert(!entry->offset); + return PR_TRUE; + } + } + return PR_FALSE; +} + +/* Take a range starting at |*start| and that start forwards based on the + * contents of the acknowedgement in |entry|. Only move if the acknowledged + * range overlaps |*start|. Return PR_TRUE if it moves. */ +static PRBool +dtls_MoveUnackedStartForward(DTLSHandshakeRecordEntry *entry, PRUint32 *start) +{ + /* This entry starts too late. */ + if (*start < entry->offset) { + return PR_FALSE; + } + /* This entry ends too early. */ + if (*start >= entry->offset + entry->length) { + return PR_FALSE; + } + *start = entry->offset + entry->length; + return PR_TRUE; +} + +/* Take a range ending at |*end| and move that end backwards based on the + * contents of the acknowedgement in |entry|. Only move if the acknowledged + * range overlaps |*end|. Return PR_TRUE if it moves. */ +static PRBool +dtls_MoveUnackedEndBackward(DTLSHandshakeRecordEntry *entry, PRUint32 *end) +{ + /* This entry ends too early. */ + if (*end > entry->offset + entry->length) { + return PR_FALSE; + } + /* This entry starts too late. */ + if (*end <= entry->offset) { + return PR_FALSE; + } + *end = entry->offset; + return PR_TRUE; +} + +/* Get the next contiguous range of unacknowledged bytes from the handshake + * message identified by |msgSeq|. The search starts at the offset in |offset|. + * |len| contains the full length of the message. + * + * Returns PR_TRUE if there is an unacknowledged range. In this case, values at + * |start| and |end| are modified to contain the range. + * + * Returns PR_FALSE if the message is entirely acknowledged from |offset| + * onwards. + */ +PRBool +dtls_NextUnackedRange(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset, + PRUint32 len, PRUint32 *startOut, PRUint32 *endOut) +{ + PRCList *cur_p; + PRBool done = PR_FALSE; + DTLSHandshakeRecordEntry *entry; + PRUint32 start; + PRUint32 end; + + PORT_Assert(IS_DTLS(ss)); + + *startOut = offset; + *endOut = len; + if (!tls13_MaybeTls13(ss)) { + return PR_TRUE; + } + + /* The message is empty. Use a simple search. */ + if (!len) { + PORT_Assert(!offset); + return !dtls_IsEmptyMessageAcknowledged(ss, msgSeq, offset); + } + + /* This iterates multiple times over the acknowledgments and only terminates + * when an entire iteration happens without start or end moving. If that + * happens without start and end crossing each other, then there is a range + * of unacknowledged data. If they meet, then the message is fully + * acknowledged. */ + start = offset; + end = len; + while (!done) { + done = PR_TRUE; + for (cur_p = PR_LIST_HEAD(&ss->ssl3.hs.dtlsSentHandshake); + cur_p != &ss->ssl3.hs.dtlsSentHandshake; + cur_p = PR_NEXT_LINK(cur_p)) { + entry = (DTLSHandshakeRecordEntry *)cur_p; + if (!entry->acked || msgSeq != entry->messageSeq) { + continue; + } + + if (dtls_MoveUnackedStartForward(entry, &start) || + dtls_MoveUnackedEndBackward(entry, &end)) { + if (start >= end) { + /* The message is all acknowledged. */ + return PR_FALSE; + } + /* Start over again and keep going until we don't move either + * start or end. */ + done = PR_FALSE; + break; + } + } + } + PORT_Assert(start < end); + + *startOut = start; + *endOut = end; + return PR_TRUE; +} + +SECStatus +dtls13_SetupAcks(sslSocket *ss) +{ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + if (ss->ssl3.hs.endOfFlight) { + dtls_CancelTimer(ss, ss->ssl3.hs.ackTimer); + + if (ss->ssl3.hs.ws == idle_handshake && ss->sec.isServer) { + SSL_TRC(10, ("%d: SSL3[%d]: dtls_HandleHandshake, sending ACK", + SSL_GETPID(), ss->fd)); + return dtls13_SendAck(ss); + } + return SECSuccess; + } + + /* We need to send an ACK. */ + if (!ss->ssl3.hs.ackTimer->cb) { + /* We're not armed, so arm. */ + SSL_TRC(10, ("%d: SSL3[%d]: dtls_HandleHandshake, arming ack timer", + SSL_GETPID(), ss->fd)); + return dtls_StartTimer(ss, ss->ssl3.hs.ackTimer, + DTLS_RETRANSMIT_INITIAL_MS / 4, + dtls13_SendAckCb); + } + /* The ack timer is already armed, so just return. */ + return SECSuccess; +} + +/* + * Special case processing for out-of-epoch records. + * This can only handle ACKs for now and everything else generates + * an error. In future, may also handle KeyUpdate. + * + * The error checking here is as follows: + * + * - If it's not encrypted, out of epoch stuff is just discarded. + * - If it's encrypted, out of epoch stuff causes an error. + */ +SECStatus +dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec, + SSL3ContentType rType, + sslBuffer *databuf) +{ + SECStatus rv; + sslBuffer buf = *databuf; + + databuf->len = 0; /* Discard data whatever happens. */ + PORT_Assert(IS_DTLS(ss)); + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + /* Can't happen, but double check. */ + if (!IS_DTLS(ss) || (ss->version < SSL_LIBRARY_VERSION_TLS_1_3)) { + tls13_FatalError(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + return SECFailure; + } + SSL_TRC(10, ("%d: DTLS13[%d]: handle out of epoch record: type=%d", SSL_GETPID(), + ss->fd, rType)); + + if (rType == content_ack) { + ssl_GetSSL3HandshakeLock(ss); + rv = dtls13_HandleAck(ss, &buf); + ssl_ReleaseSSL3HandshakeLock(ss); + PORT_Assert(databuf->len == 0); + return rv; + } + + switch (spec->epoch) { + case TrafficKeyClearText: + /* Drop. */ + return SECSuccess; + + case TrafficKeyHandshake: + /* Drop out of order handshake messages, but if we are the + * server, we might have processed the client's Finished and + * moved on to application data keys, but the client has + * retransmitted Finished (e.g., because our ACK got lost.) + * We just retransmit the previous Finished to let the client + * complete. */ + if (rType == content_handshake) { + if ((ss->sec.isServer) && + (ss->ssl3.hs.ws == idle_handshake)) { + PORT_Assert(dtls_TimerActive(ss, ss->ssl3.hs.hdTimer)); + return dtls13_SendAck(ss); + } + return SECSuccess; + } + + /* This isn't a handshake record, so shouldn't be encrypted + * under the handshake key. */ + break; + + default: + /* Any other epoch is forbidden. */ + break; + } + + SSL_TRC(10, ("%d: SSL3[%d]: unexpected out of epoch record type %d", SSL_GETPID(), + ss->fd, rType)); + + (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE); + return SECFailure; +} + +SECStatus +dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf) +{ + PRUint8 *b = databuf->buf; + PRUint32 l = databuf->len; + SECStatus rv; + + /* Ensure we don't loop. */ + databuf->len = 0; + + PORT_Assert(IS_DTLS(ss)); + if (!tls13_MaybeTls13(ss)) { + tls13_FatalError(ss, SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, illegal_parameter); + return SECSuccess; + } + + SSL_TRC(10, ("%d: SSL3[%d]: Handling ACK", SSL_GETPID(), ss->fd)); + while (l > 0) { + PRUint64 seq; + PRCList *cursor; + + rv = ssl3_ConsumeHandshakeNumber64(ss, &seq, 8, &b, &l); + if (rv != SECSuccess) { + return SECFailure; + } + + for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsSentHandshake); + cursor != &ss->ssl3.hs.dtlsSentHandshake; + cursor = PR_NEXT_LINK(cursor)) { + DTLSHandshakeRecordEntry *entry = (DTLSHandshakeRecordEntry *)cursor; + + if (entry->record == seq) { + SSL_TRC(10, ( + "%d: SSL3[%d]: Marking record=%llx message %d offset %d length=%d as ACKed", + SSL_GETPID(), ss->fd, + seq, entry->messageSeq, entry->offset, entry->length)); + entry->acked = PR_TRUE; + } + } + } + + /* Try to flush. */ + rv = dtls_TransmitMessageFlight(ss); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Reset the retransmit timer. */ + if (ss->ssl3.hs.rtTimer->cb) { + (void)dtls_RestartTimer(ss, ss->ssl3.hs.rtTimer); + } + + /* If there are no more messages to send, cleanup. */ + if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.lastMessageFlight)) { + SSL_TRC(10, ("%d: SSL3[%d]: No more unacked handshake messages", + SSL_GETPID(), ss->fd)); + + dtls_CancelTimer(ss, ss->ssl3.hs.rtTimer); + ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL); + /* If the handshake is finished, and we're the client then + * also clean up the handshake read cipher spec. Any ACKs + * we receive will be with the application data cipher spec. + * The server needs to keep the handshake cipher spec around + * for the holddown period to process retransmitted Finisheds. + */ + if (!ss->sec.isServer && (ss->ssl3.hs.ws == idle_handshake)) { + ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, + TrafficKeyHandshake); + } + } + return SECSuccess; +} + +/* Clean up the read timer for the handshake cipher suites on the + * server. + * + * In DTLS 1.3, the client speaks last (Finished), and will retransmit + * until the server ACKs that message (using application data cipher + * suites). I.e., + * + * - The client uses the retransmit timer and retransmits using the + * saved write handshake cipher suite. + * - The server keeps the saved read handshake cipher suite around + * for the holddown period in case it needs to read the Finished. + * + * After the holddown period, the server assumes the client is happy + * and discards the handshake read cipher suite. + */ +void +dtls13_HolddownTimerCb(sslSocket *ss) +{ + SSL_TRC(10, ("%d: SSL3[%d]: holddown timer fired", + SSL_GETPID(), ss->fd)); + ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyHandshake); + ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL); +} diff --git a/security/nss/lib/ssl/dtls13con.h b/security/nss/lib/ssl/dtls13con.h new file mode 100644 index 000000000..bf14d3bd2 --- /dev/null +++ b/security/nss/lib/ssl/dtls13con.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __dtls13con_h_ +#define __dtls13con_h_ + +SECStatus dtls13_RememberFragment(sslSocket *ss, PRCList *list, + PRUint32 sequence, PRUint32 offset, + PRUint32 length, DTLSEpoch epoch, + sslSequenceNumber record); +PRBool dtls_NextUnackedRange(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset, + PRUint32 len, PRUint32 *startOut, PRUint32 *endOut); +SECStatus dtls13_SetupAcks(sslSocket *ss); +SECStatus dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec, + SSL3ContentType rType, + sslBuffer *databuf); +SECStatus dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf); + +SECStatus dtls13_SendAck(sslSocket *ss); +void dtls13_SendAckCb(sslSocket *ss); +void dtls13_HolddownTimerCb(sslSocket *ss); +void dtls_ReceivedFirstMessageInFlight(sslSocket *ss); + +#endif diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c index fbd1779db..2f335f924 100644 --- a/security/nss/lib/ssl/dtlscon.c +++ b/security/nss/lib/ssl/dtlscon.c @@ -10,16 +10,17 @@ #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" +#include "dtls13con.h" #ifndef PR_ARRAY_SIZE #define PR_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif -static SECStatus dtls_TransmitMessageFlight(sslSocket *ss); static SECStatus dtls_StartRetransmitTimer(sslSocket *ss); static void dtls_RetransmitTimerExpiredCb(sslSocket *ss); static SECStatus dtls_SendSavedWriteData(sslSocket *ss); static void dtls_FinishedTimerCb(sslSocket *ss); +static void dtls_CancelAllTimers(sslSocket *ss); /* -28 adjusts for the IP/UDP header */ static const PRUint16 COMMON_MTU_VALUES[] = { @@ -30,6 +31,9 @@ static const PRUint16 COMMON_MTU_VALUES[] = { }; #define DTLS_COOKIE_BYTES 32 +/* Maximum DTLS expansion = header + IV + max CBC padding + + * maximum MAC. */ +#define DTLS_MAX_EXPANSION (DTLS_RECORD_HEADER_LENGTH + 16 + 16 + 32) /* List copied from ssl3con.c:cipherSuites */ static const ssl3CipherSuite nonDTLSSuites[] = { @@ -119,9 +123,9 @@ static DTLSQueuedMessage * dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type, const unsigned char *data, PRUint32 len) { - DTLSQueuedMessage *msg = NULL; + DTLSQueuedMessage *msg; - msg = PORT_ZAlloc(sizeof(DTLSQueuedMessage)); + msg = PORT_ZNew(DTLSQueuedMessage); if (!msg) return NULL; @@ -137,7 +141,7 @@ dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type, msg->type = type; /* Safe if we are < 1.3, since the refct is * already very high. */ - tls13_CipherSpecAddRef(cwSpec); + ssl_CipherSpecAddRef(cwSpec); return msg; } @@ -155,7 +159,7 @@ dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg) /* Safe if we are < 1.3, since the refct is * already very high. */ - tls13_CipherSpecRelease(msg->cwSpec); + ssl_CipherSpecRelease(msg->cwSpec); PORT_ZFree(msg->data, msg->len); PORT_Free(msg); } @@ -184,37 +188,38 @@ dtls_FreeHandshakeMessages(PRCList *list) static SECStatus dtls_RetransmitDetected(sslSocket *ss) { + dtlsTimer *timer = ss->ssl3.hs.rtTimer; SECStatus rv = SECSuccess; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - if (ss->ssl3.hs.rtTimerCb == dtls_RetransmitTimerExpiredCb) { + if (timer->cb == dtls_RetransmitTimerExpiredCb) { /* Check to see if we retransmitted recently. If so, * suppress the triggered retransmit. This avoids * retransmit wars after packet loss. * This is not in RFC 5346 but it should be. */ - if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > - (ss->ssl3.hs.rtTimeoutMs / 4)) { + if ((PR_IntervalNow() - timer->started) > + (timer->timeout / 4)) { SSL_TRC(30, ("%d: SSL3[%d]: Shortcutting retransmit timer", SSL_GETPID(), ss->fd)); /* Cancel the timer and call the CB, * which re-arms the timer */ - dtls_CancelTimer(ss); + dtls_CancelTimer(ss, ss->ssl3.hs.rtTimer); dtls_RetransmitTimerExpiredCb(ss); } else { SSL_TRC(30, ("%d: SSL3[%d]: Ignoring retransmission: " "last retransmission %dms ago, suppressed for %dms", SSL_GETPID(), ss->fd, - PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted, - ss->ssl3.hs.rtTimeoutMs / 4)); + PR_IntervalNow() - timer->started, + timer->timeout / 4)); } - } else if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb) { + } else if (timer->cb == dtls_FinishedTimerCb) { SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected in holddown", SSL_GETPID(), ss->fd)); /* Retransmit the messages and re-arm the timer @@ -222,14 +227,14 @@ dtls_RetransmitDetected(sslSocket *ss) * The spec isn't clear and my reasoning is that this * may be a re-ordered packet rather than slowness, * so let's be aggressive. */ - dtls_CancelTimer(ss); + dtls_CancelTimer(ss, ss->ssl3.hs.rtTimer); rv = dtls_TransmitMessageFlight(ss); if (rv == SECSuccess) { rv = dtls_StartHolddownTimer(ss); } } else { - PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); + PORT_Assert(timer->cb == NULL); /* ... and ignore it. */ } return rv; @@ -238,19 +243,8 @@ dtls_RetransmitDetected(sslSocket *ss) static SECStatus dtls_HandleHandshakeMessage(sslSocket *ss, PRUint8 *data, PRBool last) { - - /* At this point we are advancing our state machine, so we can free our last - * flight of messages. */ - dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); ss->ssl3.hs.recvdHighWater = -1; - /* Reset the timer to the initial value if the retry counter - * is 0, per Sec. 4.2.4.1 */ - dtls_CancelTimer(ss); - if (ss->ssl3.hs.rtRetries == 0) { - ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS; - } - return ssl3_HandleHandshakeMessage(ss, data, ss->ssl3.hs.msg_len, last); } @@ -273,7 +267,8 @@ dtls_HandleHandshakeMessage(sslSocket *ss, PRUint8 *data, PRBool last) #define OFFSET_MASK(o) (1 << (o % 8)) SECStatus -dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) +dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, + sslBuffer *origBuf) { /* XXX OK for now. * This doesn't work properly with asynchronous certificate validation. @@ -283,6 +278,9 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) */ sslBuffer buf = *origBuf; SECStatus rv = SECSuccess; + PRBool discarded = PR_FALSE; + + ss->ssl3.hs.endOfFlight = PR_FALSE; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -298,7 +296,7 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) if (buf.len < 12) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - break; + goto loser; } /* Parse the header */ @@ -323,14 +321,28 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) if (buf.len < fragment_length) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - break; + goto loser; } /* Sanity check the packet contents */ if ((fragment_length + fragment_offset) > message_length) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - break; + goto loser; + } + + /* If we're a server and we receive what appears to be a retried + * ClientHello, and we are expecting a ClientHello, move the receive + * sequence number forward. This allows for a retried ClientHello if we + * send a stateless HelloRetryRequest. */ + if (message_seq > ss->ssl3.hs.recvMessageSeq && + message_seq == 1 && + fragment_offset == 0 && + ss->ssl3.hs.ws == wait_client_hello && + (SSLHandshakeType)type == ssl_hs_client_hello) { + SSL_TRC(5, ("%d: DTLS[%d]: Received apparent 2nd ClientHello", + SSL_GETPID(), ss->fd)); + ss->ssl3.hs.recvMessageSeq = 1; } /* There are three ways we could not be ready for this packet. @@ -346,20 +358,20 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) (fragment_offset == 0) && (fragment_length == message_length)) { /* Complete next message. Process immediately */ - ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; + ss->ssl3.hs.msg_type = (SSLHandshakeType)type; ss->ssl3.hs.msg_len = message_length; rv = dtls_HandleHandshakeMessage(ss, buf.buf, buf.len == fragment_length); if (rv == SECFailure) { - break; /* Discard the remainder of the record. */ + goto loser; } } else { if (message_seq < ss->ssl3.hs.recvMessageSeq) { /* Case 3: we do an immediate retransmit if we're * in a waiting state. */ rv = dtls_RetransmitDetected(ss); - break; + goto loser; } else if (message_seq > ss->ssl3.hs.recvMessageSeq) { /* Case 2 * @@ -369,7 +381,12 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) * * XXX OK for now. Maybe do something smarter at some point? */ + SSL_TRC(10, ("%d: SSL3[%d]: dtls_HandleHandshake, discarding handshake message", + SSL_GETPID(), ss->fd)); + discarded = PR_TRUE; } else { + PRInt32 end = fragment_offset + fragment_length; + /* Case 1 * * Buffer the fragment for reassembly @@ -380,18 +397,18 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length); if (rv != SECSuccess) - break; + goto loser; /* Make room for the fragment map */ rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments, map_length); if (rv != SECSuccess) - break; + goto loser; /* Reset the reassembly map */ ss->ssl3.hs.recvdHighWater = 0; PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0, ss->ssl3.hs.recvdFragments.space); - ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; + ss->ssl3.hs.msg_type = (SSLHandshakeType)type; ss->ssl3.hs.msg_len = message_length; } @@ -403,14 +420,14 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) ss->ssl3.hs.recvdHighWater = -1; PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - break; + goto loser; } - /* Now copy this fragment into the buffer */ - PORT_Assert((fragment_offset + fragment_length) <= - ss->ssl3.hs.msg_body.space); - PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset, - buf.buf, fragment_length); + /* Now copy this fragment into the buffer. */ + if (end > ss->ssl3.hs.recvdHighWater) { + PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset, + buf.buf, fragment_length); + } /* This logic is a bit tricky. We have two values for * reassembly state: @@ -426,12 +443,11 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) if (fragment_offset <= (unsigned int)ss->ssl3.hs.recvdHighWater) { /* Either this is the adjacent fragment or an overlapping * fragment */ - ss->ssl3.hs.recvdHighWater = fragment_offset + - fragment_length; + if (end > ss->ssl3.hs.recvdHighWater) { + ss->ssl3.hs.recvdHighWater = end; + } } else { - for (offset = fragment_offset; - offset < fragment_offset + fragment_length; - offset++) { + for (offset = fragment_offset; offset < end; offset++) { ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |= OFFSET_MASK(offset); } @@ -457,7 +473,7 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) buf.len == fragment_length); if (rv == SECFailure) { - break; /* Discard the rest of the record. */ + goto loser; } } } @@ -467,6 +483,26 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) buf.len -= fragment_length; } + // This should never happen, but belt and suspenders. + if (rv == SECFailure) { + PORT_Assert(0); + goto loser; + } + + /* If we processed all the fragments in this message, then mark it as remembered. + * TODO(ekr@rtfm.com): Store out of order messages for DTLS 1.3 so ACKs work + * better. Bug 1392620.*/ + if (!discarded && tls13_MaybeTls13(ss)) { + rv = dtls13_RememberFragment(ss, &ss->ssl3.hs.dtlsRcvdHandshake, + 0, 0, 0, epoch, seqNum); + } + if (rv != SECSuccess) { + goto loser; + } + + rv = dtls13_SetupAcks(ss); + +loser: origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */ /* XXX OK for now. In future handle rv == SECWouldBlock safely in order @@ -560,6 +596,8 @@ dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) if (!(flags & ssl_SEND_FLAG_NO_RETRANSMIT)) { rv = dtls_StartRetransmitTimer(ss); + } else { + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); } } @@ -576,7 +614,7 @@ static void dtls_RetransmitTimerExpiredCb(sslSocket *ss) { SECStatus rv; - + dtlsTimer *timer = ss->ssl3.hs.rtTimer; ss->ssl3.hs.rtRetries++; if (!(ss->ssl3.hs.rtRetries % 3)) { @@ -589,175 +627,239 @@ dtls_RetransmitTimerExpiredCb(sslSocket *ss) rv = dtls_TransmitMessageFlight(ss); if (rv == SECSuccess) { /* Re-arm the timer */ - ss->ssl3.hs.rtTimeoutMs *= 2; - if (ss->ssl3.hs.rtTimeoutMs > DTLS_RETRANSMIT_MAX_MS) { - ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_MAX_MS; + timer->timeout *= 2; + if (timer->timeout > DTLS_RETRANSMIT_MAX_MS) { + timer->timeout = DTLS_RETRANSMIT_MAX_MS; } - ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); - ss->ssl3.hs.rtTimerCb = dtls_RetransmitTimerExpiredCb; + timer->started = PR_IntervalNow(); + timer->cb = dtls_RetransmitTimerExpiredCb; SSL_TRC(30, ("%d: SSL3[%d]: Retransmit #%d, next in %d", SSL_GETPID(), ss->fd, - ss->ssl3.hs.rtRetries, ss->ssl3.hs.rtTimeoutMs)); + ss->ssl3.hs.rtRetries, timer->timeout)); } /* else: OK for now. In future maybe signal the stack that we couldn't * transmit. For now, let the read handle any real network errors */ } +#define DTLS_HS_HDR_LEN 12 +#define DTLS_MIN_FRAGMENT (DTLS_HS_HDR_LEN + 1 + DTLS_MAX_EXPANSION) + +/* Encrypt and encode a handshake message fragment. Flush the data out to the + * network if there is insufficient space for any fragment. */ +static SECStatus +dtls_SendFragment(sslSocket *ss, DTLSQueuedMessage *msg, PRUint8 *data, + unsigned int len) +{ + PRInt32 sent; + SECStatus rv; + + PRINT_BUF(40, (ss, "dtls_SendFragment", data, len)); + sent = ssl3_SendRecord(ss, msg->cwSpec, msg->type, data, len, + ssl_SEND_FLAG_FORCE_INTO_BUFFER); + if (sent != len) { + if (sent != -1) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + } + return SECFailure; + } + + /* If another fragment won't fit, flush. */ + if (ss->ssl3.mtu < ss->pendingBuf.len + DTLS_MIN_FRAGMENT) { + SSL_TRC(20, ("%d: DTLS[%d]: dtls_SendFragment: flush", + SSL_GETPID(), ss->fd)); + rv = dtls_SendSavedWriteData(ss); + if (rv != SECSuccess) { + return SECFailure; + } + } + return SECSuccess; +} + +/* Fragment a handshake message into multiple records and send them. */ +static SECStatus +dtls_FragmentHandshake(sslSocket *ss, DTLSQueuedMessage *msg) +{ + PRBool fragmentWritten = PR_FALSE; + PRUint16 msgSeq; + PRUint8 *fragment; + PRUint32 fragmentOffset = 0; + PRUint32 fragmentLen; + const PRUint8 *content = msg->data + DTLS_HS_HDR_LEN; + PRUint32 contentLen = msg->len - DTLS_HS_HDR_LEN; + SECStatus rv; + + /* The headers consume 12 bytes so the smallest possible message (i.e., an + * empty one) is 12 bytes. */ + PORT_Assert(msg->len >= DTLS_HS_HDR_LEN); + + /* DTLS only supports fragmenting handshaking messages. */ + PORT_Assert(msg->type == content_handshake); + + msgSeq = (msg->data[4] << 8) | msg->data[5]; + + /* do {} while() so that empty messages are sent at least once. */ + do { + PRUint8 buf[DTLS_MAX_MTU]; /* >= than largest plausible MTU */ + PRBool hasUnackedRange; + PRUint32 end; + + hasUnackedRange = dtls_NextUnackedRange(ss, msgSeq, + fragmentOffset, contentLen, + &fragmentOffset, &end); + if (!hasUnackedRange) { + SSL_TRC(20, ("%d: SSL3[%d]: FragmentHandshake %d: all acknowledged", + SSL_GETPID(), ss->fd, msgSeq)); + break; + } + + SSL_TRC(20, ("%d: SSL3[%d]: FragmentHandshake %d: unacked=%u-%u", + SSL_GETPID(), ss->fd, msgSeq, fragmentOffset, end)); + + /* Cut down to the data we have available. */ + PORT_Assert(fragmentOffset <= contentLen); + PORT_Assert(fragmentOffset <= end); + 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. */ + fragmentLen = PR_MIN(fragmentLen, + ss->ssl3.mtu - /* MTU estimate. */ + ss->pendingBuf.len - /* Less unsent records. */ + DTLS_MAX_EXPANSION - /* Allow for expansion. */ + DTLS_HS_HDR_LEN); /* + handshake header. */ + PORT_Assert(fragmentLen > 0 || fragmentOffset == 0); + + /* Make totally sure that we will fit in the buffer. This should be + * impossible; DTLS_MAX_MTU should always be more than ss->ssl3.mtu. */ + if (fragmentLen >= (DTLS_MAX_MTU - DTLS_HS_HDR_LEN)) { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + if (fragmentLen == contentLen) { + fragment = msg->data; + } else { + sslBuffer tmp = SSL_BUFFER_FIXED(buf, sizeof(buf)); + + /* Construct an appropriate-sized fragment */ + /* Type, length, sequence */ + rv = sslBuffer_Append(&tmp, msg->data, 6); + if (rv != SECSuccess) { + return SECFailure; + } + /* Offset. */ + rv = sslBuffer_AppendNumber(&tmp, fragmentOffset, 3); + if (rv != SECSuccess) { + return SECFailure; + } + /* Length. */ + rv = sslBuffer_AppendNumber(&tmp, fragmentLen, 3); + if (rv != SECSuccess) { + return SECFailure; + } + /* Data. */ + rv = sslBuffer_Append(&tmp, content + fragmentOffset, fragmentLen); + if (rv != SECSuccess) { + return SECFailure; + } + + fragment = SSL_BUFFER_BASE(&tmp); + } + + /* Record that we are sending first, because encrypting + * increments the sequence number. */ + rv = dtls13_RememberFragment(ss, &ss->ssl3.hs.dtlsSentHandshake, + msgSeq, fragmentOffset, fragmentLen, + msg->cwSpec->epoch, + msg->cwSpec->seqNum); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = dtls_SendFragment(ss, msg, fragment, + fragmentLen + DTLS_HS_HDR_LEN); + if (rv != SECSuccess) { + return SECFailure; + } + + fragmentWritten = PR_TRUE; + fragmentOffset += fragmentLen; + } while (fragmentOffset < contentLen); + + if (!fragmentWritten) { + /* Nothing was written if we got here, so the whole message must have + * been acknowledged. Discard it. */ + SSL_TRC(10, ("%d: SSL3[%d]: FragmentHandshake %d: removed", + SSL_GETPID(), ss->fd, msgSeq)); + PR_REMOVE_LINK(&msg->link); + dtls_FreeHandshakeMessage(msg); + } + + return SECSuccess; +} + /* Transmit a flight of handshake messages, stuffing them - * into as few records as seems reasonable + * into as few records as seems reasonable. + * + * TODO: Space separate UDP packets out a little. * * Called from: * dtls_FlushHandshake() * dtls_RetransmitTimerExpiredCb() */ -static SECStatus +SECStatus dtls_TransmitMessageFlight(sslSocket *ss) { SECStatus rv = SECSuccess; PRCList *msg_p; - PRUint16 room_left = ss->ssl3.mtu; - PRInt32 sent; + + SSL_TRC(10, ("%d: SSL3[%d]: dtls_TransmitMessageFlight", + SSL_GETPID(), ss->fd)); ssl_GetXmitBufLock(ss); ssl_GetSpecReadLock(ss); - /* DTLS does not buffer its handshake messages in - * ss->pendingBuf, but rather in the lastMessageFlight - * structure. This is just a sanity check that - * some programming error hasn't inadvertantly - * stuffed something in ss->pendingBuf + /* DTLS does not buffer its handshake messages in ss->pendingBuf, but rather + * in the lastMessageFlight structure. This is just a sanity check that some + * programming error hasn't inadvertantly stuffed something in + * ss->pendingBuf. This function uses ss->pendingBuf temporarily and it + * needs to be empty to start. */ PORT_Assert(!ss->pendingBuf.len); + for (msg_p = PR_LIST_HEAD(&ss->ssl3.hs.lastMessageFlight); - msg_p != &ss->ssl3.hs.lastMessageFlight; - msg_p = PR_NEXT_LINK(msg_p)) { + msg_p != &ss->ssl3.hs.lastMessageFlight;) { DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p; - /* The logic here is: - * - * 1. If this is a message that will not fit into the remaining - * space, then flush. - * 2. If the message will now fit into the remaining space, - * encrypt, buffer, and loop. - * 3. If the message will not fit, then fragment. - * - * At the end of the function, flush. - */ - if ((msg->len + SSL3_BUFFER_FUDGE) > room_left) { - /* The message will not fit into the remaining space, so flush */ - rv = dtls_SendSavedWriteData(ss); - if (rv != SECSuccess) - break; - - room_left = ss->ssl3.mtu; - } + /* Move the pointer forward so that the functions below are free to + * remove messages from the list. */ + msg_p = PR_NEXT_LINK(msg_p); - if ((msg->len + SSL3_BUFFER_FUDGE) <= room_left) { - /* The message will fit, so encrypt and then continue with the - * next packet */ - sent = ssl3_SendRecord(ss, msg->cwSpec, msg->type, - msg->data, msg->len, - ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (sent != msg->len) { - rv = SECFailure; - if (sent != -1) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - } - break; - } + /* Note: This function fragments messages so that each record is close + * to full. This produces fewer records, but it means that messages can + * be quite fragmented. Adding an extra flush here would push new + * messages into new records and reduce fragmentation. */ - room_left = ss->ssl3.mtu - ss->pendingBuf.len; + if (msg->type == content_handshake) { + rv = dtls_FragmentHandshake(ss, msg); } else { - /* The message will not fit, so fragment. - * - * XXX OK for now. Arrange to coalesce the last fragment - * of this message with the next message if possible. - * That would be more efficient. - */ - PRUint32 fragment_offset = 0; - unsigned char fragment[DTLS_MAX_MTU]; /* >= than largest - * plausible MTU */ - - /* Assert that we have already flushed */ - PORT_Assert(room_left == ss->ssl3.mtu); - - /* Case 3: We now need to fragment this message - * DTLS only supports fragmenting handshaking messages */ - PORT_Assert(msg->type == content_handshake); - - /* The headers consume 12 bytes so the smalles possible - * message (i.e., an empty one) is 12 bytes - */ - PORT_Assert(msg->len >= 12); - - while ((fragment_offset + 12) < msg->len) { - PRUint32 fragment_len; - const unsigned char *content = msg->data + 12; - PRUint32 content_len = msg->len - 12; - - /* The reason we use 8 here is that that's the length of - * the new DTLS data that we add to the header */ - fragment_len = PR_MIN((PRUint32)room_left - (SSL3_BUFFER_FUDGE + 8), - content_len - fragment_offset); - PORT_Assert(fragment_len < DTLS_MAX_MTU - 12); - /* Make totally sure that we are within the buffer. - * Note that the only way that fragment len could get - * adjusted here is if - * - * (a) we are in release mode so the PORT_Assert is compiled out - * (b) either the MTU table is inconsistent with DTLS_MAX_MTU - * or ss->ssl3.mtu has become corrupt. - */ - fragment_len = PR_MIN(fragment_len, DTLS_MAX_MTU - 12); - - /* Construct an appropriate-sized fragment */ - /* Type, length, sequence */ - PORT_Memcpy(fragment, msg->data, 6); - - /* Offset */ - fragment[6] = (fragment_offset >> 16) & 0xff; - fragment[7] = (fragment_offset >> 8) & 0xff; - fragment[8] = (fragment_offset)&0xff; - - /* Fragment length */ - fragment[9] = (fragment_len >> 16) & 0xff; - fragment[10] = (fragment_len >> 8) & 0xff; - fragment[11] = (fragment_len)&0xff; - - PORT_Memcpy(fragment + 12, content + fragment_offset, - fragment_len); - - /* - * Send the record. We do this in two stages - * 1. Encrypt - */ - sent = ssl3_SendRecord(ss, msg->cwSpec, msg->type, - fragment, fragment_len + 12, - ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (sent != (fragment_len + 12)) { - rv = SECFailure; - if (sent != -1) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - } - break; - } - - /* 2. Flush */ - rv = dtls_SendSavedWriteData(ss); - if (rv != SECSuccess) - break; - - fragment_offset += fragment_len; - } + PORT_Assert(!tls13_MaybeTls13(ss)); + rv = dtls_SendFragment(ss, msg, msg->data, msg->len); + } + if (rv != SECSuccess) { + break; } } - /* Finally, we need to flush */ - if (rv == SECSuccess) + /* Finally, flush any data that wasn't flushed already. */ + if (rv == SECSuccess) { rv = dtls_SendSavedWriteData(ss); + } /* Give up the locks */ ssl_ReleaseSpecReadLock(ss); @@ -796,23 +898,59 @@ dtls_SendSavedWriteData(sslSocket *ss) return SECSuccess; } -static SECStatus -dtls_StartTimer(sslSocket *ss, PRUint32 time, DTLSTimerCb cb) +void +dtls_InitTimers(sslSocket *ss) { - PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); + unsigned int i; + dtlsTimer **timers[PR_ARRAY_SIZE(ss->ssl3.hs.timers)] = { + &ss->ssl3.hs.rtTimer, + &ss->ssl3.hs.ackTimer, + &ss->ssl3.hs.hdTimer + }; + static const char *timerLabels[] = { + "retransmit", "ack", "holddown" + }; + + PORT_Assert(PR_ARRAY_SIZE(timers) == PR_ARRAY_SIZE(timerLabels)); + for (i = 0; i < PR_ARRAY_SIZE(ss->ssl3.hs.timers); ++i) { + *timers[i] = &ss->ssl3.hs.timers[i]; + ss->ssl3.hs.timers[i].label = timerLabels[i]; + } +} - ss->ssl3.hs.rtRetries = 0; - ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); - ss->ssl3.hs.rtTimeoutMs = time; - ss->ssl3.hs.rtTimerCb = cb; +SECStatus +dtls_StartTimer(sslSocket *ss, dtlsTimer *timer, PRUint32 time, DTLSTimerCb cb) +{ + PORT_Assert(timer->cb == NULL); + + SSL_TRC(10, ("%d: SSL3[%d]: %s dtls_StartTimer %s timeout=%d", + SSL_GETPID(), ss->fd, SSL_ROLE(ss), timer->label, time)); + + timer->started = PR_IntervalNow(); + timer->timeout = time; + timer->cb = cb; return SECSuccess; } +SECStatus +dtls_RestartTimer(sslSocket *ss, dtlsTimer *timer) +{ + timer->started = PR_IntervalNow(); + return SECSuccess; +} + +PRBool +dtls_TimerActive(sslSocket *ss, dtlsTimer *timer) +{ + return timer->cb != NULL; +} /* Start a timer for retransmission. */ static SECStatus dtls_StartRetransmitTimer(sslSocket *ss) { - return dtls_StartTimer(ss, DTLS_RETRANSMIT_INITIAL_MS, + ss->ssl3.hs.rtRetries = 0; + return dtls_StartTimer(ss, ss->ssl3.hs.rtTimer, + DTLS_RETRANSMIT_INITIAL_MS, dtls_RetransmitTimerExpiredCb); } @@ -820,7 +958,9 @@ dtls_StartRetransmitTimer(sslSocket *ss) SECStatus dtls_StartHolddownTimer(sslSocket *ss) { - return dtls_StartTimer(ss, DTLS_RETRANSMIT_FINISHED_MS, + ss->ssl3.hs.rtRetries = 0; + return dtls_StartTimer(ss, ss->ssl3.hs.rtTimer, + DTLS_RETRANSMIT_FINISHED_MS, dtls_FinishedTimerCb); } @@ -831,11 +971,25 @@ dtls_StartHolddownTimer(sslSocket *ss) * dtls_CheckTimer() */ void -dtls_CancelTimer(sslSocket *ss) +dtls_CancelTimer(sslSocket *ss, dtlsTimer *timer) { + SSL_TRC(30, ("%d: SSL3[%d]: %s dtls_CancelTimer %s", + SSL_GETPID(), ss->fd, SSL_ROLE(ss), + timer->label)); + PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - ss->ssl3.hs.rtTimerCb = NULL; + timer->cb = NULL; +} + +static void +dtls_CancelAllTimers(sslSocket *ss) +{ + unsigned int i; + + for (i = 0; i < PR_ARRAY_SIZE(ss->ssl3.hs.timers); ++i) { + dtls_CancelTimer(ss, &ss->ssl3.hs.timers[i]); + } } /* Check the pending timer and fire the callback if it expired @@ -845,22 +999,33 @@ dtls_CancelTimer(sslSocket *ss) void dtls_CheckTimer(sslSocket *ss) { + unsigned int i; + SSL_TRC(30, ("%d: SSL3[%d]: dtls_CheckTimer (%s)", + SSL_GETPID(), ss->fd, ss->sec.isServer ? "server" : "client")); + ssl_GetSSL3HandshakeLock(ss); - if (!ss->ssl3.hs.rtTimerCb) { - ssl_ReleaseSSL3HandshakeLock(ss); - return; - } - if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > - PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) { - /* Timer has expired */ - DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb; + for (i = 0; i < PR_ARRAY_SIZE(ss->ssl3.hs.timers); ++i) { + dtlsTimer *timer = &ss->ssl3.hs.timers[i]; + if (!timer->cb) { + continue; + } + + if ((PR_IntervalNow() - timer->started) >= + PR_MillisecondsToInterval(timer->timeout)) { + /* Timer has expired */ + DTLSTimerCb cb = timer->cb; + + SSL_TRC(10, ("%d: SSL3[%d]: %s firing timer %s", + SSL_GETPID(), ss->fd, SSL_ROLE(ss), + timer->label)); - /* Cancel the timer so that we can call the CB safely */ - dtls_CancelTimer(ss); + /* Cancel the timer so that we can call the CB safely */ + dtls_CancelTimer(ss, timer); - /* Now call the CB */ - cb(ss); + /* Now call the CB */ + cb(ss); + } } ssl_ReleaseSSL3HandshakeLock(ss); } @@ -874,9 +1039,6 @@ static void dtls_FinishedTimerCb(sslSocket *ss) { dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); - } } /* Cancel the Finished hold-down timer and destroy the @@ -895,8 +1057,8 @@ dtls_RehandshakeCleanup(sslSocket *ss) return; } PORT_Assert((ss->version < SSL_LIBRARY_VERSION_TLS_1_3)); - dtls_CancelTimer(ss); - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); + dtls_CancelAllTimers(ss); + dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); ss->ssl3.hs.sendMessageSeq = 0; ss->ssl3.hs.recvMessageSeq = 0; } @@ -959,6 +1121,8 @@ dtls_HandleHelloVerifyRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) goto alert_loser; } + dtls_ReceivedFirstMessageInFlight(ss); + /* The version. * * RFC 4347 required that you verify that the server versions @@ -1103,27 +1267,53 @@ SECStatus DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout) { sslSocket *ss = NULL; - PRIntervalTime elapsed; - PRIntervalTime desired; + PRBool found = PR_FALSE; + PRIntervalTime now = PR_IntervalNow(); + PRIntervalTime to; + unsigned int i; + + *timeout = PR_INTERVAL_NO_TIMEOUT; ss = ssl_FindSocket(socket); - if (!ss) + if (!ss) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; + } - if (!IS_DTLS(ss)) + if (!IS_DTLS(ss)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; + } - if (!ss->ssl3.hs.rtTimerCb) - return SECFailure; + for (i = 0; i < PR_ARRAY_SIZE(ss->ssl3.hs.timers); ++i) { + PRIntervalTime elapsed; + PRIntervalTime desired; + dtlsTimer *timer = &ss->ssl3.hs.timers[i]; - elapsed = PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted; - desired = PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs); - if (elapsed > desired) { - /* Timer expired */ - *timeout = PR_INTERVAL_NO_WAIT; - } else { - *timeout = desired - elapsed; + if (!timer->cb) { + continue; + } + found = PR_TRUE; + + elapsed = now - timer->started; + desired = PR_MillisecondsToInterval(timer->timeout); + if (elapsed > desired) { + /* Timer expired */ + *timeout = PR_INTERVAL_NO_WAIT; + return SECSuccess; + } else { + to = desired - elapsed; + } + + if (*timeout > to) { + *timeout = to; + } + } + + if (!found) { + PORT_SetError(SSL_ERROR_NO_TIMERS_FOUND); + return SECFailure; } return SECSuccess; @@ -1137,72 +1327,50 @@ DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout) * seems like a good tradeoff for implementation effort and is * consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1. * - * If the packet is not relevant, this function returns PR_FALSE. - * If the packet is relevant, this function returns PR_TRUE - * and sets |*seqNum| to the packet sequence number. + * If the packet is not relevant, this function returns PR_FALSE. If the packet + * is relevant, this function returns PR_TRUE and sets |*seqNumOut| to the + * packet sequence number (removing the epoch). */ PRBool -dtls_IsRelevant(sslSocket *ss, const SSL3Ciphertext *cText, - PRBool *sameEpoch, PRUint64 *seqNum) +dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec, + const SSL3Ciphertext *cText, + sslSequenceNumber *seqNumOut) { - const ssl3CipherSpec *crSpec = ss->ssl3.crSpec; - DTLSEpoch epoch; - sslSequenceNumber dtls_seq_num; - - epoch = cText->seq_num >> 48; - *sameEpoch = crSpec->epoch == epoch; - if (!*sameEpoch) { - SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, received packet " - "from irrelevant epoch %d", - SSL_GETPID(), ss->fd, epoch)); - return PR_FALSE; - } - - dtls_seq_num = cText->seq_num & RECORD_SEQ_MAX; - if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) { - SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, rejecting " - "potentially replayed packet", - SSL_GETPID(), ss->fd)); + sslSequenceNumber seqNum = cText->seq_num & RECORD_SEQ_MASK; + if (dtls_RecordGetRecvd(&spec->recvdRecords, seqNum) != 0) { + SSL_TRC(10, ("%d: SSL3[%d]: dtls_IsRelevant, rejecting " + "potentially replayed packet", + SSL_GETPID(), ss->fd)); return PR_FALSE; } - *seqNum = dtls_seq_num; + *seqNumOut = seqNum; return PR_TRUE; } -/* In TLS 1.3, a client that receives a retransmission of the server's first - * flight will reject that message and discard it (see dtls_IsRelevant() above). - * However, we need to trigger retransmission to prevent loss of the client's - * last flight from causing the connection to fail. - * - * This only triggers for a retransmitted ServerHello. Other (encrypted) - * handshake messages do not trigger retransmission, so we are a little more - * exposed to loss than is ideal. - * - * Note: This isn't an issue in earlier versions because the second-to-last - * flight (sent by the server) includes the Finished message, which is not - * dropped because it has the same epoch that the client currently expects. - */ -SECStatus -dtls_MaybeRetransmitHandshake(sslSocket *ss, const SSL3Ciphertext *cText, - PRBool sameEpoch) +void +dtls_ReceivedFirstMessageInFlight(sslSocket *ss) { - SECStatus rv = SECSuccess; - DTLSEpoch messageEpoch = cText->seq_num >> 48; - - /* Drop messages from other epochs if we are ignoring things. */ - if (!sameEpoch && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) { - return SECSuccess; - } + if (!IS_DTLS(ss)) + return; - if (!ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && - messageEpoch == 0 && cText->type == content_handshake) { - ssl_GetSSL3HandshakeLock(ss); - if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb && - ss->ssl3.hs.ws == idle_handshake) { - rv = dtls_RetransmitDetected(ss); + /* At this point we are advancing our state machine, so we can free our last + * flight of messages. */ + if (ss->ssl3.hs.ws != idle_handshake || + ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + /* We need to keep our last flight around in DTLS 1.2 and below, + * so we can retransmit it in response to other people's + * retransmits. */ + dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); + + /* Reset the timer to the initial value if the retry counter + * is 0, per RFC 6347, Sec. 4.2.4.1 */ + dtls_CancelTimer(ss, ss->ssl3.hs.rtTimer); + if (ss->ssl3.hs.rtRetries == 0) { + ss->ssl3.hs.rtTimer->timeout = DTLS_RETRANSMIT_INITIAL_MS; } - ssl_ReleaseSSL3HandshakeLock(ss); } - return rv; + + /* Empty the ACK queue (TLS 1.3 only). */ + ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL); } diff --git a/security/nss/lib/ssl/dtlscon.h b/security/nss/lib/ssl/dtlscon.h new file mode 100644 index 000000000..d094380f8 --- /dev/null +++ b/security/nss/lib/ssl/dtlscon.h @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __dtlscon_h_ +#define __dtlscon_h_ + +extern void dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg); +extern void dtls_FreeHandshakeMessages(PRCList *lst); +SECStatus dtls_TransmitMessageFlight(sslSocket *ss); +void dtls_InitTimers(sslSocket *ss); +SECStatus dtls_StartTimer(sslSocket *ss, dtlsTimer *timer, + PRUint32 time, DTLSTimerCb cb); +SECStatus dtls_RestartTimer(sslSocket *ss, dtlsTimer *timer); +PRBool dtls_TimerActive(sslSocket *ss, dtlsTimer *timer); +extern SECStatus dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, + sslSequenceNumber seqNum, + sslBuffer *origBuf); +extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss, + PRUint8 *b, PRUint32 length); +extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss); +extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, + const PRUint8 *pIn, PRInt32 nIn); +extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); +SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss); +extern SECStatus dtls_StartHolddownTimer(sslSocket *ss); +extern void dtls_CheckTimer(sslSocket *ss); +extern void dtls_CancelTimer(sslSocket *ss, dtlsTimer *timer); +extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised); +extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records); +extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records, + sslSequenceNumber seq); +extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records, + sslSequenceNumber seq); +extern void dtls_RehandshakeCleanup(sslSocket *ss); +extern SSL3ProtocolVersion +dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv); +extern SSL3ProtocolVersion +dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv); +extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec, + const SSL3Ciphertext *cText, + sslSequenceNumber *seqNum); +void dtls_ReceivedFirstMessageInFlight(sslSocket *ss); +#endif diff --git a/security/nss/lib/ssl/exports.gyp b/security/nss/lib/ssl/exports.gyp index e2123af84..c3b34c6cc 100644 --- a/security/nss/lib/ssl/exports.gyp +++ b/security/nss/lib/ssl/exports.gyp @@ -15,6 +15,7 @@ 'preenc.h', 'ssl.h', 'sslerr.h', + 'sslexp.h', 'sslproto.h', 'sslt.h' ], diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn index fbb88baff..ca9b9ee7b 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -10,6 +10,7 @@ EXPORTS = \ ssl.h \ sslt.h \ sslerr.h \ + sslexp.h \ sslproto.h \ preenc.h \ $(NULL) @@ -19,13 +20,15 @@ MAPFILE = $(OBJDIR)/ssl.def CSRCS = \ dtlscon.c \ + dtls13con.c \ prelib.c \ ssl3con.c \ ssl3gthr.c \ sslauth.c \ + sslbloom.c \ sslcon.c \ ssldef.c \ - ssl3encode.c \ + sslencode.c \ sslenum.c \ sslerr.c \ sslerrstrs.c \ @@ -38,6 +41,7 @@ CSRCS = \ sslsecur.c \ sslsnce.c \ sslsock.c \ + sslspec.c \ ssltrace.c \ sslver.c \ authcert.c \ @@ -47,7 +51,9 @@ CSRCS = \ ssl3ecc.c \ tls13con.c \ tls13exthandle.c \ + tls13hashstate.c \ tls13hkdf.c \ + tls13replay.c \ sslcert.c \ sslgrp.c \ $(NULL) diff --git a/security/nss/lib/ssl/selfencrypt.c b/security/nss/lib/ssl/selfencrypt.c index 6d6e25cfc..97217b4a6 100644 --- a/security/nss/lib/ssl/selfencrypt.c +++ b/security/nss/lib/ssl/selfencrypt.c @@ -11,7 +11,6 @@ #include "pk11func.h" #include "ssl.h" #include "sslt.h" -#include "ssl3encode.h" #include "sslimpl.h" #include "selfencrypt.h" @@ -121,12 +120,11 @@ ssl_SelfEncryptProtectInt( PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) { unsigned int len; + unsigned int lenOffset; unsigned char iv[AES_BLOCK_SIZE]; SECItem ivItem = { siBuffer, iv, sizeof(iv) }; - unsigned char mac[SHA256_LENGTH]; /* SHA-256 */ - unsigned int macLen; - SECItem outItem = { siBuffer, out, maxOutLen }; - SECItem lengthBytesItem; + /* Write directly to out. */ + sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen); SECStatus rv; /* Generate a random IV */ @@ -137,52 +135,54 @@ ssl_SelfEncryptProtectInt( } /* Add header. */ - rv = ssl3_AppendToItem(&outItem, keyName, SELF_ENCRYPT_KEY_NAME_LEN); + rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN); if (rv != SECSuccess) { return SECFailure; } - rv = ssl3_AppendToItem(&outItem, iv, sizeof(iv)); + rv = sslBuffer_Append(&buf, iv, sizeof(iv)); if (rv != SECSuccess) { return SECFailure; } - /* Skip forward by two so we can encode the ciphertext in place. */ - lengthBytesItem = outItem; - rv = ssl3_AppendNumberToItem(&outItem, 0, 2); + /* Leave space for the length of the ciphertext. */ + rv = sslBuffer_Skip(&buf, 2, &lenOffset); if (rv != SECSuccess) { return SECFailure; } + /* Encode the ciphertext in place. */ rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem, - outItem.data, &len, outItem.len, in, inLen); + SSL_BUFFER_NEXT(&buf), &len, + SSL_BUFFER_SPACE(&buf), in, inLen); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_Skip(&buf, len, NULL); if (rv != SECSuccess) { return SECFailure; } - outItem.data += len; - outItem.len -= len; - - /* Now encode the ciphertext length. */ - rv = ssl3_AppendNumberToItem(&lengthBytesItem, len, 2); + rv = sslBuffer_InsertLength(&buf, lenOffset, 2); if (rv != SECSuccess) { return SECFailure; } - /* MAC the entire output buffer and append the MAC to the end. */ + /* MAC the entire output buffer into the output. */ + PORT_Assert(buf.space - buf.len >= SHA256_LENGTH); rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, - out, outItem.data - out, - mac, &macLen, sizeof(mac)); + SSL_BUFFER_BASE(&buf), /* input */ + SSL_BUFFER_LEN(&buf), + SSL_BUFFER_NEXT(&buf), &len, /* output */ + SHA256_LENGTH); if (rv != SECSuccess) { return SECFailure; } - PORT_Assert(macLen == sizeof(mac)); - - rv = ssl3_AppendToItem(&outItem, mac, macLen); + rv = sslBuffer_Skip(&buf, len, NULL); if (rv != SECSuccess) { return SECFailure; } - *outLen = outItem.data - out; + *outLen = SSL_BUFFER_LEN(&buf); return SECSuccess; } @@ -269,6 +269,17 @@ ssl_SelfEncryptUnprotectInt( } #endif +/* Predict the size of the encrypted data, including padding */ +unsigned int +ssl_SelfEncryptGetProtectedSize(unsigned int inLen) +{ + return SELF_ENCRYPT_KEY_NAME_LEN + + AES_BLOCK_SIZE + + 2 + + ((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */ + SHA256_LENGTH; +} + SECStatus ssl_SelfEncryptProtect( sslSocket *ss, const PRUint8 *in, unsigned int inLen, diff --git a/security/nss/lib/ssl/selfencrypt.h b/security/nss/lib/ssl/selfencrypt.h index 5bc8e4348..5415ac09f 100644 --- a/security/nss/lib/ssl/selfencrypt.h +++ b/security/nss/lib/ssl/selfencrypt.h @@ -11,6 +11,7 @@ #include "secmodt.h" +unsigned int ssl_SelfEncryptGetProtectedSize(unsigned int inLen); SECStatus ssl_SelfEncryptProtect( sslSocket *ss, const PRUint8 *in, unsigned int inLen, PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); diff --git a/security/nss/lib/ssl/ssl.def b/security/nss/lib/ssl/ssl.def index 94d304223..9a447dbef 100644 --- a/security/nss/lib/ssl/ssl.def +++ b/security/nss/lib/ssl/ssl.def @@ -234,3 +234,9 @@ SSL_AlertSentCallback; ;+ local: ;+*; ;+}; +;+NSS_3.33 { # NSS 3.33 release +;+ global: +SSL_GetExperimentalAPI; +;+ local: +;+*; +;+}; diff --git a/security/nss/lib/ssl/ssl.gyp b/security/nss/lib/ssl/ssl.gyp index 03b2d6014..3694ab91a 100644 --- a/security/nss/lib/ssl/ssl.gyp +++ b/security/nss/lib/ssl/ssl.gyp @@ -13,18 +13,20 @@ 'authcert.c', 'cmpcert.c', 'dtlscon.c', + 'dtls13con.c', 'prelib.c', 'selfencrypt.c', 'ssl3con.c', 'ssl3ecc.c', - 'ssl3encode.c', 'ssl3ext.c', 'ssl3exthandle.c', 'ssl3gthr.c', 'sslauth.c', + 'sslbloom.c', 'sslcert.c', 'sslcon.c', 'ssldef.c', + 'sslencode.c', 'sslenum.c', 'sslerr.c', 'sslerrstrs.c', @@ -37,11 +39,14 @@ 'sslsecur.c', 'sslsnce.c', 'sslsock.c', + 'sslspec.c', 'ssltrace.c', 'sslver.c', 'tls13con.c', 'tls13exthandle.c', + 'tls13hashstate.c', 'tls13hkdf.c', + 'tls13replay.c', ], 'conditions': [ [ 'OS=="win"', { @@ -57,14 +62,6 @@ 'unix_err.c' ], }], - [ 'ssl_enable_zlib==1', { - 'dependencies': [ - '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib' - ], - 'defines': [ - 'NSS_SSL_ENABLE_ZLIB', - ], - }], [ 'fuzz_tls==1', { 'defines': [ 'UNSAFE_FUZZER_MODE', diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index 7e538ac1f..25aabbaa2 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -107,8 +107,7 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); #define SSL_NO_LOCKS 17 /* Don't use locks for protection */ #define SSL_ENABLE_SESSION_TICKETS 18 /* Enable TLS SessionTicket */ /* extension (off by default) */ -#define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */ - /* DEFLATE (off by default) */ +#define SSL_ENABLE_DEFLATE 19 /* (unsupported, deprecated, off) */ #define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */ #define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signaling */ /* Cipher Suite Value (SCSV) or */ @@ -231,25 +230,46 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); * parameters. * * The transition between the 0-RTT and 1-RTT modes is marked by the - * handshake callback. + * handshake callback. However, it is possible to force the completion + * of the handshake (and cause the handshake callback to be called) + * prior to reading all 0-RTT data using SSL_ForceHandshake(). To + * ensure that all early data is read before the handshake callback, any + * time that SSL_ForceHandshake() returns a PR_WOULD_BLOCK_ERROR, use + * PR_Read() to read all available data. If PR_Read() is called + * multiple times, this will result in the handshake completing, but the + * handshake callback will occur after early data has all been read. * * WARNING: 0-RTT data has different anti-replay and PFS properties than - * the rest of the TLS data. See [draft-ietf-tls-tls13; Section 6.2.3] + * the rest of the TLS data. See [draft-ietf-tls-tls13; Section 8] * for more details. + * + * Note: when DTLS 1.3 is in use, any 0-RTT data received after EndOfEarlyData + * (e.g., because of reordering) is discarded. */ #define SSL_ENABLE_0RTT_DATA 33 +/* 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 + #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ -SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on); -SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on); +SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on); +SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRIntn on); #endif -/* New function names */ -SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRBool on); -SSL_IMPORT SECStatus SSL_OptionGet(PRFileDesc *fd, PRInt32 option, PRBool *on); -SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRBool on); -SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRBool *on); +/* Set (and get) options for sockets and defaults for newly created sockets. + * + * While the |val| parameter of these methods is PRIntn, options only support + * two values by default: PR_TRUE or PR_FALSE. The documentation of specific + * options will explain if other values are permitted. + */ +SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRIntn val); +SSL_IMPORT SECStatus SSL_OptionGet(PRFileDesc *fd, PRInt32 option, PRIntn *val); +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 @@ -1374,6 +1394,13 @@ extern const char *NSSSSL_GetVersion(void); */ SSL_IMPORT SECStatus SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error); + +/* + * This is used to access experimental APIs. Don't call this directly. This is + * used to enable the experimental APIs that are defined in "sslexp.h". + */ +SSL_IMPORT void *SSL_GetExperimentalAPI(const char *name); + SEC_END_PROTOS #endif /* __ssl_h_ */ diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 5cbe2bd09..61878ae99 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -34,14 +34,13 @@ #include "blapi.h" #include <stdio.h> -#ifdef NSS_SSL_ENABLE_ZLIB -#include "zlib.h" -#endif static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, PK11SlotInfo *serverKeySlot); -static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); -static SECStatus ssl3_DeriveConnectionKeys(sslSocket *ss); +static SECStatus ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms, + PK11SymKey **msp); +static SECStatus ssl3_DeriveConnectionKeys(sslSocket *ss, + PK11SymKey *masterSecret); static SECStatus ssl3_HandshakeFailure(sslSocket *ss); static SECStatus ssl3_SendCertificate(sslSocket *ss); static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); @@ -51,27 +50,28 @@ static SECStatus ssl3_SendServerHelloDone(sslSocket *ss); static SECStatus ssl3_SendServerKeyExchange(sslSocket *ss); static SECStatus ssl3_HandleClientHelloPart2(sslSocket *ss, SECItem *suites, - SECItem *comps, - sslSessionID *sid); + sslSessionID *sid, + const PRUint8 *msg, + unsigned int len); static SECStatus ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, int *retErrCode); static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, - PRUint32 length, - SSL3Hashes *hashesPtr); + PRUint32 length); static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); -static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, - int maxOutputLen, const unsigned char *input, - int inputLen); - static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType); static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash); PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme); -#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */ -#define MIN_SEND_BUF_LENGTH 4000 +const PRUint8 ssl_hello_retry_random[] = { + 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C +}; +PR_STATIC_ASSERT(PR_ARRAY_SIZE(ssl_hello_retry_random) == SSL3_RANDOM_LENGTH); /* This list of SSL3 cipher suites is sorted in descending order of * precedence (desirability). It only includes cipher suites we implement. @@ -214,52 +214,6 @@ ssl3_CheckCipherSuiteOrderConsistency() } #endif -/* This list of SSL3 compression methods is sorted in descending order of - * precedence (desirability). It only includes compression methods we - * implement. - */ -static const SSLCompressionMethod ssl_compression_methods[] = { -#ifdef NSS_SSL_ENABLE_ZLIB - ssl_compression_deflate, -#endif - ssl_compression_null -}; - -static const unsigned int ssl_compression_method_count = - PR_ARRAY_SIZE(ssl_compression_methods); - -/* compressionEnabled returns true iff the compression algorithm is enabled - * for the given SSL socket. */ -static PRBool -ssl_CompressionEnabled(sslSocket *ss, SSLCompressionMethod compression) -{ - SSL3ProtocolVersion version; - - if (compression == ssl_compression_null) { - return PR_TRUE; /* Always enabled */ - } - if (ss->sec.isServer) { - /* We can't easily check that the client didn't attempt TLS 1.3, - * so this will have to do. */ - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - version = ss->version; - } else { - version = ss->vrange.max; - } - if (version >= SSL_LIBRARY_VERSION_TLS_1_3) { - return PR_FALSE; - } -#ifdef NSS_SSL_ENABLE_ZLIB - if (compression == ssl_compression_deflate) { - if (IS_DTLS(ss)) { - return PR_FALSE; - } - return ss->opt.enableDeflate; - } -#endif - return PR_FALSE; -} - static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = { ct_RSA_sign, ct_ECDSA_sign, @@ -268,173 +222,125 @@ static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = { static SSL3Statistics ssl3stats; -/* Record protection algorithms, indexed by SSL3BulkCipher. - * - * The |max_records| field (|mr| below) is set to a number that is higher than - * recommended in some literature (esp. TLS 1.3) because we currently abort the - * connection when this limit is reached and we want to ensure that we only - * rarely hit this limit. See bug 1268745 for details. - */ -#define MR_MAX RECORD_SEQ_MAX /* 2^48-1 */ -#define MR_128 (0x5aULL << 28) /* For AES and similar. */ -#define MR_LOW (1ULL << 20) /* For weak ciphers. */ -/* clang-format off */ -static const ssl3BulkCipherDef bulk_cipher_defs[] = { - /* |--------- Lengths ---------| */ - /* cipher calg : s : */ - /* : e b n */ - /* oid short_name mr : l o */ - /* k r o t n */ - /* e e i c a c */ - /* y t type v k g e */ - {cipher_null, calg_null, 0, 0, type_stream, 0, 0, 0, 0, - SEC_OID_NULL_CIPHER, "NULL", MR_MAX}, - {cipher_rc4, calg_rc4, 16,16, type_stream, 0, 0, 0, 0, - SEC_OID_RC4, "RC4", MR_LOW}, - {cipher_des, calg_des, 8, 8, type_block, 8, 8, 0, 0, - SEC_OID_DES_CBC, "DES-CBC", MR_LOW}, - {cipher_3des, calg_3des, 24,24, type_block, 8, 8, 0, 0, - SEC_OID_DES_EDE3_CBC, "3DES-EDE-CBC", MR_LOW}, - {cipher_aes_128, calg_aes, 16,16, type_block, 16,16, 0, 0, - SEC_OID_AES_128_CBC, "AES-128", MR_128}, - {cipher_aes_256, calg_aes, 32,32, type_block, 16,16, 0, 0, - SEC_OID_AES_256_CBC, "AES-256", MR_128}, - {cipher_camellia_128, calg_camellia, 16,16, type_block, 16,16, 0, 0, - SEC_OID_CAMELLIA_128_CBC, "Camellia-128", MR_128}, - {cipher_camellia_256, calg_camellia, 32,32, type_block, 16,16, 0, 0, - SEC_OID_CAMELLIA_256_CBC, "Camellia-256", MR_128}, - {cipher_seed, calg_seed, 16,16, type_block, 16,16, 0, 0, - SEC_OID_SEED_CBC, "SEED-CBC", MR_128}, - {cipher_aes_128_gcm, calg_aes_gcm, 16,16, type_aead, 4, 0,16, 8, - SEC_OID_AES_128_GCM, "AES-128-GCM", MR_128}, - {cipher_aes_256_gcm, calg_aes_gcm, 32,32, type_aead, 4, 0,16, 8, - SEC_OID_AES_256_GCM, "AES-256-GCM", MR_128}, - {cipher_chacha20, calg_chacha20, 32,32, type_aead, 12, 0,16, 0, - SEC_OID_CHACHA20_POLY1305, "ChaCha20-Poly1305", MR_MAX}, - {cipher_missing, calg_null, 0, 0, type_stream, 0, 0, 0, 0, - SEC_OID_UNKNOWN, "missing", 0U}, -}; - static const ssl3KEADef kea_defs[] = -{ /* indexed by SSL3KeyExchangeAlgorithm */ - /* kea exchKeyType signKeyType authKeyType ephemeral oid */ - {kea_null, ssl_kea_null, nullKey, ssl_auth_null, PR_FALSE, 0}, - {kea_rsa, ssl_kea_rsa, nullKey, ssl_auth_rsa_decrypt, PR_FALSE, SEC_OID_TLS_RSA}, - {kea_dh_dss, ssl_kea_dh, dsaKey, ssl_auth_dsa, PR_FALSE, SEC_OID_TLS_DH_DSS}, - {kea_dh_rsa, ssl_kea_dh, rsaKey, ssl_auth_rsa_sign, PR_FALSE, SEC_OID_TLS_DH_RSA}, - {kea_dhe_dss, ssl_kea_dh, dsaKey, ssl_auth_dsa, PR_TRUE, SEC_OID_TLS_DHE_DSS}, - {kea_dhe_rsa, ssl_kea_dh, rsaKey, ssl_auth_rsa_sign, PR_TRUE, SEC_OID_TLS_DHE_RSA}, - {kea_dh_anon, ssl_kea_dh, nullKey, ssl_auth_null, PR_TRUE, SEC_OID_TLS_DH_ANON}, - {kea_ecdh_ecdsa, ssl_kea_ecdh, nullKey, ssl_auth_ecdh_ecdsa, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA}, - {kea_ecdhe_ecdsa, ssl_kea_ecdh, ecKey, ssl_auth_ecdsa, PR_TRUE, SEC_OID_TLS_ECDHE_ECDSA}, - {kea_ecdh_rsa, ssl_kea_ecdh, nullKey, ssl_auth_ecdh_rsa, PR_FALSE, SEC_OID_TLS_ECDH_RSA}, - {kea_ecdhe_rsa, ssl_kea_ecdh, rsaKey, ssl_auth_rsa_sign, PR_TRUE, SEC_OID_TLS_ECDHE_RSA}, - {kea_ecdh_anon, ssl_kea_ecdh, nullKey, ssl_auth_null, PR_TRUE, SEC_OID_TLS_ECDH_ANON}, - {kea_ecdhe_psk, ssl_kea_ecdh_psk, nullKey, ssl_auth_psk, PR_TRUE, SEC_OID_TLS_ECDHE_PSK}, - {kea_dhe_psk, ssl_kea_dh_psk, nullKey, ssl_auth_psk, PR_TRUE, SEC_OID_TLS_DHE_PSK}, - {kea_tls13_any, ssl_kea_tls13_any, nullKey, ssl_auth_tls13_any, PR_TRUE, SEC_OID_TLS13_KEA_ANY}, -}; + { + /* indexed by SSL3KeyExchangeAlgorithm */ + /* kea exchKeyType signKeyType authKeyType ephemeral oid */ + { kea_null, ssl_kea_null, nullKey, ssl_auth_null, PR_FALSE, 0 }, + { kea_rsa, ssl_kea_rsa, nullKey, ssl_auth_rsa_decrypt, PR_FALSE, SEC_OID_TLS_RSA }, + { kea_dh_dss, ssl_kea_dh, dsaKey, ssl_auth_dsa, PR_FALSE, SEC_OID_TLS_DH_DSS }, + { kea_dh_rsa, ssl_kea_dh, rsaKey, ssl_auth_rsa_sign, PR_FALSE, SEC_OID_TLS_DH_RSA }, + { kea_dhe_dss, ssl_kea_dh, dsaKey, ssl_auth_dsa, PR_TRUE, SEC_OID_TLS_DHE_DSS }, + { kea_dhe_rsa, ssl_kea_dh, rsaKey, ssl_auth_rsa_sign, PR_TRUE, SEC_OID_TLS_DHE_RSA }, + { kea_dh_anon, ssl_kea_dh, nullKey, ssl_auth_null, PR_TRUE, SEC_OID_TLS_DH_ANON }, + { kea_ecdh_ecdsa, ssl_kea_ecdh, nullKey, ssl_auth_ecdh_ecdsa, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA }, + { kea_ecdhe_ecdsa, ssl_kea_ecdh, ecKey, ssl_auth_ecdsa, PR_TRUE, SEC_OID_TLS_ECDHE_ECDSA }, + { kea_ecdh_rsa, ssl_kea_ecdh, nullKey, ssl_auth_ecdh_rsa, PR_FALSE, SEC_OID_TLS_ECDH_RSA }, + { kea_ecdhe_rsa, ssl_kea_ecdh, rsaKey, ssl_auth_rsa_sign, PR_TRUE, SEC_OID_TLS_ECDHE_RSA }, + { kea_ecdh_anon, ssl_kea_ecdh, nullKey, ssl_auth_null, PR_TRUE, SEC_OID_TLS_ECDH_ANON }, + { kea_ecdhe_psk, ssl_kea_ecdh_psk, nullKey, ssl_auth_psk, PR_TRUE, SEC_OID_TLS_ECDHE_PSK }, + { kea_dhe_psk, ssl_kea_dh_psk, nullKey, ssl_auth_psk, PR_TRUE, SEC_OID_TLS_DHE_PSK }, + { kea_tls13_any, ssl_kea_tls13_any, nullKey, ssl_auth_tls13_any, PR_TRUE, SEC_OID_TLS13_KEA_ANY }, + }; /* must use ssl_LookupCipherSuiteDef to access */ static const ssl3CipherSuiteDef cipher_suite_defs[] = -{ -/* cipher_suite bulk_cipher_alg mac_alg key_exchange_alg prf_hash */ -/* Note that the prf_hash_alg is the hash function used by the PRF, see sslimpl.h. */ - - {TLS_NULL_WITH_NULL_NULL, cipher_null, mac_null, kea_null, ssl_hash_none}, - {TLS_RSA_WITH_NULL_MD5, cipher_null, mac_md5, kea_rsa, ssl_hash_none}, - {TLS_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_RSA_WITH_NULL_SHA256, cipher_null, hmac_sha256, kea_rsa, ssl_hash_sha256}, - {TLS_RSA_WITH_RC4_128_MD5, cipher_rc4, mac_md5, kea_rsa, ssl_hash_none}, - {TLS_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_DHE_DSS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_dss, ssl_hash_none}, - {TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, - cipher_3des, mac_sha, kea_dhe_dss, ssl_hash_none}, - {TLS_DHE_DSS_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_dhe_dss, ssl_hash_none}, - {TLS_DHE_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_dhe_rsa, ssl_hash_none}, - {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - cipher_3des, mac_sha, kea_dhe_rsa, ssl_hash_none}, - - -/* New TLS cipher suites */ - {TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_rsa, ssl_hash_sha256}, - {TLS_DHE_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_dss, ssl_hash_none}, - {TLS_DHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_dhe_rsa, ssl_hash_none}, - {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_rsa, ssl_hash_sha256}, - {TLS_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_rsa, ssl_hash_sha256}, - {TLS_DHE_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_dss, ssl_hash_none}, - {TLS_DHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_dhe_rsa, ssl_hash_none}, - {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_rsa, ssl_hash_sha256}, - {TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_rsa, ssl_hash_sha384}, - - {TLS_RSA_WITH_SEED_CBC_SHA, cipher_seed, mac_sha, kea_rsa, ssl_hash_none}, - - {TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, - cipher_camellia_128, mac_sha, kea_dhe_dss, ssl_hash_none}, - {TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, - cipher_camellia_128, mac_sha, kea_dhe_rsa, ssl_hash_none}, - {TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, cipher_camellia_256, mac_sha, kea_rsa, ssl_hash_none}, - {TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, - cipher_camellia_256, mac_sha, kea_dhe_dss, ssl_hash_none}, - {TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, - cipher_camellia_256, mac_sha, kea_dhe_rsa, ssl_hash_none}, - - {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa, ssl_hash_sha256}, - {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa, ssl_hash_sha256}, - - {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa, ssl_hash_sha256}, - {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256}, - {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha384}, - {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_rsa, ssl_hash_sha384}, - {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_ecdsa, ssl_hash_sha384}, - {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_rsa, ssl_hash_sha384}, - {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss, ssl_hash_sha256}, - {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss, ssl_hash_sha256}, - {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss, ssl_hash_sha256}, - {TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_dss, ssl_hash_sha384}, - {TLS_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_rsa, ssl_hash_sha384}, - - {TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_dhe_rsa, ssl_hash_sha256}, - - {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_rsa, ssl_hash_sha256}, - {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256}, - - {TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_ecdsa, ssl_hash_none}, - {TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_ecdsa, ssl_hash_none}, - {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa, ssl_hash_none}, - {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa, ssl_hash_none}, - {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa, ssl_hash_none}, - - {TLS_ECDHE_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none}, - {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none}, - {TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_ecdsa, ssl_hash_sha256}, - {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none}, - - {TLS_ECDH_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_rsa, ssl_hash_none}, - {TLS_ECDH_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_rsa, ssl_hash_none}, - {TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_rsa, ssl_hash_none}, - {TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_rsa, ssl_hash_none}, - {TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_rsa, ssl_hash_none}, - - {TLS_ECDHE_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_rsa, ssl_hash_none}, - {TLS_ECDHE_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_rsa, ssl_hash_none}, - {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_rsa, ssl_hash_none}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa, ssl_hash_none}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_rsa, ssl_hash_sha256}, - {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_rsa, ssl_hash_none}, - - {TLS_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_tls13_any, ssl_hash_sha256}, - {TLS_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_tls13_any, ssl_hash_sha256}, - {TLS_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_tls13_any, ssl_hash_sha384}, -}; -/* clang-format on */ + { + /* cipher_suite bulk_cipher_alg mac_alg key_exchange_alg prf_hash */ + /* Note that the prf_hash_alg is the hash function used by the PRF, see sslimpl.h. */ + + { TLS_NULL_WITH_NULL_NULL, cipher_null, ssl_mac_null, kea_null, ssl_hash_none }, + { TLS_RSA_WITH_NULL_MD5, cipher_null, ssl_mac_md5, kea_rsa, ssl_hash_none }, + { TLS_RSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_RSA_WITH_NULL_SHA256, cipher_null, ssl_hmac_sha256, kea_rsa, ssl_hash_sha256 }, + { TLS_RSA_WITH_RC4_128_MD5, cipher_rc4, ssl_mac_md5, kea_rsa, ssl_hash_none }, + { TLS_RSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_RSA_WITH_DES_CBC_SHA, cipher_des, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_DHE_DSS_WITH_DES_CBC_SHA, cipher_des, ssl_mac_sha, kea_dhe_dss, ssl_hash_none }, + { TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + cipher_3des, ssl_mac_sha, kea_dhe_dss, ssl_hash_none }, + { TLS_DHE_DSS_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_dhe_dss, ssl_hash_none }, + { TLS_DHE_RSA_WITH_DES_CBC_SHA, cipher_des, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none }, + { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + cipher_3des, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none }, + + /* New TLS cipher suites */ + { TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_rsa, ssl_hash_sha256 }, + { TLS_DHE_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_dhe_dss, ssl_hash_none }, + { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none }, + { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_dhe_rsa, ssl_hash_sha256 }, + { TLS_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, ssl_hmac_sha256, kea_rsa, ssl_hash_sha256 }, + { TLS_DHE_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_dhe_dss, ssl_hash_none }, + { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none }, + { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, ssl_hmac_sha256, kea_dhe_rsa, ssl_hash_sha256 }, + { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_dhe_rsa, ssl_hash_sha384 }, + + { TLS_RSA_WITH_SEED_CBC_SHA, cipher_seed, ssl_mac_sha, kea_rsa, ssl_hash_none }, + + { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, + cipher_camellia_128, ssl_mac_sha, kea_dhe_dss, ssl_hash_none }, + { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + cipher_camellia_128, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none }, + { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, cipher_camellia_256, ssl_mac_sha, kea_rsa, ssl_hash_none }, + { TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, + cipher_camellia_256, ssl_mac_sha, kea_dhe_dss, ssl_hash_none }, + { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + cipher_camellia_256, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none }, + + { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_dhe_rsa, ssl_hash_sha256 }, + { TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_rsa, ssl_hash_sha256 }, + + { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_ecdhe_rsa, ssl_hash_sha256 }, + { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256 }, + { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha384 }, + { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_ecdhe_rsa, ssl_hash_sha384 }, + { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, ssl_hmac_sha384, kea_ecdhe_ecdsa, ssl_hash_sha384 }, + { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, ssl_hmac_sha384, kea_ecdhe_rsa, ssl_hash_sha384 }, + { TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_dhe_dss, ssl_hash_sha256 }, + { TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_dhe_dss, ssl_hash_sha256 }, + { TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, ssl_hmac_sha256, kea_dhe_dss, ssl_hash_sha256 }, + { TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_dhe_dss, ssl_hash_sha384 }, + { TLS_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_rsa, ssl_hash_sha384 }, + + { TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_dhe_rsa, ssl_hash_sha256 }, + + { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_ecdhe_rsa, ssl_hash_sha256 }, + { TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256 }, + + { TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none }, + { TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none }, + { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none }, + { TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none }, + { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none }, + + { TLS_ECDHE_ECDSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none }, + { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none }, + { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none }, + { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none }, + { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_ecdhe_ecdsa, ssl_hash_sha256 }, + { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none }, + + { TLS_ECDH_RSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none }, + { TLS_ECDH_RSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none }, + { TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none }, + { TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none }, + { TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none }, + + { TLS_ECDHE_RSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none }, + { TLS_ECDHE_RSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none }, + { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none }, + { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none }, + { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_ecdhe_rsa, ssl_hash_sha256 }, + { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none }, + + { TLS_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_tls13_any, ssl_hash_sha256 }, + { TLS_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_tls13_any, ssl_hash_sha256 }, + { TLS_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_tls13_any, ssl_hash_sha384 }, + }; static const CK_MECHANISM_TYPE auth_alg_defs[] = { CKM_INVALID_MECHANISM, /* ssl_auth_null */ @@ -471,44 +377,20 @@ typedef struct SSLCipher2MechStr { /* indexed by type SSLCipherAlgorithm */ static const SSLCipher2Mech alg2Mech[] = { /* calg, cmech */ - { calg_null, (CK_MECHANISM_TYPE)0x80000000L }, - { calg_rc4, CKM_RC4 }, - { calg_rc2, CKM_RC2_CBC }, - { calg_des, CKM_DES_CBC }, - { calg_3des, CKM_DES3_CBC }, - { calg_idea, CKM_IDEA_CBC }, - { calg_fortezza, CKM_SKIPJACK_CBC64 }, - { calg_aes, CKM_AES_CBC }, - { calg_camellia, CKM_CAMELLIA_CBC }, - { calg_seed, CKM_SEED_CBC }, - { calg_aes_gcm, CKM_AES_GCM }, - { calg_chacha20, CKM_NSS_CHACHA20_POLY1305 }, - /* { calg_init , (CK_MECHANISM_TYPE)0x7fffffffL } */ + { ssl_calg_null, CKM_INVALID_MECHANISM }, + { ssl_calg_rc4, CKM_RC4 }, + { ssl_calg_rc2, CKM_RC2_CBC }, + { ssl_calg_des, CKM_DES_CBC }, + { ssl_calg_3des, CKM_DES3_CBC }, + { ssl_calg_idea, CKM_IDEA_CBC }, + { ssl_calg_fortezza, CKM_SKIPJACK_CBC64 }, + { ssl_calg_aes, CKM_AES_CBC }, + { ssl_calg_camellia, CKM_CAMELLIA_CBC }, + { ssl_calg_seed, CKM_SEED_CBC }, + { ssl_calg_aes_gcm, CKM_AES_GCM }, + { ssl_calg_chacha20, CKM_NSS_CHACHA20_POLY1305 }, }; -#define mmech_invalid (CK_MECHANISM_TYPE)0x80000000L -#define mmech_md5 CKM_SSL3_MD5_MAC -#define mmech_sha CKM_SSL3_SHA1_MAC -#define mmech_md5_hmac CKM_MD5_HMAC -#define mmech_sha_hmac CKM_SHA_1_HMAC -#define mmech_sha256_hmac CKM_SHA256_HMAC -#define mmech_sha384_hmac CKM_SHA384_HMAC - -/* clang-format off */ -static const ssl3MACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */ - /* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */ - /* mac mmech pad_size mac_size */ - { mac_null, mmech_invalid, 0, 0 , 0}, - { mac_md5, mmech_md5, 48, MD5_LENGTH, SEC_OID_HMAC_MD5 }, - { mac_sha, mmech_sha, 40, SHA1_LENGTH, SEC_OID_HMAC_SHA1}, - {hmac_md5, mmech_md5_hmac, 0, MD5_LENGTH, SEC_OID_HMAC_MD5}, - {hmac_sha, mmech_sha_hmac, 0, SHA1_LENGTH, SEC_OID_HMAC_SHA1}, - {hmac_sha256, mmech_sha256_hmac, 0, SHA256_LENGTH, SEC_OID_HMAC_SHA256}, - { mac_aead, mmech_invalid, 0, 0, 0 }, - {hmac_sha384, mmech_sha384_hmac, 0, SHA384_LENGTH, SEC_OID_HMAC_SHA384} -}; -/* clang-format on */ - const PRUint8 tls13_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x01 }; const PRUint8 tls12_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E, @@ -554,48 +436,57 @@ ssl3_DecodeHandshakeType(int msgType) static char line[40]; switch (msgType) { - case hello_request: + case ssl_hs_hello_request: rv = "hello_request (0)"; break; - case client_hello: + case ssl_hs_client_hello: rv = "client_hello (1)"; break; - case server_hello: + case ssl_hs_server_hello: rv = "server_hello (2)"; break; - case hello_verify_request: + case ssl_hs_hello_verify_request: rv = "hello_verify_request (3)"; break; - case new_session_ticket: - rv = "session_ticket (4)"; + case ssl_hs_new_session_ticket: + rv = "new_session_ticket (4)"; + break; + case ssl_hs_end_of_early_data: + rv = "end_of_early_data (5)"; break; - case hello_retry_request: + case ssl_hs_hello_retry_request: rv = "hello_retry_request (6)"; break; - case encrypted_extensions: + case ssl_hs_encrypted_extensions: rv = "encrypted_extensions (8)"; break; - case certificate: + case ssl_hs_certificate: rv = "certificate (11)"; break; - case server_key_exchange: + case ssl_hs_server_key_exchange: rv = "server_key_exchange (12)"; break; - case certificate_request: + case ssl_hs_certificate_request: rv = "certificate_request (13)"; break; - case server_hello_done: + case ssl_hs_server_hello_done: rv = "server_hello_done (14)"; break; - case certificate_verify: + case ssl_hs_certificate_verify: rv = "certificate_verify (15)"; break; - case client_key_exchange: + case ssl_hs_client_key_exchange: rv = "client_key_exchange (16)"; break; - case finished: + case ssl_hs_finished: rv = "finished (20)"; break; + case ssl_hs_certificate_status: + rv = "certificate_status (22)"; + break; + case ssl_hs_key_update: + rv = "key_update (24)"; + break; default: sprintf(line, "*UNKNOWN* handshake type! (%d)", msgType); rv = line; @@ -622,6 +513,9 @@ ssl3_DecodeContentType(int msgType) case content_application_data: rv = "application_data (23)"; break; + case content_ack: + rv = "ack (25)"; + break; default: sprintf(line, "*UNKNOWN* record type! (%d)", msgType); rv = line; @@ -874,20 +768,12 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType) return PR_FALSE; } -const ssl3BulkCipherDef * -ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def) -{ - PORT_Assert(cipher_def->bulk_cipher_alg < PR_ARRAY_SIZE(bulk_cipher_defs)); - PORT_Assert(bulk_cipher_defs[cipher_def->bulk_cipher_alg].cipher == cipher_def->bulk_cipher_alg); - return &bulk_cipher_defs[cipher_def->bulk_cipher_alg]; -} - /* Initialize the suite->isPresent value for config_match * Returns count of enabled ciphers supported by extant tokens, * regardless of policy or user preference. * If this returns zero, the user cannot do SSL v3. */ -int +unsigned int ssl3_config_match_init(sslSocket *ss) { ssl3CipherSuiteCfg *suite; @@ -896,9 +782,9 @@ ssl3_config_match_init(sslSocket *ss) CK_MECHANISM_TYPE cipher_mech; SSLAuthType authType; SSLKEAType keaType; - int i; - int numPresent = 0; - int numEnabled = 0; + unsigned int i; + unsigned int numPresent = 0; + unsigned int numEnabled = 0; PORT_Assert(ss); if (!ss) { @@ -909,6 +795,7 @@ ssl3_config_match_init(sslSocket *ss) return 0; } + ssl_FilterSupportedGroups(ss); for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { suite = &ss->cipherSuites[i]; if (suite->enabled) { @@ -944,7 +831,7 @@ ssl3_config_match_init(sslSocket *ss) suite->isPresent = PR_FALSE; } - if (cipher_alg != calg_null && + if (cipher_alg != ssl_calg_null && !PK11_TokenExists(cipher_mech)) { suite->isPresent = PR_FALSE; } @@ -955,7 +842,7 @@ ssl3_config_match_init(sslSocket *ss) } } PORT_Assert(numPresent > 0 || numEnabled == 0); - if (numPresent <= 0) { + if (numPresent == 0) { PORT_SetError(SSL_ERROR_NO_CIPHERS_SUPPORTED); } return numPresent; @@ -1000,10 +887,10 @@ config_match(const ssl3CipherSuiteCfg *suite, int policy, /* Return the number of cipher suites that are usable. */ /* called from ssl3_SendClientHello */ -static int +static unsigned int count_cipher_suites(sslSocket *ss, int policy) { - int i, count = 0; + unsigned int i, count = 0; if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) { return 0; @@ -1012,7 +899,7 @@ count_cipher_suites(sslSocket *ss, int policy) if (config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss)) count++; } - if (count <= 0) { + if (count == 0) { PORT_SetError(SSL_ERROR_SSL_DISABLED); } return count; @@ -1021,7 +908,7 @@ count_cipher_suites(sslSocket *ss, int policy) /* * Null compression, mac and encryption functions */ -static SECStatus +SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, const unsigned char *input, int inputLen) { @@ -1041,6 +928,19 @@ Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, * SSL3 Utility functions */ +static void +ssl_SetSpecVersions(sslSocket *ss, ssl3CipherSpec *spec) +{ + spec->version = ss->version; + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + tls13_SetSpecRecordVersion(ss, spec); + } else if (IS_DTLS(ss)) { + spec->recordVersion = dtls_TLSVersionToDTLSVersion(ss->version); + } else { + spec->recordVersion = ss->version; + } +} + /* allowLargerPeerVersion controls whether the function will select the * highest enabled SSL version or fail when peerVersion is greater than the * highest enabled version. @@ -1052,6 +952,8 @@ SECStatus ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion, PRBool allowLargerPeerVersion) { + SSL3ProtocolVersion negotiated; + if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) { PORT_SetError(SSL_ERROR_SSL_DISABLED); return SECFailure; @@ -1063,9 +965,14 @@ ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion, return SECFailure; } - ss->version = PR_MIN(peerVersion, ss->vrange.max); - PORT_Assert(ssl3_VersionIsSupported(ss->protocolVariant, ss->version)); + negotiated = PR_MIN(peerVersion, ss->vrange.max); + PORT_Assert(ssl3_VersionIsSupported(ss->protocolVariant, negotiated)); + if (ss->firstHsDone && ss->version != negotiated) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); + return SECFailure; + } + ss->version = negotiated; return SECSuccess; } @@ -1104,24 +1011,16 @@ ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b, unsigned int *len, v = dtls_DTLSVersionToTLSVersion(v); } - PORT_Assert(!SSL_ALL_VERSIONS_DISABLED(&ss->vrange)); - if (ss->vrange.min > v || ss->vrange.max < v) { - (void)SSL3_SendAlert(ss, alert_fatal, - (v > SSL_LIBRARY_VERSION_3_0) ? protocol_version - : handshake_failure); - PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); - return SECFailure; - } *version = v; return SECSuccess; } static SECStatus -ssl3_GetNewRandom(SSL3Random *random) +ssl3_GetNewRandom(SSL3Random random) { SECStatus rv; - rv = PK11_GenerateRandom(random->rand, SSL3_RANDOM_LENGTH); + rv = PK11_GenerateRandom(random, SSL3_RANDOM_LENGTH); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); } @@ -1135,7 +1034,7 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key, { SECStatus rv = SECFailure; PRBool doDerEncode = PR_FALSE; - PRBool isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(ss->ssl3.hs.signatureScheme); SECItem hashItem; @@ -1421,124 +1320,110 @@ static SECStatus ssl3_ComputeDHKeyHash(sslSocket *ss, SSLHashType hashAlg, SSL3Hashes *hashes, SECItem dh_p, SECItem dh_g, SECItem dh_Ys, PRBool padY) { - PRUint8 *hashBuf; - PRUint8 *pBuf; - SECStatus rv = SECSuccess; - unsigned int bufLen, yLen; - PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 4096 / 8 + 2 + 4096 / 8]; + sslBuffer buf = SSL_BUFFER_EMPTY; + SECStatus rv; + unsigned int yLen; + unsigned int i; PORT_Assert(dh_p.data); PORT_Assert(dh_g.data); PORT_Assert(dh_Ys.data); - yLen = padY ? dh_p.len : dh_Ys.len; - bufLen = 2 * SSL3_RANDOM_LENGTH + - 2 + dh_p.len + - 2 + dh_g.len + - 2 + yLen; - if (bufLen <= sizeof buf) { - hashBuf = buf; - } else { - hashBuf = PORT_Alloc(bufLen); - if (!hashBuf) { - return SECFailure; - } + rv = sslBuffer_Append(&buf, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); + if (rv != SECSuccess) { + goto loser; } - - memcpy(hashBuf, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); - pBuf = hashBuf + SSL3_RANDOM_LENGTH; - memcpy(pBuf, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); - pBuf += SSL3_RANDOM_LENGTH; - pBuf = ssl_EncodeUintX(dh_p.len, 2, pBuf); - memcpy(pBuf, dh_p.data, dh_p.len); - pBuf += dh_p.len; - pBuf = ssl_EncodeUintX(dh_g.len, 2, pBuf); - memcpy(pBuf, dh_g.data, dh_g.len); - pBuf += dh_g.len; - pBuf = ssl_EncodeUintX(yLen, 2, pBuf); - if (padY && dh_p.len > dh_Ys.len) { - memset(pBuf, 0, dh_p.len - dh_Ys.len); - pBuf += dh_p.len - dh_Ys.len; + rv = sslBuffer_Append(&buf, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); + if (rv != SECSuccess) { + goto loser; + } + /* p */ + rv = sslBuffer_AppendVariable(&buf, dh_p.data, dh_p.len, 2); + if (rv != SECSuccess) { + goto loser; + } + /* g */ + rv = sslBuffer_AppendVariable(&buf, dh_g.data, dh_g.len, 2); + if (rv != SECSuccess) { + goto loser; + } + /* y - complicated by padding */ + yLen = padY ? dh_p.len : dh_Ys.len; + rv = sslBuffer_AppendNumber(&buf, yLen, 2); + if (rv != SECSuccess) { + goto loser; } /* If we're padding Y, dh_Ys can't be longer than dh_p. */ PORT_Assert(!padY || dh_p.len >= dh_Ys.len); - memcpy(pBuf, dh_Ys.data, dh_Ys.len); - pBuf += dh_Ys.len; - PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - - rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes); - - PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen)); - if (rv == SECSuccess) { - if (hashAlg == ssl_hash_none) { - PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", - hashes->u.s.md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", - hashes->u.s.sha, SHA1_LENGTH)); - } else { - PRINT_BUF(95, (NULL, "DHkey hash: result", - hashes->u.raw, hashes->len)); + for (i = dh_Ys.len; i < yLen; ++i) { + rv = sslBuffer_AppendNumber(&buf, 0, 1); + if (rv != SECSuccess) { + goto loser; } } - - if (hashBuf != buf && hashBuf != NULL) - PORT_Free(hashBuf); - return rv; -} - -/* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */ -static void -ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat) -{ - if (mat->write_key != NULL) { - PK11_FreeSymKey(mat->write_key); - mat->write_key = NULL; + rv = sslBuffer_Append(&buf, dh_Ys.data, dh_Ys.len); + if (rv != SECSuccess) { + goto loser; } - if (mat->write_mac_key != NULL) { - PK11_FreeSymKey(mat->write_mac_key); - mat->write_mac_key = NULL; + + rv = ssl3_ComputeCommonKeyHash(hashAlg, SSL_BUFFER_BASE(&buf), + SSL_BUFFER_LEN(&buf), hashes); + if (rv != SECSuccess) { + goto loser; } - if (mat->write_mac_context != NULL) { - PK11_DestroyContext(mat->write_mac_context, PR_TRUE); - mat->write_mac_context = NULL; + + PRINT_BUF(95, (NULL, "DHkey hash: ", SSL_BUFFER_BASE(&buf), + SSL_BUFFER_LEN(&buf))); + if (hashAlg == ssl_hash_none) { + PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", + hashes->u.s.md5, MD5_LENGTH)); + PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", + hashes->u.s.sha, SHA1_LENGTH)); + } else { + PRINT_BUF(95, (NULL, "DHkey hash: result", + hashes->u.raw, hashes->len)); } + + sslBuffer_Clear(&buf); + return SECSuccess; + +loser: + sslBuffer_Clear(&buf); + return SECFailure; } -/* Called from ssl3_SendChangeCipherSpecs() and -** ssl3_HandleChangeCipherSpecs() -** ssl3_DestroySSL3Info -** Caller must hold SpecWriteLock. -*/ -void -ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName) +static SECStatus +ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction, + const ssl3CipherSuiteDef *suiteDef, + ssl3CipherSpec **specp) { - /* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ - if (spec->encodeContext) { - PK11_DestroyContext(spec->encodeContext, PR_TRUE); - spec->encodeContext = NULL; - } - if (spec->decodeContext) { - PK11_DestroyContext(spec->decodeContext, PR_TRUE); - spec->decodeContext = NULL; - } - if (spec->destroyCompressContext && spec->compressContext) { - spec->destroyCompressContext(spec->compressContext, 1); - spec->compressContext = NULL; + ssl3CipherSpec *spec; + const ssl3CipherSpec *prev; + + prev = (direction == CipherSpecWrite) ? ss->ssl3.cwSpec : ss->ssl3.crSpec; + if (prev->epoch == PR_UINT16_MAX) { + PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); + return SECFailure; } - if (spec->destroyDecompressContext && spec->decompressContext) { - spec->destroyDecompressContext(spec->decompressContext, 1); - spec->decompressContext = NULL; + + spec = ssl_CreateCipherSpec(ss, direction); + if (!spec) { + return SECFailure; } - if (spec->master_secret != NULL) { - PK11_FreeSymKey(spec->master_secret); - spec->master_secret = NULL; + + spec->cipherDef = ssl_GetBulkCipherDef(suiteDef); + spec->macDef = ssl_GetMacDef(ss, suiteDef); + + spec->epoch = prev->epoch + 1; + spec->seqNum = 0; + if (IS_DTLS(ss) && direction == CipherSpecRead) { + dtls_InitRecvdRecords(&spec->recvdRecords); } - spec->msItem.data = NULL; - spec->msItem.len = 0; - ssl3_CleanupKeyMaterial(&spec->client); - ssl3_CleanupKeyMaterial(&spec->server); - spec->destroyCompressContext = NULL; - spec->destroyDecompressContext = NULL; + ssl_SetSpecVersions(ss, spec); + + ssl_SaveCipherSpec(ss, spec); + *specp = spec; + return SECSuccess; } /* Fill in the pending cipher spec with info from the selected ciphersuite. @@ -1548,272 +1433,116 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName) ** Acquires & releases SpecWriteLock. */ SECStatus -ssl3_SetupPendingCipherSpec(sslSocket *ss) +ssl3_SetupBothPendingCipherSpecs(sslSocket *ss) { - ssl3CipherSpec *pwSpec; - ssl3CipherSpec *cwSpec; ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite; - SSL3MACAlgorithm mac; SSL3KeyExchangeAlgorithm kea; - const ssl3CipherSuiteDef *suite_def; - PRBool isTLS; + const ssl3CipherSuiteDef *suiteDef; + SECStatus rv; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); ssl_GetSpecWriteLock(ss); /*******************************/ - pwSpec = ss->ssl3.pwSpec; - PORT_Assert(pwSpec == ss->ssl3.prSpec); - /* This hack provides maximal interoperability with SSL 3 servers. */ - cwSpec = ss->ssl3.cwSpec; - if (cwSpec->mac_def->mac == mac_null) { + if (ss->ssl3.cwSpec->macDef->mac == ssl_mac_null) { /* SSL records are not being MACed. */ - cwSpec->version = ss->version; + ss->ssl3.cwSpec->version = ss->version; } - pwSpec->version = ss->version; - isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0); - SSL_TRC(3, ("%d: SSL3[%d]: Set XXX Pending Cipher Suite to 0x%04x", SSL_GETPID(), ss->fd, suite)); - suite_def = ssl_LookupCipherSuiteDef(suite); - if (suite_def == NULL) { - ssl_ReleaseSpecWriteLock(ss); - return SECFailure; /* error code set by ssl_LookupCipherSuiteDef */ + suiteDef = ssl_LookupCipherSuiteDef(suite); + if (suiteDef == NULL) { + goto loser; } if (IS_DTLS(ss)) { /* Double-check that we did not pick an RC4 suite */ - PORT_Assert(suite_def->bulk_cipher_alg != cipher_rc4); + PORT_Assert(suiteDef->bulk_cipher_alg != cipher_rc4); } - kea = suite_def->key_exchange_alg; - mac = suite_def->mac_alg; - if (mac <= ssl_mac_sha && mac != ssl_mac_null && isTLS) - mac += 2; + ss->ssl3.hs.suite_def = suiteDef; - ss->ssl3.hs.suite_def = suite_def; + kea = suiteDef->key_exchange_alg; ss->ssl3.hs.kea_def = &kea_defs[kea]; PORT_Assert(ss->ssl3.hs.kea_def->kea == kea); - pwSpec->cipher_def = ssl_GetBulkCipherDef(suite_def); - - pwSpec->mac_def = &mac_defs[mac]; - PORT_Assert(pwSpec->mac_def->mac == mac); - - pwSpec->encodeContext = NULL; - pwSpec->decodeContext = NULL; - - pwSpec->mac_size = pwSpec->mac_def->mac_size; - - pwSpec->compression_method = ss->ssl3.hs.compression; - pwSpec->compressContext = NULL; - pwSpec->decompressContext = NULL; - - ssl_ReleaseSpecWriteLock(ss); /*******************************/ - return SECSuccess; -} - -#ifdef NSS_SSL_ENABLE_ZLIB -#define SSL3_DEFLATE_CONTEXT_SIZE sizeof(z_stream) - -static SECStatus -ssl3_MapZlibError(int zlib_error) -{ - switch (zlib_error) { - case Z_OK: - return SECSuccess; - default: - return SECFailure; - } -} - -static SECStatus -ssl3_DeflateInit(void *void_context) -{ - z_stream *context = void_context; - context->zalloc = NULL; - context->zfree = NULL; - context->opaque = NULL; - - return ssl3_MapZlibError(deflateInit(context, Z_DEFAULT_COMPRESSION)); -} - -static SECStatus -ssl3_InflateInit(void *void_context) -{ - z_stream *context = void_context; - context->zalloc = NULL; - context->zfree = NULL; - context->opaque = NULL; - context->next_in = NULL; - context->avail_in = 0; - - return ssl3_MapZlibError(inflateInit(context)); -} - -static SECStatus -ssl3_DeflateCompress(void *void_context, unsigned char *out, int *out_len, - int maxout, const unsigned char *in, int inlen) -{ - z_stream *context = void_context; - - if (!inlen) { - *out_len = 0; - return SECSuccess; - } - - context->next_in = (unsigned char *)in; - context->avail_in = inlen; - context->next_out = out; - context->avail_out = maxout; - if (deflate(context, Z_SYNC_FLUSH) != Z_OK) { - return SECFailure; - } - if (context->avail_out == 0) { - /* We ran out of space! */ - SSL_TRC(3, ("%d: SSL3[%d] Ran out of buffer while compressing", - SSL_GETPID())); - return SECFailure; - } - - *out_len = maxout - context->avail_out; - return SECSuccess; -} - -static SECStatus -ssl3_DeflateDecompress(void *void_context, unsigned char *out, int *out_len, - int maxout, const unsigned char *in, int inlen) -{ - z_stream *context = void_context; - - if (!inlen) { - *out_len = 0; - return SECSuccess; + rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecRead, suiteDef, + &ss->ssl3.prSpec); + if (rv != SECSuccess) { + goto loser; } - - context->next_in = (unsigned char *)in; - context->avail_in = inlen; - context->next_out = out; - context->avail_out = maxout; - if (inflate(context, Z_SYNC_FLUSH) != Z_OK) { - PORT_SetError(SSL_ERROR_DECOMPRESSION_FAILURE); - return SECFailure; + rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecWrite, suiteDef, + &ss->ssl3.pwSpec); + if (rv != SECSuccess) { + goto loser; } - *out_len = maxout - context->avail_out; - return SECSuccess; -} - -static SECStatus -ssl3_DestroyCompressContext(void *void_context, PRBool unused) -{ - deflateEnd(void_context); - PORT_Free(void_context); - return SECSuccess; -} - -static SECStatus -ssl3_DestroyDecompressContext(void *void_context, PRBool unused) -{ - inflateEnd(void_context); - PORT_Free(void_context); + ssl_ReleaseSpecWriteLock(ss); /*******************************/ return SECSuccess; -} -#endif /* NSS_SSL_ENABLE_ZLIB */ - -/* Initialize the compression functions and contexts for the given - * CipherSpec. */ -static SECStatus -ssl3_InitCompressionContext(ssl3CipherSpec *pwSpec) -{ - /* Setup the compression functions */ - switch (pwSpec->compression_method) { - case ssl_compression_null: - pwSpec->compressor = NULL; - pwSpec->decompressor = NULL; - pwSpec->compressContext = NULL; - pwSpec->decompressContext = NULL; - pwSpec->destroyCompressContext = NULL; - pwSpec->destroyDecompressContext = NULL; - break; -#ifdef NSS_SSL_ENABLE_ZLIB - case ssl_compression_deflate: - pwSpec->compressor = ssl3_DeflateCompress; - pwSpec->decompressor = ssl3_DeflateDecompress; - pwSpec->compressContext = PORT_Alloc(SSL3_DEFLATE_CONTEXT_SIZE); - pwSpec->decompressContext = PORT_Alloc(SSL3_DEFLATE_CONTEXT_SIZE); - pwSpec->destroyCompressContext = ssl3_DestroyCompressContext; - pwSpec->destroyDecompressContext = ssl3_DestroyDecompressContext; - ssl3_DeflateInit(pwSpec->compressContext); - ssl3_InflateInit(pwSpec->decompressContext); - break; -#endif /* NSS_SSL_ENABLE_ZLIB */ - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - return SECSuccess; +loser: + ssl_ReleaseSpecWriteLock(ss); + return SECFailure; } -/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data - * which is included in the MAC or AEAD additional data) to |out| and returns - * its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the - * definition of the AEAD additional data. +/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data which + * is included in the MAC or AEAD additional data) to |buf|. See + * https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the definition of the + * AEAD additional data. * * TLS pseudo-header includes the record's version field, SSL's doesn't. Which - * pseudo-header defintiion to use should be decided based on the version of + * pseudo-header definition to use should be decided based on the version of * the protocol that was negotiated when the cipher spec became current, NOT * based on the version value in the record itself, and the decision is passed * to this function as the |includesVersion| argument. But, the |version| * argument should be the record's version value. */ -static unsigned int -ssl3_BuildRecordPseudoHeader(unsigned char *out, - sslSequenceNumber seq_num, +static SECStatus +ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch, + sslSequenceNumber seqNum, SSL3ContentType type, PRBool includesVersion, SSL3ProtocolVersion version, PRBool isDTLS, - int length) -{ - out[0] = (unsigned char)(seq_num >> 56); - out[1] = (unsigned char)(seq_num >> 48); - out[2] = (unsigned char)(seq_num >> 40); - out[3] = (unsigned char)(seq_num >> 32); - out[4] = (unsigned char)(seq_num >> 24); - out[5] = (unsigned char)(seq_num >> 16); - out[6] = (unsigned char)(seq_num >> 8); - out[7] = (unsigned char)(seq_num >> 0); - out[8] = type; + int length, + sslBuffer *buf) +{ + SECStatus rv; + if (isDTLS) { + rv = sslBuffer_AppendNumber(buf, epoch, 2); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(buf, seqNum, 6); + } else { + rv = sslBuffer_AppendNumber(buf, seqNum, 8); + } + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(buf, type, 1); + if (rv != SECSuccess) { + return SECFailure; + } /* SSL3 MAC doesn't include the record's version field. */ - if (!includesVersion) { - out[9] = MSB(length); - out[10] = LSB(length); - return 11; + if (includesVersion) { + /* TLS MAC and AEAD additional data include version. */ + rv = sslBuffer_AppendNumber(buf, version, 2); + if (rv != SECSuccess) { + return SECFailure; + } } - - /* TLS MAC and AEAD additional data include version. */ - if (isDTLS) { - SSL3ProtocolVersion dtls_version; - - dtls_version = dtls_TLSVersionToDTLSVersion(version); - out[9] = MSB(dtls_version); - out[10] = LSB(dtls_version); - } else { - out[9] = MSB(version); - out[10] = LSB(version); + rv = sslBuffer_AppendNumber(buf, length, 2); + if (rv != SECSuccess) { + return SECFailure; } - out[11] = MSB(length); - out[12] = LSB(length); - return 13; + + return SECSuccess; } static SECStatus @@ -1833,13 +1562,12 @@ ssl3_AESGCM(ssl3KeyMaterial *keys, unsigned int uOutLen; CK_GCM_PARAMS gcmParams; - const int tagSize = bulk_cipher_defs[cipher_aes_128_gcm].tag_size; - const int explicitNonceLen = - bulk_cipher_defs[cipher_aes_128_gcm].explicit_nonce_size; + const int tagSize = 16; + const int explicitNonceLen = 8; /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the * nonce is formed. */ - memcpy(nonce, keys->write_iv, 4); + memcpy(nonce, keys->iv, 4); if (doDecrypt) { memcpy(nonce + 4, in, explicitNonceLen); in += explicitNonceLen; @@ -1868,10 +1596,10 @@ ssl3_AESGCM(ssl3KeyMaterial *keys, gcmParams.ulTagBits = tagSize * 8; if (doDecrypt) { - rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, + rv = PK11_Decrypt(keys->key, CKM_AES_GCM, ¶m, out, &uOutLen, maxout, in, inlen); } else { - rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, + rv = PK11_Encrypt(keys->key, CKM_AES_GCM, ¶m, out, &uOutLen, maxout, in, inlen); } *outlen += (int)uOutLen; @@ -1893,12 +1621,12 @@ ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, unsigned char nonce[12]; CK_NSS_AEAD_PARAMS aeadParams; - const int tagSize = bulk_cipher_defs[cipher_chacha20].tag_size; + const int tagSize = 16; /* See * https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2 * for details of how the nonce is formed. */ - PORT_Memcpy(nonce, keys->write_iv, 12); + PORT_Memcpy(nonce, keys->iv, 12); /* XOR the last 8 bytes of the IV with the sequence number. */ PORT_Assert(additionalDataLen >= 8); @@ -1917,10 +1645,10 @@ ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, aeadParams.ulTagLen = tagSize; if (doDecrypt) { - rv = PK11_Decrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, ¶m, + rv = PK11_Decrypt(keys->key, CKM_NSS_CHACHA20_POLY1305, ¶m, out, &uOutLen, maxout, in, inlen); } else { - rv = PK11_Encrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, ¶m, + rv = PK11_Encrypt(keys->key, CKM_NSS_CHACHA20_POLY1305, ¶m, out, &uOutLen, maxout, in, inlen); } *outlen = (int)uOutLen; @@ -1933,44 +1661,31 @@ ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, * Caller holds Spec write lock. */ static SECStatus -ssl3_InitPendingContexts(sslSocket *ss) +ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec) { - ssl3CipherSpec *pwSpec; - const ssl3BulkCipherDef *cipher_def; - PK11Context *serverContext = NULL; - PK11Context *clientContext = NULL; - SECItem *param; - CK_MECHANISM_TYPE mechanism; - CK_MECHANISM_TYPE mac_mech; + CK_MECHANISM_TYPE encMechanism; + CK_ATTRIBUTE_TYPE encMode; + SECItem macParam; CK_ULONG macLength; SECItem iv; - SECItem mac_param; SSLCipherAlgorithm calg; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - pwSpec = ss->ssl3.pwSpec; - cipher_def = pwSpec->cipher_def; - macLength = pwSpec->mac_size; - calg = cipher_def->calg; + macLength = spec->macDef->mac_size; + calg = spec->cipherDef->calg; PORT_Assert(alg2Mech[calg].calg == calg); - pwSpec->client.write_mac_context = NULL; - pwSpec->server.write_mac_context = NULL; - - if (cipher_def->type == type_aead) { - pwSpec->encode = NULL; - pwSpec->decode = NULL; - pwSpec->encodeContext = NULL; - pwSpec->decodeContext = NULL; + if (spec->cipherDef->type == type_aead) { + spec->cipher = NULL; + spec->cipherContext = NULL; switch (calg) { - case calg_aes_gcm: - pwSpec->aead = ssl3_AESGCM; + case ssl_calg_aes_gcm: + spec->aead = ssl3_AESGCM; break; - case calg_chacha20: - pwSpec->aead = ssl3_ChaCha20Poly1305; + case ssl_calg_chacha20: + spec->aead = ssl3_ChaCha20Poly1305; break; default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -1983,128 +1698,43 @@ ssl3_InitPendingContexts(sslSocket *ss) ** Now setup the MAC contexts, ** crypto contexts are setup below. */ + macParam.data = (unsigned char *)&macLength; + macParam.len = sizeof(macLength); + macParam.type = siBuffer; - mac_mech = pwSpec->mac_def->mmech; - mac_param.data = (unsigned char *)&macLength; - mac_param.len = sizeof(macLength); - mac_param.type = 0; - - pwSpec->client.write_mac_context = PK11_CreateContextBySymKey( - mac_mech, CKA_SIGN, pwSpec->client.write_mac_key, &mac_param); - if (pwSpec->client.write_mac_context == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - pwSpec->server.write_mac_context = PK11_CreateContextBySymKey( - mac_mech, CKA_SIGN, pwSpec->server.write_mac_key, &mac_param); - if (pwSpec->server.write_mac_context == NULL) { + spec->keyMaterial.macContext = PK11_CreateContextBySymKey( + spec->macDef->mmech, CKA_SIGN, spec->keyMaterial.macKey, &macParam); + if (!spec->keyMaterial.macContext) { ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; + return SECFailure; } /* ** Now setup the crypto contexts. */ - - if (calg == calg_null) { - pwSpec->encode = Null_Cipher; - pwSpec->decode = Null_Cipher; + if (calg == ssl_calg_null) { + spec->cipher = Null_Cipher; return SECSuccess; } - mechanism = ssl3_Alg2Mech(calg); - /* - * build the server context - */ - iv.data = pwSpec->server.write_iv; - iv.len = cipher_def->iv_size; - param = PK11_ParamFromIV(mechanism, &iv); - if (param == NULL) { - ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); - goto fail; - } - serverContext = PK11_CreateContextBySymKey(mechanism, - (ss->sec.isServer ? CKA_ENCRYPT - : CKA_DECRYPT), - pwSpec->server.write_key, param); - iv.data = PK11_IVFromParam(mechanism, param, (int *)&iv.len); - if (iv.data) - PORT_Memcpy(pwSpec->server.write_iv, iv.data, iv.len); - SECITEM_FreeItem(param, PR_TRUE); - if (serverContext == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } + spec->cipher = (SSLCipher)PK11_CipherOp; + encMechanism = ssl3_Alg2Mech(calg); + encMode = (spec->direction == CipherSpecWrite) ? CKA_ENCRYPT : CKA_DECRYPT; /* - * build the client context + * build the context */ - iv.data = pwSpec->client.write_iv; - iv.len = cipher_def->iv_size; - - param = PK11_ParamFromIV(mechanism, &iv); - if (param == NULL) { - ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); - goto fail; - } - clientContext = PK11_CreateContextBySymKey(mechanism, - (ss->sec.isServer ? CKA_DECRYPT - : CKA_ENCRYPT), - pwSpec->client.write_key, param); - iv.data = PK11_IVFromParam(mechanism, param, (int *)&iv.len); - if (iv.data) - PORT_Memcpy(pwSpec->client.write_iv, iv.data, iv.len); - SECITEM_FreeItem(param, PR_TRUE); - if (clientContext == NULL) { + iv.data = spec->keyMaterial.iv; + iv.len = spec->cipherDef->iv_size; + spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode, + spec->keyMaterial.key, + &iv); + if (!spec->cipherContext) { ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; + return SECFailure; } - pwSpec->encode = (SSLCipher)PK11_CipherOp; - pwSpec->decode = (SSLCipher)PK11_CipherOp; - - pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext; - pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext; - - serverContext = NULL; - clientContext = NULL; - - ssl3_InitCompressionContext(pwSpec); return SECSuccess; - -fail: - if (serverContext != NULL) - PK11_DestroyContext(serverContext, PR_TRUE); - if (pwSpec->client.write_mac_context != NULL) { - PK11_DestroyContext(pwSpec->client.write_mac_context, PR_TRUE); - pwSpec->client.write_mac_context = NULL; - } - if (pwSpec->server.write_mac_context != NULL) { - PK11_DestroyContext(pwSpec->server.write_mac_context, PR_TRUE); - pwSpec->server.write_mac_context = NULL; - } - - return SECFailure; -} - -HASH_HashType -ssl3_GetTls12HashType(sslSocket *ss) -{ - if (ss->ssl3.pwSpec->version < SSL_LIBRARY_VERSION_TLS_1_2) { - return HASH_AlgNULL; - } - - switch (ss->ssl3.hs.suite_def->prf_hash) { - case ssl_hash_sha384: - return HASH_AlgSHA384; - case ssl_hash_sha256: - case ssl_hash_none: - /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */ - return HASH_AlgSHA256; - default: - PORT_Assert(0); - } - return HASH_AlgSHA256; } /* Complete the initialization of all keys, ciphers, MACs and their contexts @@ -2114,73 +1744,78 @@ ssl3_GetTls12HashType(sslSocket *ss) * ssl3_HandleServerHello (for session restart) * ssl3_HandleClientHello (for session restart) * Sets error code, but caller probably should override to disambiguate. - * NULL pms means re-use old master_secret. * - * If the old master secret is reused, pms is NULL and the master secret is - * already in pwSpec->master_secret. + * If |secret| is a master secret from a previous connection is reused, |derive| + * is PR_FALSE. If the secret is a pre-master secret, then |derive| is PR_TRUE + * and the master secret is derived from |secret|. */ SECStatus -ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) +ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret, PRBool derive) { + PK11SymKey *masterSecret; ssl3CipherSpec *pwSpec; - ssl3CipherSpec *cwSpec; + ssl3CipherSpec *prSpec; SECStatus rv; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert(secret); ssl_GetSpecWriteLock(ss); /**************************************/ - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - + PORT_Assert(ss->ssl3.pwSpec); + PORT_Assert(ss->ssl3.cwSpec->epoch == ss->ssl3.crSpec->epoch); + prSpec = ss->ssl3.prSpec; pwSpec = ss->ssl3.pwSpec; - cwSpec = ss->ssl3.cwSpec; - if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) { - rv = ssl3_DeriveMasterSecret(ss, pms); - if (rv != SECSuccess) { - goto done; /* err code set by ssl3_DeriveMasterSecret */ - } + if (ss->ssl3.cwSpec->epoch == PR_UINT16_MAX) { + /* The problem here is that we have rehandshaked too many + * times (you are not allowed to wrap the epoch). The + * spec says you should be discarding the connection + * and start over, so not much we can do here. */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; } - if (pwSpec->master_secret) { - rv = ssl3_DeriveConnectionKeys(ss); - if (rv == SECSuccess) { - rv = ssl3_InitPendingContexts(ss); + + if (derive) { + rv = ssl3_ComputeMasterSecret(ss, secret, &masterSecret); + if (rv != SECSuccess) { + goto loser; } } else { - PORT_Assert(pwSpec->master_secret); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; + masterSecret = secret; } + + PORT_Assert(masterSecret); + rv = ssl3_DeriveConnectionKeys(ss, masterSecret); if (rv != SECSuccess) { - goto done; + if (derive) { + /* masterSecret was created here. */ + PK11_FreeSymKey(masterSecret); + } + goto loser; } - /* Generic behaviors -- common to all crypto methods */ - if (!IS_DTLS(ss)) { - pwSpec->read_seq_num = pwSpec->write_seq_num = 0; - } else { - if (cwSpec->epoch == PR_UINT16_MAX) { - /* The problem here is that we have rehandshaked too many - * times (you are not allowed to wrap the epoch). The - * spec says you should be discarding the connection - * and start over, so not much we can do here. */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - goto done; - } - /* The sequence number has the high 16 bits as the epoch. */ - pwSpec->epoch = cwSpec->epoch + 1; - pwSpec->read_seq_num = pwSpec->write_seq_num = - (sslSequenceNumber)pwSpec->epoch << 48; + /* Both cipher specs maintain a reference to the master secret, since each + * is managed and freed independently. */ + prSpec->masterSecret = masterSecret; + pwSpec->masterSecret = PK11_ReferenceSymKey(masterSecret); + rv = ssl3_InitPendingContexts(ss, ss->ssl3.prSpec); + if (rv != SECSuccess) { + goto loser; + } - dtls_InitRecvdRecords(&pwSpec->recvdRecords); + rv = ssl3_InitPendingContexts(ss, ss->ssl3.pwSpec); + if (rv != SECSuccess) { + goto loser; } -done: ssl_ReleaseSpecWriteLock(ss); /******************************/ - if (rv != SECSuccess) - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return rv; + return SECSuccess; + +loser: + ssl_ReleaseSpecWriteLock(ss); /******************************/ + ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); + return SECFailure; } /* @@ -2213,36 +1848,33 @@ static const unsigned char mac_pad_2[60] = { static SECStatus ssl3_ComputeRecordMAC( ssl3CipherSpec *spec, - PRBool useServerMacKey, const unsigned char *header, unsigned int headerLen, const PRUint8 *input, - int inputLength, + int inputLen, unsigned char *outbuf, - unsigned int *outLength) + unsigned int *outLen) { - const ssl3MACDef *mac_def; + PK11Context *context; + int macSize = spec->macDef->mac_size; SECStatus rv; PRINT_BUF(95, (NULL, "frag hash1: header", header, headerLen)); - PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength)); + PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLen)); - mac_def = spec->mac_def; - if (mac_def->mac == mac_null) { - *outLength = 0; + if (spec->macDef->mac == ssl_mac_null) { + *outLen = 0; return SECSuccess; } - PK11Context *mac_context = - (useServerMacKey ? spec->server.write_mac_context - : spec->client.write_mac_context); - rv = PK11_DigestBegin(mac_context); - rv |= PK11_DigestOp(mac_context, header, headerLen); - rv |= PK11_DigestOp(mac_context, input, inputLength); - rv |= PK11_DigestFinal(mac_context, outbuf, outLength, spec->mac_size); - PORT_Assert(rv != SECSuccess || *outLength == (unsigned)spec->mac_size); + context = spec->keyMaterial.macContext; + rv = PK11_DigestBegin(context); + rv |= PK11_DigestOp(context, header, headerLen); + rv |= PK11_DigestOp(context, input, inputLen); + rv |= PK11_DigestFinal(context, outbuf, outLen, macSize); + PORT_Assert(rv != SECSuccess || *outLen == (unsigned)macSize); - PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLength)); + PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLen)); if (rv != SECSuccess) { rv = SECFailure; @@ -2260,7 +1892,6 @@ ssl3_ComputeRecordMAC( static SECStatus ssl3_ComputeRecordMACConstantTime( ssl3CipherSpec *spec, - PRBool useServerMacKey, const unsigned char *header, unsigned int headerLen, const PRUint8 *input, @@ -2272,13 +1903,13 @@ ssl3_ComputeRecordMACConstantTime( CK_MECHANISM_TYPE macType; CK_NSS_MAC_CONSTANT_TIME_PARAMS params; SECItem param, inputItem, outputItem; + int macSize = spec->macDef->mac_size; SECStatus rv; - PK11SymKey *key; - PORT_Assert(inputLen >= spec->mac_size); + PORT_Assert(inputLen >= spec->macDef->mac_size); PORT_Assert(originalLen >= inputLen); - if (spec->mac_def->mac == mac_null) { + if (spec->macDef->mac == ssl_mac_null) { *outLen = 0; return SECSuccess; } @@ -2288,7 +1919,7 @@ ssl3_ComputeRecordMACConstantTime( macType = CKM_NSS_SSL3_MAC_CONSTANT_TIME; } - params.macAlg = spec->mac_def->mmech; + params.macAlg = spec->macDef->mmech; params.ulBodyTotalLen = originalLen; params.pHeader = (unsigned char *)header; /* const cast */ params.ulHeaderLen = headerLen; @@ -2305,19 +1936,14 @@ ssl3_ComputeRecordMACConstantTime( outputItem.len = *outLen; outputItem.type = 0; - key = spec->server.write_mac_key; - if (!useServerMacKey) { - key = spec->client.write_mac_key; - } - - rv = PK11_SignWithSymKey(key, macType, ¶m, &outputItem, &inputItem); + rv = PK11_SignWithSymKey(spec->keyMaterial.macKey, macType, ¶m, + &outputItem, &inputItem); if (rv != SECSuccess) { if (PORT_GetError() == SEC_ERROR_INVALID_ALGORITHM) { /* ssl3_ComputeRecordMAC() expects the MAC to have been removed * from the input length already. */ - return ssl3_ComputeRecordMAC(spec, useServerMacKey, - header, headerLen, - input, inputLen - spec->mac_size, + return ssl3_ComputeRecordMAC(spec, header, headerLen, + input, inputLen - macSize, outbuf, outLen); } @@ -2327,7 +1953,7 @@ ssl3_ComputeRecordMACConstantTime( return rv; } - PORT_Assert(outputItem.len == (unsigned)spec->mac_size); + PORT_Assert(outputItem.len == (unsigned)macSize); *outLen = outputItem.len; return rv; @@ -2363,34 +1989,30 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) /* Caller must hold the spec read lock. */ SECStatus -ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, - PRBool isServer, - PRBool isDTLS, - PRBool capRecordVersion, - SSL3ContentType type, - const PRUint8 *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf) -{ - const ssl3BulkCipherDef *cipher_def; +ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, + PRBool isServer, + PRBool isDTLS, + SSL3ContentType type, + const PRUint8 *pIn, + PRUint32 contentLen, + sslBuffer *wrBuf) +{ SECStatus rv; PRUint32 macLen = 0; PRUint32 fragLen; PRUint32 p1Len, p2Len, oddLen = 0; unsigned int ivLen = 0; - unsigned char pseudoHeader[13]; - unsigned int pseudoHeaderLen; - - cipher_def = cwSpec->cipher_def; + unsigned char pseudoHeaderBuf[13]; + sslBuffer pseudoHeader = SSL_BUFFER(pseudoHeaderBuf); - if (cipher_def->type == type_block && + if (cwSpec->cipherDef->type == type_block && cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { /* Prepend the per-record explicit IV using technique 2b from * RFC 4346 section 6.2.3.2: The IV is a cryptographically * strong random number XORed with the CBC residue from the previous * record. */ - ivLen = cipher_def->iv_size; + ivLen = cwSpec->cipherDef->iv_size; if (ivLen > wrBuf->space) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; @@ -2400,7 +2022,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); return rv; } - rv = cwSpec->encode(cwSpec->encodeContext, + rv = cwSpec->cipher(cwSpec->cipherContext, wrBuf->buf, /* output */ (int *)&wrBuf->len, /* outlen */ ivLen, /* max outlen */ @@ -2412,24 +2034,14 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, } } - if (cwSpec->compressor) { - int outlen; - rv = cwSpec->compressor(cwSpec->compressContext, wrBuf->buf + ivLen, - &outlen, wrBuf->space - ivLen, pIn, contentLen); - if (rv != SECSuccess) - return rv; - pIn = wrBuf->buf + ivLen; - contentLen = outlen; - } - - pseudoHeaderLen = ssl3_BuildRecordPseudoHeader( - pseudoHeader, cwSpec->write_seq_num, type, - cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->version, - isDTLS, contentLen); - PORT_Assert(pseudoHeaderLen <= sizeof(pseudoHeader)); - if (cipher_def->type == type_aead) { - const int nonceLen = cipher_def->explicit_nonce_size; - const int tagLen = cipher_def->tag_size; + rv = ssl3_BuildRecordPseudoHeader( + cwSpec->epoch, cwSpec->seqNum, type, + cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->recordVersion, + isDTLS, contentLen, &pseudoHeader); + PORT_Assert(rv == SECSuccess); + if (cwSpec->cipherDef->type == type_aead) { + const int nonceLen = cwSpec->cipherDef->explicit_nonce_size; + const int tagLen = cwSpec->cipherDef->tag_size; if (nonceLen + contentLen + tagLen > wrBuf->space) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -2437,23 +2049,26 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, } rv = cwSpec->aead( - isServer ? &cwSpec->server : &cwSpec->client, + &cwSpec->keyMaterial, PR_FALSE, /* do encrypt */ wrBuf->buf, /* output */ (int *)&wrBuf->len, /* out len */ wrBuf->space, /* max out */ pIn, contentLen, /* input */ - pseudoHeader, pseudoHeaderLen); + SSL_BUFFER_BASE(&pseudoHeader), SSL_BUFFER_LEN(&pseudoHeader)); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); return SECFailure; } } else { + int blockSize = cwSpec->cipherDef->block_size; + /* * Add the MAC */ - rv = ssl3_ComputeRecordMAC(cwSpec, isServer, pseudoHeader, - pseudoHeaderLen, pIn, contentLen, + rv = ssl3_ComputeRecordMAC(cwSpec, SSL_BUFFER_BASE(&pseudoHeader), + SSL_BUFFER_LEN(&pseudoHeader), + pIn, contentLen, wrBuf->buf + ivLen + contentLen, &macLen); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); @@ -2468,16 +2083,16 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, * Pad the text (if we're doing a block cipher) * then Encrypt it */ - if (cipher_def->type == type_block) { + if (cwSpec->cipherDef->type == type_block) { unsigned char *pBuf; int padding_length; int i; - oddLen = contentLen % cipher_def->block_size; + oddLen = contentLen % blockSize; /* Assume blockSize is a power of two */ - padding_length = cipher_def->block_size - 1 - ((fragLen) & (cipher_def->block_size - 1)); + padding_length = blockSize - 1 - ((fragLen) & (blockSize - 1)); fragLen += padding_length + 1; - PORT_Assert((fragLen % cipher_def->block_size) == 0); + PORT_Assert((fragLen % blockSize) == 0); /* Pad according to TLS rules (also acceptable to SSL3). */ pBuf = &wrBuf->buf[ivLen + fragLen - 1]; @@ -2495,13 +2110,13 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, } if (oddLen) { p2Len += oddLen; - PORT_Assert((cipher_def->block_size < 2) || - (p2Len % cipher_def->block_size) == 0); + PORT_Assert((blockSize < 2) || + (p2Len % blockSize) == 0); memmove(wrBuf->buf + ivLen + p1Len, pIn + p1Len, oddLen); } if (p1Len > 0) { int cipherBytesPart1 = -1; - rv = cwSpec->encode(cwSpec->encodeContext, + rv = cwSpec->cipher(cwSpec->cipherContext, wrBuf->buf + ivLen, /* output */ &cipherBytesPart1, /* actual outlen */ p1Len, /* max outlen */ @@ -2516,7 +2131,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, } if (p2Len > 0) { int cipherBytesPart2 = -1; - rv = cwSpec->encode(cwSpec->encodeContext, + rv = cwSpec->cipher(cwSpec->cipherContext, wrBuf->buf + ivLen + p1Len, &cipherBytesPart2, /* output and actual outLen */ p2Len, /* max outlen */ @@ -2534,34 +2149,66 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, return SECSuccess; } +/* Note: though this can report failure, it shouldn't. */ +static SECStatus +ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec, + SSL3ContentType contentType, unsigned int len, + sslBuffer *wrBuf) +{ + SECStatus rv; + +#ifndef UNSAFE_FUZZER_MODE + if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3 && + cwSpec->cipherDef->calg != ssl_calg_null) { + contentType = content_application_data; + } +#endif + rv = sslBuffer_AppendNumber(wrBuf, contentType, 1); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = sslBuffer_AppendNumber(wrBuf, cwSpec->recordVersion, 2); + if (rv != SECSuccess) { + return SECFailure; + } + if (IS_DTLS(ss)) { + rv = sslBuffer_AppendNumber(wrBuf, cwSpec->epoch, 2); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(wrBuf, cwSpec->seqNum, 6); + if (rv != SECSuccess) { + return SECFailure; + } + } + rv = sslBuffer_AppendNumber(wrBuf, len, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + return SECSuccess; +} + SECStatus -ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, - PRBool capRecordVersion, SSL3ContentType type, +ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) { - const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def; - PRUint16 headerLen; - sslBuffer protBuf; - SSL3ProtocolVersion version = cwSpec->version; + 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; - PRUint8 *ptr = wrBuf->buf; SECStatus rv; - if (ss->ssl3.hs.shortHeaders) { - PORT_Assert(!IS_DTLS(ss)); - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - headerLen = TLS13_RECORD_HEADER_LENGTH_SHORT; - } else { - headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH; - } - protBuf.buf = wrBuf->buf + headerLen; - protBuf.len = 0; - protBuf.space = wrBuf->space - headerLen; - - PORT_Assert(cipher_def->max_records <= RECORD_SEQ_MAX); - if ((cwSpec->write_seq_num & RECORD_SEQ_MAX) >= cipher_def->max_records) { + 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) { + /* 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->write_seq_num)); + SSL_GETPID(), cwSpec->seqNum)); PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS); return SECFailure; } @@ -2569,15 +2216,22 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, isTLS13 = (PRBool)(cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3); #ifdef UNSAFE_FUZZER_MODE - rv = Null_Cipher(NULL, protBuf.buf, (int *)&protBuf.len, protBuf.space, - pIn, contentLen); + { + int len; + rv = Null_Cipher(NULL, SSL_BUFFER_BASE(&protBuf), &len, + SSL_BUFFER_SPACE(&protBuf), pIn, contentLen); + if (rv != SECSuccess) { + return SECFailure; /* error was set */ + } + rv = sslBuffer_Skip(&protBuf, len, NULL); + PORT_Assert(rv == SECSuccess); /* Can't fail. */ + } #else if (isTLS13) { rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, &protBuf); } else { - rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, - IS_DTLS(ss), capRecordVersion, type, - pIn, contentLen, &protBuf); + rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), type, + pIn, contentLen, &protBuf); } #endif if (rv != SECSuccess) { @@ -2585,40 +2239,58 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, } PORT_Assert(protBuf.len <= MAX_FRAGMENT_LENGTH + (isTLS13 ? 256 : 1024)); - wrBuf->len = protBuf.len + headerLen; - if (ss->ssl3.hs.shortHeaders) { - PORT_Assert(!IS_DTLS(ss)); /* Decoder not yet implemented. */ - (void)ssl_EncodeUintX(0x8000 | protBuf.len, 2, ptr); - } else { -#ifndef UNSAFE_FUZZER_MODE - if (isTLS13 && cipher_def->calg != ssl_calg_null) { - *ptr++ = content_application_data; - } else -#endif - { - *ptr++ = type; - } + rv = ssl_InsertRecordHeader(ss, cwSpec, type, SSL_BUFFER_LEN(&protBuf), + wrBuf); + if (rv != SECSuccess) { + return SECFailure; + } - if (IS_DTLS(ss)) { - version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version; - version = dtls_TLSVersionToDTLSVersion(version); + 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; + } + ++cwSpec->seqNum; - ptr = ssl_EncodeUintX(version, 2, ptr); - ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 8, ptr); - } else { - if (capRecordVersion || isTLS13) { - version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version); - } - ptr = ssl_EncodeUintX(version, 2, ptr); + return SECSuccess; +} + +SECStatus +ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type, + const PRUint8 *pIn, unsigned int nIn, + unsigned int *written) +{ + sslBuffer *wrBuf = &ss->sec.writeBuf; + unsigned int contentLen; + unsigned int spaceNeeded; + SECStatus rv; + + contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH); + spaceNeeded = contentLen + SSL3_BUFFER_FUDGE; + if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_1 && + spec->cipherDef->type == type_block) { + spaceNeeded += spec->cipherDef->iv_size; + } + if (spaceNeeded > SSL_BUFFER_SPACE(wrBuf)) { + rv = sslBuffer_Grow(wrBuf, spaceNeeded); + if (rv != SECSuccess) { + SSL_DBG(("%d: SSL3[%d]: failed to expand write buffer to %d", + SSL_GETPID(), ss->fd, spaceNeeded)); + return SECFailure; } - (void)ssl_EncodeUintX(protBuf.len, 2, ptr); } - ++cwSpec->write_seq_num; + rv = ssl_ProtectRecord(ss, spec, type, pIn, contentLen, wrBuf); + if (rv != SECSuccess) { + return SECFailure; + } + PRINT_BUF(50, (ss, "send (encrypted) record data:", + SSL_BUFFER_BASE(wrBuf), SSL_BUFFER_LEN(wrBuf))); + *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 @@ -2639,16 +2311,6 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, * all ciphertext into the pending ciphertext buffer. * ssl_SEND_FLAG_USE_EPOCH (for DTLS) * Forces the use of the provided epoch - * ssl_SEND_FLAG_CAP_RECORD_VERSION - * Caps the record layer version number of TLS ClientHello to { 3, 1 } - * (TLS 1.0). Some TLS 1.0 servers (which seem to use F5 BIG-IP) ignore - * ClientHello.client_version and use the record layer version number - * (TLSPlaintext.version) instead when negotiating protocol versions. In - * addition, if the record layer version number of ClientHello is { 3, 2 } - * (TLS 1.1) or higher, these servers reset the TCP connections. Lastly, - * some F5 BIG-IP servers hang if a record containing a ClientHello has a - * version greater than { 3, 1 } and a length greater than 255. Set this - * flag to work around such servers. */ PRInt32 ssl3_SendRecord(sslSocket *ss, @@ -2659,10 +2321,9 @@ ssl3_SendRecord(sslSocket *ss, PRInt32 flags) { sslBuffer *wrBuf = &ss->sec.writeBuf; + ssl3CipherSpec *spec; SECStatus rv; PRInt32 totalSent = 0; - PRBool capRecordVersion; - ssl3CipherSpec *spec; SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), @@ -2670,6 +2331,7 @@ ssl3_SendRecord(sslSocket *ss, PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0); if (ss->ssl3.fatalAlertSent) { SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent", @@ -2677,114 +2339,41 @@ ssl3_SendRecord(sslSocket *ss, return SECFailure; } - capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0); - - if (capRecordVersion) { - /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the - * TLS initial ClientHello. */ - PORT_Assert(!IS_DTLS(ss)); - PORT_Assert(!ss->firstHsDone); - PORT_Assert(type == content_handshake); - PORT_Assert(ss->ssl3.hs.ws == wait_server_hello); - } - - if (ss->ssl3.initialized == PR_FALSE) { - /* This can happen on a server if the very first incoming record - ** looks like a defective ssl3 record (e.g. too long), and we're - ** trying to send an alert. - */ - PR_ASSERT(type == content_alert); - ssl3_InitState(ss); - } - /* check for Token Presence */ if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) { PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); return SECFailure; } - while (nIn > 0) { - PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH); - unsigned int spaceNeeded; - unsigned int numRecords; - - ssl_GetSpecReadLock(ss); /********************************/ + if (cwSpec) { + /* cwSpec can only be set for retransmissions of the DTLS handshake. */ + PORT_Assert(IS_DTLS(ss) && + (type == content_handshake || + type == content_change_cipher_spec)); + spec = cwSpec; + } else { + spec = ss->ssl3.cwSpec; + } - if (nIn > 1 && ss->opt.cbcRandomIV && - ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_1 && - type == content_application_data && - ss->ssl3.cwSpec->cipher_def->type == type_block /* CBC mode */) { - /* We will split the first byte of the record into its own record, - * as explained in the documentation for SSL_CBC_RANDOM_IV in ssl.h - */ - numRecords = 2; - } else { - numRecords = 1; - } + while (nIn > 0) { + unsigned int written = 0; + PRInt32 sent; - spaceNeeded = contentLen + (numRecords * SSL3_BUFFER_FUDGE); - if (ss->ssl3.cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1 && - ss->ssl3.cwSpec->cipher_def->type == type_block) { - spaceNeeded += ss->ssl3.cwSpec->cipher_def->iv_size; - } - if (spaceNeeded > wrBuf->space) { - rv = sslBuffer_Grow(wrBuf, spaceNeeded); - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, spaceNeeded)); - goto spec_locked_loser; /* sslBuffer_Grow set error code. */ - } + ssl_GetSpecReadLock(ss); + rv = ssl_ProtectNextRecord(ss, spec, type, pIn, nIn, &written); + ssl_ReleaseSpecReadLock(ss); + if (rv != SECSuccess) { + return SECFailure; } - if (numRecords == 2) { - sslBuffer secondRecord; - rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type, - pIn, 1, wrBuf); - if (rv != SECSuccess) - goto spec_locked_loser; - - PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:", - wrBuf->buf, wrBuf->len)); - - secondRecord.buf = wrBuf->buf + wrBuf->len; - secondRecord.len = 0; - secondRecord.space = wrBuf->space - wrBuf->len; - - rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type, - pIn + 1, contentLen - 1, &secondRecord); - if (rv == SECSuccess) { - PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:", - secondRecord.buf, secondRecord.len)); - wrBuf->len += secondRecord.len; - } - } else { - if (cwSpec) { - /* cwSpec can only be set for retransmissions of DTLS handshake - * messages. */ - PORT_Assert(IS_DTLS(ss) && - (type == content_handshake || - type == content_change_cipher_spec)); - spec = cwSpec; - } else { - spec = ss->ssl3.cwSpec; - } - - rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion, - type, pIn, contentLen, wrBuf); - if (rv == SECSuccess) { - PRINT_BUF(50, (ss, "send (encrypted) record data:", - wrBuf->buf, wrBuf->len)); - } + PORT_Assert(written > 0); + /* DTLS should not fragment non-application data here. */ + if (IS_DTLS(ss) && type != content_application_data) { + PORT_Assert(written == nIn); } - spec_locked_loser: - ssl_ReleaseSpecReadLock(ss); /************************************/ - - if (rv != SECSuccess) - return SECFailure; - - pIn += contentLen; - nIn -= contentLen; + pIn += written; + nIn -= written; PORT_Assert(nIn >= 0); /* If there's still some previously saved ciphertext, @@ -2794,58 +2383,64 @@ ssl3_SendRecord(sslSocket *ss, if ((ss->pendingBuf.len > 0) || (flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len); + rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf), + SSL_BUFFER_LEN(wrBuf)); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ - return SECFailure; + goto loser; } - wrBuf->len = 0; /* All cipher text is saved away. */ if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - PRInt32 sent; ss->handshakeBegun = 1; sent = ssl_SendSavedWriteData(ss); if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) { ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - return SECFailure; + goto loser; } if (ss->pendingBuf.len) { flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER; } } - } else if (wrBuf->len > 0) { - PRInt32 sent; + } else { + PORT_Assert(SSL_BUFFER_LEN(wrBuf) > 0); ss->handshakeBegun = 1; - sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len, + sent = ssl_DefSend(ss, SSL_BUFFER_BASE(wrBuf), + SSL_BUFFER_LEN(wrBuf), flags & ~ssl_SEND_FLAG_MASK); if (sent < 0) { - if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { + if (PORT_GetError() != PR_WOULD_BLOCK_ERROR) { ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - return SECFailure; + goto loser; } /* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */ sent = 0; } - wrBuf->len -= sent; - if (wrBuf->len) { + if (SSL_BUFFER_LEN(wrBuf) > (unsigned int)sent) { if (IS_DTLS(ss)) { /* DTLS just says no in this case. No buffering */ - PR_SetError(PR_WOULD_BLOCK_ERROR, 0); - return SECFailure; + PORT_SetError(PR_WOULD_BLOCK_ERROR); + goto loser; } /* now take all the remaining unsent new ciphertext and * append it to the buffer of previously unsent ciphertext. */ - rv = ssl_SaveWriteData(ss, wrBuf->buf + sent, wrBuf->len); + rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf) + sent, + SSL_BUFFER_LEN(wrBuf) - sent); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ - return SECFailure; + goto loser; } } } - totalSent += contentLen; + wrBuf->len = 0; + totalSent += written; } return totalSent; + +loser: + /* Don't leave bits of buffer lying around. */ + wrBuf->len = 0; + return -1; } #define SSL3_PENDING_HIGH_WATER 1024 @@ -2859,6 +2454,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, { PRInt32 totalSent = 0; PRInt32 discarded = 0; + PRBool splitNeeded = PR_FALSE; PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); /* These flags for internal use only */ @@ -2885,6 +2481,16 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, len--; discarded = 1; } + + /* We will split the first byte of the record into its own record, as + * explained in the documentation for SSL_CBC_RANDOM_IV in ssl.h. + */ + if (len > 1 && ss->opt.cbcRandomIV && + ss->version < SSL_LIBRARY_VERSION_TLS_1_1 && + ss->ssl3.cwSpec->cipherDef->type == type_block /* CBC */) { + splitNeeded = PR_TRUE; + } + while (len > totalSent) { PRInt32 sent, toSend; @@ -2899,7 +2505,13 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */ ssl_GetXmitBufLock(ss); } - toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); + + if (splitNeeded) { + toSend = 1; + splitNeeded = PR_FALSE; + } else { + toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); + } /* * Note that the 0 epoch is OK because flags will never require @@ -2959,9 +2571,8 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) { if (IS_DTLS(ss)) { return dtls_FlushHandshakeMessages(ss, flags); - } else { - return ssl3_FlushHandshakeMessages(ss, flags); } + return ssl3_FlushHandshakeMessages(ss, flags); } /* Attempt to send the content of sendBuf buffer in an SSL handshake record. @@ -2973,8 +2584,7 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) { - static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER | - ssl_SEND_FLAG_CAP_RECORD_VERSION; + static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER; PRInt32 count = -1; SECStatus rv; @@ -3105,6 +2715,15 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) ss->sec.uncache(ss->sec.ci.sid); } } + + rv = tls13_SetAlertCipherSpec(ss); + if (rv != SECSuccess) { + if (needHsLock) { + ssl_ReleaseSSL3HandshakeLock(ss); + } + return rv; + } + ssl_GetXmitBufLock(ss); rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (rv == SECSuccess) { @@ -3340,9 +2959,6 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) case bad_certificate_hash_value: error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT; break; - case end_of_early_data: - error = SSL_ERROR_END_OF_EARLY_DATA_ALERT; - break; default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break; @@ -3354,7 +2970,6 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) switch (desc) { case close_notify: case user_canceled: - case end_of_early_data: break; default: level = alert_fatal; @@ -3374,9 +2989,6 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) PORT_SetError(error); return SECFailure; } - if (desc == end_of_early_data) { - return tls13_HandleEndOfEarlyData(ss); - } if ((desc == no_certificate) && (ss->ssl3.hs.ws == wait_client_cert)) { /* I'm a server. I've requested a client cert. He hasn't got one. */ SECStatus rv; @@ -3399,59 +3011,64 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) * and pending write spec pointers. */ -static SECStatus -ssl3_SendChangeCipherSpecs(sslSocket *ss) +SECStatus +ssl3_SendChangeCipherSpecsInt(sslSocket *ss) { PRUint8 change = change_cipher_spec_choice; - ssl3CipherSpec *pwSpec; SECStatus rv; - PRInt32 sent; SSL_TRC(3, ("%d: SSL3[%d]: send change_cipher_spec record", SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (rv != SECSuccess) { - return rv; /* error code set by ssl3_FlushHandshake */ + return SECFailure; /* error code set by ssl3_FlushHandshake */ } + if (!IS_DTLS(ss)) { - sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec, &change, 1, - ssl_SEND_FLAG_FORCE_INTO_BUFFER); + PRInt32 sent; + sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec, + &change, 1, ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (sent < 0) { - return (SECStatus)sent; /* error code set by ssl3_SendRecord */ + 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 rv; + return SECFailure; } } + return SECSuccess; +} + +static SECStatus +ssl3_SendChangeCipherSpecs(sslSocket *ss) +{ + SECStatus rv; + + PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + rv = ssl3_SendChangeCipherSpecsInt(ss); + if (rv != SECSuccess) { + return rv; /* Error code set. */ + } /* swap the pending and current write specs. */ ssl_GetSpecWriteLock(ss); /**************************************/ - pwSpec = ss->ssl3.pwSpec; - ss->ssl3.pwSpec = ss->ssl3.cwSpec; - ss->ssl3.cwSpec = pwSpec; + ssl_CipherSpecRelease(ss->ssl3.cwSpec); + ss->ssl3.cwSpec = ss->ssl3.pwSpec; + ss->ssl3.pwSpec = NULL; SSL_TRC(3, ("%d: SSL3[%d] Set Current Write Cipher Suite to Pending", SSL_GETPID(), ss->fd)); - /* We need to free up the contexts, keys and certs ! */ - /* If we are really through with the old cipher spec - * (Both the read and write sides have changed) destroy it. - */ - if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - if (!IS_DTLS(ss)) { - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE /*freeSrvName*/); - } else { - /* With DTLS, we need to set a holddown timer in case the final - * message got lost */ - rv = dtls_StartHolddownTimer(ss); - } + /* With DTLS, we need to set a holddown timer in case the final + * message got lost */ + if (IS_DTLS(ss) && ss->ssl3.crSpec->epoch == ss->ssl3.cwSpec->epoch) { + rv = dtls_StartHolddownTimer(ss); } ssl_ReleaseSpecWriteLock(ss); /**************************************/ @@ -3467,7 +3084,6 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) static SECStatus ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) { - ssl3CipherSpec *prSpec; SSL3WaitState ws = ss->ssl3.hs.ws; SSL3ChangeCipherSpecChoice change; @@ -3477,19 +3093,18 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) SSL_TRC(3, ("%d: SSL3[%d]: handle change_cipher_spec record", SSL_GETPID(), ss->fd)); - if (ws != wait_change_cipher) { - if (IS_DTLS(ss)) { - /* Ignore this because it's out of order. */ - SSL_TRC(3, ("%d: SSL3[%d]: discard out of order " - "DTLS change_cipher_spec", - SSL_GETPID(), ss->fd)); - buf->len = 0; - return SECSuccess; - } - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER); - return SECFailure; + /* For DTLS: Ignore this if we aren't expecting it. Don't kill a connection + * as a result of receiving trash. + * For TLS: Maybe ignore, but only after checking format. */ + if (ws != wait_change_cipher && IS_DTLS(ss)) { + /* Ignore this because it's out of order. */ + SSL_TRC(3, ("%d: SSL3[%d]: discard out of order " + "DTLS change_cipher_spec", + SSL_GETPID(), ss->fd)); + buf->len = 0; + return SECSuccess; } + /* Handshake messages should not span ChangeCipherSpec. */ if (ss->ssl3.hs.header_bytes) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); @@ -3508,26 +3123,44 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER); return SECFailure; } - buf->len = 0; - /* Swap the pending and current read specs. */ - ssl_GetSpecWriteLock(ss); /*************************************/ - prSpec = ss->ssl3.prSpec; - - ss->ssl3.prSpec = ss->ssl3.crSpec; - ss->ssl3.crSpec = prSpec; - ss->ssl3.hs.ws = wait_finished; + buf->len = 0; + if (ws != wait_change_cipher) { + /* Ignore a CCS for TLS 1.3. This only happens if the server sends a + * HelloRetryRequest. In other cases, the CCS will fail decryption and + * will be discarded by ssl3_HandleRecord(). */ + if (ws == wait_server_hello && + ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && + ss->ssl3.hs.helloRetry) { + PORT_Assert(!ss->sec.isServer); + return SECSuccess; + } + /* Note: For a server, we can't test ss->ssl3.hs.helloRetry or + * ss->version because the server might be stateless (and so it won't + * have set either value yet). Set a flag so that at least we will + * guarantee that the server will treat any ClientHello properly. */ + if (ws == wait_client_hello && + ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 && + !ss->ssl3.hs.receivedCcs) { + PORT_Assert(ss->sec.isServer); + ss->ssl3.hs.receivedCcs = PR_TRUE; + return SECSuccess; + } + (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER); + return SECFailure; + } SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending", SSL_GETPID(), ss->fd)); - - /* If we are really through with the old cipher prSpec - * (Both the read and write sides have changed) destroy it. - */ - if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE /*freeSrvName*/); - } + ssl_GetSpecWriteLock(ss); /*************************************/ + PORT_Assert(ss->ssl3.prSpec); + ssl_CipherSpecRelease(ss->ssl3.crSpec); + ss->ssl3.crSpec = ss->ssl3.prSpec; + ss->ssl3.prSpec = NULL; ssl_ReleaseSpecWriteLock(ss); /*************************************/ + + ss->ssl3.hs.ws = wait_finished; return SECSuccess; } @@ -3650,12 +3283,8 @@ static SECStatus ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms, PK11SymKey **msp) { - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random; - unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random; - PRBool isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0); - PRBool isTLS12 = - (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); + PRBool isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size @@ -3701,9 +3330,9 @@ ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms, } master_params.pVersion = pms_version_ptr; - master_params.RandomInfo.pClientRandom = cr; + master_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random; master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH; - master_params.RandomInfo.pServerRandom = sr; + master_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random; master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH; if (isTLS12) { master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss); @@ -3763,7 +3392,7 @@ tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms, pms_version_ptr = &pms_version; } - if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { /* TLS 1.2+ */ extended_master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss); key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE; @@ -3795,7 +3424,6 @@ ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms, { PORT_Assert(pms != NULL); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) { return tls_ComputeExtendedMasterSecretInt(ss, pms, msp); @@ -3804,36 +3432,6 @@ ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms, } } -/* This method uses PKCS11 to derive the MS from the PMS, where PMS -** is a PKCS11 symkey. We call ssl3_ComputeMasterSecret to do the -** computations and then modify the pwSpec->state as a side effect. -** -** This is used in all cases except the "triple bypass" with RSA key -** exchange. -** -** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec. -*/ -static SECStatus -ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms) -{ - SECStatus rv; - PK11SymKey *ms = NULL; - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - - if (pms) { - rv = ssl3_ComputeMasterSecret(ss, pms, &ms); - pwSpec->master_secret = ms; - if (rv != SECSuccess) - return rv; - } - - return SECSuccess; -} - /* * Derive encryption and MAC Keys (and IVs) from master secret * Sets a useful error code when returning SECFailure. @@ -3850,17 +3448,18 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms) * */ static SECStatus -ssl3_DeriveConnectionKeys(sslSocket *ss) +ssl3_DeriveConnectionKeys(sslSocket *ss, PK11SymKey *masterSecret) { ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random; - unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random; - PRBool isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0); + ssl3CipherSpec *prSpec = ss->ssl3.prSpec; + ssl3CipherSpec *clientSpec; + ssl3CipherSpec *serverSpec; + PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); PRBool isTLS12 = - (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; + (PRBool)(isTLS && ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); + const ssl3BulkCipherDef *cipher_def = pwSpec->cipherDef; PK11SlotInfo *slot = NULL; - PK11SymKey *symKey = NULL; + PK11SymKey *derivedKeyHandle = NULL; void *pwArg = ss->pkcs11PinArg; int keySize; CK_TLS12_KEY_MAT_PARAMS key_material_params; /* may be used as a @@ -3871,48 +3470,53 @@ ssl3_DeriveConnectionKeys(sslSocket *ss) CK_MECHANISM_TYPE bulk_mechanism; SSLCipherAlgorithm calg; SECItem params; - PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == calg_null); + PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == ssl_calg_null); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); + PORT_Assert(masterSecret); - if (!pwSpec->master_secret) { - PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; + /* These functions operate in terms of who is writing specs. */ + if (ss->sec.isServer) { + clientSpec = prSpec; + serverSpec = pwSpec; + } else { + clientSpec = pwSpec; + serverSpec = prSpec; } + /* * generate the key material */ - key_material_params.ulMacSizeInBits = pwSpec->mac_size * BPB; - key_material_params.ulKeySizeInBits = cipher_def->secret_key_size * BPB; - key_material_params.ulIVSizeInBits = cipher_def->iv_size * BPB; if (cipher_def->type == type_block && - pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { + ss->version >= SSL_LIBRARY_VERSION_TLS_1_1) { /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */ key_material_params.ulIVSizeInBits = 0; - memset(pwSpec->client.write_iv, 0, cipher_def->iv_size); - memset(pwSpec->server.write_iv, 0, cipher_def->iv_size); + PORT_Memset(clientSpec->keyMaterial.iv, 0, cipher_def->iv_size); + PORT_Memset(serverSpec->keyMaterial.iv, 0, cipher_def->iv_size); } key_material_params.bIsExport = PR_FALSE; - key_material_params.RandomInfo.pClientRandom = cr; + key_material_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random; key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH; - key_material_params.RandomInfo.pServerRandom = sr; + key_material_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random; key_material_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH; key_material_params.pReturnedKeyMaterial = &returnedKeys; - returnedKeys.pIVClient = pwSpec->client.write_iv; - returnedKeys.pIVServer = pwSpec->server.write_iv; - keySize = cipher_def->key_size; - if (skipKeysAndIVs) { keySize = 0; - key_material_params.ulKeySizeInBits = 0; - key_material_params.ulIVSizeInBits = 0; returnedKeys.pIVClient = NULL; returnedKeys.pIVServer = NULL; + key_material_params.ulKeySizeInBits = 0; + key_material_params.ulIVSizeInBits = 0; + } else { + keySize = cipher_def->key_size; + returnedKeys.pIVClient = clientSpec->keyMaterial.iv; + returnedKeys.pIVServer = serverSpec->keyMaterial.iv; + key_material_params.ulKeySizeInBits = cipher_def->secret_key_size * BPB; + key_material_params.ulIVSizeInBits = cipher_def->iv_size * BPB; } + key_material_params.ulMacSizeInBits = pwSpec->macDef->mac_size * BPB; calg = cipher_def->calg; bulk_mechanism = ssl3_Alg2Mech(calg); @@ -3934,9 +3538,9 @@ ssl3_DeriveConnectionKeys(sslSocket *ss) /* CKM_SSL3_KEY_AND_MAC_DERIVE is defined to set ENCRYPT, DECRYPT, and * DERIVE by DEFAULT */ - symKey = PK11_Derive(pwSpec->master_secret, key_derive, ¶ms, - bulk_mechanism, CKA_ENCRYPT, keySize); - if (!symKey) { + derivedKeyHandle = PK11_Derive(masterSecret, key_derive, ¶ms, + bulk_mechanism, CKA_ENCRYPT, keySize); + if (!derivedKeyHandle) { ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); return SECFailure; } @@ -3944,41 +3548,44 @@ ssl3_DeriveConnectionKeys(sslSocket *ss) * don't because these types are used to map keytype anyway and both * mac's map to the same keytype. */ - slot = PK11_GetSlotFromKey(symKey); + slot = PK11_GetSlotFromKey(derivedKeyHandle); PK11_FreeSlot(slot); /* slot is held until the key is freed */ - pwSpec->client.write_mac_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - CKM_SSL3_SHA1_MAC, returnedKeys.hClientMacSecret, PR_TRUE, pwArg); - if (pwSpec->client.write_mac_key == NULL) { + clientSpec->keyMaterial.macKey = + PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, + CKM_SSL3_SHA1_MAC, returnedKeys.hClientMacSecret, + PR_TRUE, pwArg); + if (clientSpec->keyMaterial.macKey == NULL) { goto loser; /* loser sets err */ } - pwSpec->server.write_mac_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - CKM_SSL3_SHA1_MAC, returnedKeys.hServerMacSecret, PR_TRUE, pwArg); - if (pwSpec->server.write_mac_key == NULL) { + serverSpec->keyMaterial.macKey = + PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, + CKM_SSL3_SHA1_MAC, returnedKeys.hServerMacSecret, + PR_TRUE, pwArg); + if (serverSpec->keyMaterial.macKey == NULL) { goto loser; /* loser sets err */ } if (!skipKeysAndIVs) { - pwSpec->client.write_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - bulk_mechanism, returnedKeys.hClientKey, PR_TRUE, pwArg); - if (pwSpec->client.write_key == NULL) { + clientSpec->keyMaterial.key = + PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, + bulk_mechanism, returnedKeys.hClientKey, + PR_TRUE, pwArg); + if (clientSpec->keyMaterial.key == NULL) { goto loser; /* loser sets err */ } - pwSpec->server.write_key = - PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, - bulk_mechanism, returnedKeys.hServerKey, PR_TRUE, pwArg); - if (pwSpec->server.write_key == NULL) { + serverSpec->keyMaterial.key = + PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, + bulk_mechanism, returnedKeys.hServerKey, + PR_TRUE, pwArg); + if (serverSpec->keyMaterial.key == NULL) { goto loser; /* loser sets err */ } } - PK11_FreeSymKey(symKey); + PK11_FreeSymKey(derivedKeyHandle); return SECSuccess; loser: - if (symKey) - PK11_FreeSymKey(symKey); + PK11_FreeSymKey(derivedKeyHandle); ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); return SECFailure; } @@ -4022,11 +3629,11 @@ ssl3_InitHandshakeHashes(sslSocket *ss) return SECFailure; } ss->ssl3.hs.hashType = handshake_hash_single; - if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); return SECFailure; } + } else { /* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or * created successfully. */ @@ -4117,7 +3724,7 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l return sslBuffer_Append(&ss->ssl3.hs.messages, b, l); } - PRINT_BUF(90, (NULL, "handshake hash input:", b, l)); + PRINT_BUF(90, (ss, "handshake hash input:", b, l)); if (ss->ssl3.hs.hashType == handshake_hash_single) { PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); @@ -4141,104 +3748,8 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l return rv; } -/************************************************************************** - * Append Handshake functions. - * All these functions set appropriate error codes. - * Most rely on ssl3_AppendHandshake to set the error code. - **************************************************************************/ -SECStatus -ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes) -{ - unsigned char *src = (unsigned char *)void_src; - int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len; - SECStatus rv; - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); /* protects sendBuf. */ - - if (!bytes) - return SECSuccess; - if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) { - rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH, - PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes))); - if (rv != SECSuccess) - return rv; /* sslBuffer_Grow has set a memory error code. */ - room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len; - } - - PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes)); - rv = ssl3_UpdateHandshakeHashes(ss, src, bytes); - if (rv != SECSuccess) - return rv; /* error code set by ssl3_UpdateHandshakeHashes */ - - while (bytes > room) { - if (room > 0) - PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, - room); - ss->sec.ci.sendBuf.len += room; - rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (rv != SECSuccess) { - return rv; /* error code set by ssl3_FlushHandshake */ - } - bytes -= room; - src += room; - room = ss->sec.ci.sendBuf.space; - PORT_Assert(ss->sec.ci.sendBuf.len == 0); - } - PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, bytes); - ss->sec.ci.sendBuf.len += bytes; - return SECSuccess; -} - -SECStatus -ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize) -{ - SECStatus rv; - PRUint8 b[4]; - PRUint8 *p = b; - - PORT_Assert(lenSize <= 4 && lenSize > 0); - if (lenSize < 4 && num >= (1L << (lenSize * 8))) { - PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG); - return SECFailure; - } - - switch (lenSize) { - case 4: - *p++ = (num >> 24) & 0xff; - case 3: - *p++ = (num >> 16) & 0xff; - case 2: - *p++ = (num >> 8) & 0xff; - case 1: - *p = num & 0xff; - } - SSL_TRC(60, ("%d: number:", SSL_GETPID())); - rv = ssl3_AppendHandshake(ss, &b[0], lenSize); - return rv; /* error code set by AppendHandshake, if applicable. */ -} - -SECStatus -ssl3_AppendHandshakeVariable( - sslSocket *ss, const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize) -{ - SECStatus rv; - - PORT_Assert((bytes < (1 << 8) && lenSize == 1) || - (bytes < (1L << 16) && lenSize == 2) || - (bytes < (1L << 24) && lenSize == 3)); - - SSL_TRC(60, ("%d: append variable:", SSL_GETPID())); - rv = ssl3_AppendHandshakeNumber(ss, bytes, lenSize); - if (rv != SECSuccess) { - return rv; /* error code set by AppendHandshake, if applicable. */ - } - SSL_TRC(60, ("data:")); - rv = ssl3_AppendHandshake(ss, src, bytes); - return rv; /* error code set by AppendHandshake, if applicable. */ -} - SECStatus -ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) +ssl3_AppendHandshakeHeader(sslSocket *ss, SSLHandshakeType t, PRUint32 length) { SECStatus rv; @@ -4330,17 +3841,22 @@ ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes, PRUint8 **b, * On error, an alert has been sent, and a generic error code has been set. */ SECStatus -ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes, - PRUint8 **b, PRUint32 *length) +ssl3_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *num, PRUint32 bytes, + PRUint8 **b, PRUint32 *length) { PRUint8 *buf = *b; - int i; + PRUint32 i; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); *num = 0; - if (bytes > *length || bytes > sizeof(*num)) { + if (bytes > sizeof(*num)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + if (bytes > *length) { return ssl3_DecodeError(ss); } PRINT_BUF(60, (ss, "consume bytes:", *b, bytes)); @@ -4353,6 +3869,26 @@ ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes, return SECSuccess; } +SECStatus +ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes, + PRUint8 **b, PRUint32 *length) +{ + PRUint64 num64; + SECStatus rv; + + PORT_Assert(bytes <= sizeof(*num)); + if (bytes > sizeof(*num)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + rv = ssl3_ConsumeHandshakeNumber64(ss, &num64, bytes, b, length); + if (rv != SECSuccess) { + return SECFailure; + } + *num = num64 & 0xffffffff; + return SECSuccess; +} + /* Read in two values from the incoming decrypted byte stream "b", which is * *length bytes long. The first value is a number whose size is "bytes" * bytes long. The second value is a byte-string whose size is the value @@ -4762,6 +4298,8 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, unsigned int md5StateLen, shaStateLen; unsigned char md5StackBuf[256]; unsigned char shaStackBuf[512]; + const int md5Pad = ssl_GetMacDefByAlg(ssl_mac_md5)->pad_size; + const int shaPad = ssl_GetMacDefByAlg(ssl_mac_sha)->pad_size; md5StateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.md5, md5StackBuf, sizeof md5StackBuf, &md5StateLen); @@ -4783,7 +4321,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, /* compute hashes for SSL3. */ unsigned char s[4]; - if (!spec->master_secret) { + if (!spec->masterSecret) { PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); rv = SECFailure; goto loser; @@ -4799,11 +4337,10 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4)); } - PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, - mac_defs[mac_md5].pad_size)); + PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, md5Pad)); - rv |= PK11_DigestKey(md5, spec->master_secret); - rv |= PK11_DigestOp(md5, mac_pad_1, mac_defs[mac_md5].pad_size); + rv |= PK11_DigestKey(md5, spec->masterSecret); + rv |= PK11_DigestOp(md5, mac_pad_1, md5Pad); rv |= PK11_DigestFinal(md5, md5_inner, &outLength, MD5_LENGTH); PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); if (rv != SECSuccess) { @@ -4819,11 +4356,10 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4)); } - PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, - mac_defs[mac_sha].pad_size)); + PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, shaPad)); - rv |= PK11_DigestKey(sha, spec->master_secret); - rv |= PK11_DigestOp(sha, mac_pad_1, mac_defs[mac_sha].pad_size); + rv |= PK11_DigestKey(sha, spec->masterSecret); + rv |= PK11_DigestOp(sha, mac_pad_1, shaPad); rv |= PK11_DigestFinal(sha, sha_inner, &outLength, SHA1_LENGTH); PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); if (rv != SECSuccess) { @@ -4834,13 +4370,12 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength)); - PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, - mac_defs[mac_md5].pad_size)); + PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, md5Pad)); PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH)); rv |= PK11_DigestBegin(md5); - rv |= PK11_DigestKey(md5, spec->master_secret); - rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); + rv |= PK11_DigestKey(md5, spec->masterSecret); + rv |= PK11_DigestOp(md5, mac_pad_2, md5Pad); rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); } rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH); @@ -4854,13 +4389,12 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH)); if (!isTLS) { - PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, - mac_defs[mac_sha].pad_size)); + PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, shaPad)); PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH)); rv |= PK11_DigestBegin(sha); - rv |= PK11_DigestKey(sha, spec->master_secret); - rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); + rv |= PK11_DigestKey(sha, spec->masterSecret); + rv |= PK11_DigestOp(sha, mac_pad_2, shaPad); rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); } rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH); @@ -4926,6 +4460,48 @@ ssl_ClientHelloTypeName(sslClientHelloType type) #undef CHTYPE #endif +PR_STATIC_ASSERT(SSL3_SESSIONID_BYTES == SSL3_RANDOM_LENGTH); +static void +ssl_MakeFakeSid(sslSocket *ss, PRUint8 *buf) +{ + PRUint8 x = 0x5a; + int i; + for (i = 0; i < SSL3_SESSIONID_BYTES; ++i) { + x += ss->ssl3.hs.client_random[i]; + buf[i] = x; + } +} + +/* Set the version fields of the cipher spec for a ClientHello. */ +static void +ssl_SetClientHelloSpecVersion(sslSocket *ss, ssl3CipherSpec *spec) +{ + ssl_GetSpecWriteLock(ss); + PORT_Assert(spec->cipherDef->cipher == cipher_null); + /* This is - a best guess - but it doesn't matter here. */ + spec->version = ss->vrange.max; + if (IS_DTLS(ss)) { + spec->recordVersion = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE; + } else { + /* For new connections, cap the record layer version number of TLS + * ClientHello to { 3, 1 } (TLS 1.0). Some TLS 1.0 servers (which seem + * to use F5 BIG-IP) ignore ClientHello.client_version and use the + * record layer version number (TLSPlaintext.version) instead when + * negotiating protocol versions. In addition, if the record layer + * version number of ClientHello is { 3, 2 } (TLS 1.1) or higher, these + * servers reset the TCP connections. Lastly, some F5 BIG-IP servers + * hang if a record containing a ClientHello has a version greater than + * { 3, 1 } and a length greater than 255. Set this flag to work around + * such servers. + * + * The final version is set when a version is negotiated. + */ + spec->recordVersion = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, + ss->vrange.max); + } + ssl_ReleaseSpecWriteLock(ss); +} + /* Called from ssl3_HandleHelloRequest(), * ssl3_RedoHandshake() * ssl_BeginClientHandshake (when resuming ssl3 session) @@ -4942,18 +4518,18 @@ SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) { sslSessionID *sid; - ssl3CipherSpec *cwSpec; SECStatus rv; - int i; - int length; - int num_suites; - int actual_count = 0; + unsigned int i; + unsigned int length; + unsigned int num_suites; + unsigned int actual_count = 0; PRBool isTLS = PR_FALSE; PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; - PRInt32 total_exten_len = 0; - unsigned numCompressionMethods; - PRUint16 version; + PRBool unlockNeeded = PR_FALSE; + sslBuffer extensionBuf = SSL_BUFFER_EMPTY; + PRUint16 version = ss->vrange.max; PRInt32 flags; + unsigned int cookieLen = ss->ssl3.hs.cookie.len; SSL_TRC(3, ("%d: SSL3[%d]: send %s ClientHello handshake", SSL_GETPID(), ss->fd, ssl_ClientHelloTypeName(type))); @@ -4972,22 +4548,26 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) * to maintain the handshake hashes. */ if (ss->ssl3.hs.helloRetry) { PORT_Assert(type == client_hello_retry); + /* This cookieLen applies to the cookie that appears in the DTLS + ClientHello, which isn't used in DTLS 1.3. */ + cookieLen = 0; } else { - ssl3_InitState(ss); ssl3_RestartHandshakeHashes(ss); } + if (type == client_hello_initial) { + ssl_SetClientHelloSpecVersion(ss, ss->ssl3.cwSpec); + } /* These must be reset every handshake. */ + ssl3_ResetExtensionData(&ss->xtnData, ss); ss->ssl3.hs.sendingSCSV = PR_FALSE; ss->ssl3.hs.preliminaryInfo = 0; PORT_Assert(IS_DTLS(ss) || type != client_hello_retransmit); SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE); ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE; - ssl3_ResetExtensionData(&ss->xtnData); /* How many suites does our PKCS11 support (regardless of policy)? */ - num_suites = ssl3_config_match_init(ss); - if (!num_suites) { + if (ssl3_config_match_init(ss) == 0) { return SECFailure; /* ssl3_config_match_init has set error code. */ } @@ -5035,7 +4615,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) } /* Check that we can recover the master secret. */ - if (sidOK && sid->u.ssl3.keys.msIsWrapped) { + if (sidOK) { PK11SlotInfo *slot = NULL; if (sid->u.ssl3.masterValid) { slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, @@ -5100,8 +4680,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) if (sid->version < ss->vrange.min || sid->version > ss->vrange.max) { sidOK = PR_FALSE; - } else { - version = ss->vrange.max; } } } @@ -5135,8 +4713,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) */ if (ss->firstHsDone) { version = ss->clientHelloVersion; - } else { - version = ss->vrange.max; } sid = ssl3_NewSessionID(ss, PR_FALSE); @@ -5149,10 +4725,9 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) isTLS = (version > SSL_LIBRARY_VERSION_3_0); ssl_GetSpecWriteLock(ss); - cwSpec = ss->ssl3.cwSpec; - if (cwSpec->mac_def->mac == mac_null) { + if (ss->ssl3.cwSpec->macDef->mac == ssl_mac_null) { /* SSL records are not being MACed. */ - cwSpec->version = version; + ss->ssl3.cwSpec->version = version; } ssl_ReleaseSpecWriteLock(ss); @@ -5176,9 +4751,10 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) * NewSessionTicket that will cause the ticket in the sid to be replaced. * Once we've copied the session ticket into our ClientHello message, it * is OK for the ticket to change, so we just need to make sure we hold - * the lock across the calls to ssl3_CallHelloExtensionSenders. + * the lock across the calls to ssl_ConstructExtensions. */ if (sid->u.ssl3.lock) { + unlockNeeded = PR_TRUE; PR_RWLock_Rlock(sid->u.ssl3.lock); } @@ -5186,24 +4762,14 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) type == client_hello_initial) { rv = tls13_SetupClientHello(ss); if (rv != SECSuccess) { - return SECFailure; + goto loser; } } if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) { - PRUint32 maxBytes = 65535; /* 2^16 - 1 */ - PRInt32 extLen; - - extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, NULL); - if (extLen < 0) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; + rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_client_hello); + if (rv != SECSuccess) { + goto loser; } - total_exten_len += extLen; - - if (total_exten_len > 0) - total_exten_len += 2; } if (IS_DTLS(ss)) { @@ -5213,10 +4779,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) /* how many suites are permitted by policy and user preference? */ num_suites = count_cipher_suites(ss, ss->ssl3.policy); if (!num_suites) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; /* count_cipher_suites has set error code. */ + goto loser; /* count_cipher_suites has set error code. */ } fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume || @@ -5229,37 +4792,30 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) ++num_suites; } - /* count compression methods */ - numCompressionMethods = 0; - for (i = 0; i < ssl_compression_method_count; i++) { - if (ssl_CompressionEnabled(ss, ssl_compression_methods[i])) - numCompressionMethods++; - } - length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + - 1 + (sid->version >= SSL_LIBRARY_VERSION_TLS_1_3 - ? 0 - : sid->u.ssl3.sessionIDLength) + + 1 + /* session id */ 2 + num_suites * sizeof(ssl3CipherSuite) + - 1 + numCompressionMethods + total_exten_len; + 1 + 1 /* compression methods */; + if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) { + length += sid->u.ssl3.sessionIDLength; + } else if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) { + length += SSL3_SESSIONID_BYTES; + } if (IS_DTLS(ss)) { - length += 1 + ss->ssl3.hs.cookie.len; + length += 1 + cookieLen; } - if (total_exten_len > 0) { - ssl3_CalculatePaddingExtLen(ss, length); - if (ss->xtnData.paddingLen) { - total_exten_len += 4 + ss->xtnData.paddingLen; - length += 4 + ss->xtnData.paddingLen; + if (extensionBuf.len) { + rv = ssl_InsertPaddingExtension(ss, length, &extensionBuf); + if (rv != SECSuccess) { + goto loser; /* err set by ssl_InsertPaddingExtension */ } + length += 2 + extensionBuf.len; } - rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_hello, length); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } if (ss->firstHsDone) { @@ -5277,60 +4833,49 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2); } if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } /* Generate a new random if this is the first attempt. */ if (type == client_hello_initial) { - rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random); + rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by GetNewRandom. */ + goto loser; /* err set by GetNewRandom. */ } } - rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random, + rv = ssl3_AppendHandshake(ss, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } - if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) + if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) { rv = ssl3_AppendHandshakeVariable( ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1); - else + } else if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) { + /* We're faking session resumption, so rather than create new + * randomness, just mix up the client random a little. */ + PRUint8 buf[SSL3_SESSIONID_BYTES]; + ssl_MakeFakeSid(ss, buf); + rv = ssl3_AppendHandshakeVariable(ss, buf, SSL3_SESSIONID_BYTES, 1); + } else { rv = ssl3_AppendHandshakeNumber(ss, 0, 1); + } if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } if (IS_DTLS(ss)) { rv = ssl3_AppendHandshakeVariable( - ss, ss->ssl3.hs.cookie.data, ss->ssl3.hs.cookie.len, 1); + ss, ss->ssl3.hs.cookie.data, cookieLen, 1); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } } rv = ssl3_AppendHandshakeNumber(ss, num_suites * sizeof(ssl3CipherSuite), 2); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } if (ss->ssl3.hs.sendingSCSV) { @@ -5338,10 +4883,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) rv = ssl3_AppendHandshakeNumber(ss, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, sizeof(ssl3CipherSuite)); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } actual_count++; } @@ -5349,10 +4891,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV, sizeof(ssl3CipherSuite)); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } actual_count++; } @@ -5361,20 +4900,14 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) if (config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) { actual_count++; if (actual_count > num_suites) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } /* set error card removal/insertion error */ PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); - return SECFailure; + goto loser; } rv = ssl3_AppendHandshakeNumber(ss, suite->cipher_suite, sizeof(ssl3CipherSuite)); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } } } @@ -5384,57 +4917,37 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) * the server.. */ if (actual_count != num_suites) { /* Card removal/insertion error */ - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); - return SECFailure; + goto loser; } - rv = ssl3_AppendHandshakeNumber(ss, numCompressionMethods, 1); + /* Compression methods: count is always 1, null compression. */ + rv = ssl3_AppendHandshakeNumber(ss, 1, 1); if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ + goto loser; /* err set by ssl3_AppendHandshake* */ } - for (i = 0; i < ssl_compression_method_count; i++) { - if (!ssl_CompressionEnabled(ss, ssl_compression_methods[i])) - continue; - rv = ssl3_AppendHandshakeNumber(ss, ssl_compression_methods[i], 1); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by ssl3_AppendHandshake* */ - } + rv = ssl3_AppendHandshakeNumber(ss, ssl_compression_null, 1); + if (rv != SECSuccess) { + goto loser; /* err set by ssl3_AppendHandshake* */ } - if (total_exten_len) { - PRUint32 maxBytes = total_exten_len - 2; - PRInt32 extLen; - - rv = ssl3_AppendHandshakeNumber(ss, maxBytes, 2); - if (rv != SECSuccess) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return rv; /* err set by AppendHandshake. */ + if (extensionBuf.len) { + /* If we are sending a PSK binder, replace the dummy value. Note that + * we only set statelessResume on the client in TLS 1.3. */ + if (ss->statelessResume && + ss->xtnData.sentSessionTicketInClientHello) { + rv = tls13_WriteExtensionsWithBinder(ss, &extensionBuf); + } else { + rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2); } - - extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL); - if (extLen < 0) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ } - maxBytes -= extLen; - - PORT_Assert(!maxBytes); } - if (sid->u.ssl3.lock) { + sslBuffer_Clear(&extensionBuf); + if (unlockNeeded) { + /* Note: goto loser can't be used past this point. */ PR_RWLock_Unlock(sid->u.ssl3.lock); } @@ -5450,9 +4963,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) } flags = 0; - if (!ss->firstHsDone && !IS_DTLS(ss)) { - flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION; - } rv = ssl3_FlushHandshake(ss, flags); if (rv != SECSuccess) { return rv; /* error code set by ssl3_FlushHandshake */ @@ -5467,6 +4977,13 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) ss->ssl3.hs.ws = wait_server_hello; return SECSuccess; + +loser: + if (unlockNeeded) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + sslBuffer_Clear(&extensionBuf); + return SECFailure; } /* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a @@ -6018,7 +5535,7 @@ ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) /* Generate the pre-master secret ... */ ssl_GetSpecWriteLock(ss); - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.pwSpec, NULL); ssl_ReleaseSpecWriteLock(ss); @@ -6041,41 +5558,20 @@ ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) goto loser; } -#ifdef NSS_ALLOW_SSLKEYLOGFILE - if (ssl_keylog_iob) { +#ifdef TRACE + if (ssl_trace >= 100) { SECStatus extractRV = PK11_ExtractKeyValue(pms); if (extractRV == SECSuccess) { SECItem *keyData = PK11_GetKeyData(pms); if (keyData && keyData->data && keyData->len) { -#ifdef TRACE - if (ssl_trace >= 100) { - ssl_PrintBuf(ss, "Pre-Master Secret", - keyData->data, keyData->len); - } -#endif - if (ssl_keylog_iob && enc_pms.len >= 8 && keyData->len == 48) { - /* https://developer.mozilla.org/en/NSS_Key_Log_Format */ - - /* There could be multiple, concurrent writers to the - * keylog, so we have to do everything in a single call to - * fwrite. */ - char buf[4 + 8 * 2 + 1 + 48 * 2 + 1]; - - strcpy(buf, "RSA "); - hexEncode(buf + 4, enc_pms.data, 8); - buf[20] = ' '; - hexEncode(buf + 21, keyData->data, 48); - buf[sizeof(buf) - 1] = '\n'; - - fwrite(buf, sizeof(buf), 1, ssl_keylog_iob); - fflush(ssl_keylog_iob); - } + ssl_PrintBuf(ss, "Pre-Master Secret", + keyData->data, keyData->len); } } } #endif - rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange, isTLS ? enc_pms.len + 2 : enc_pms.len); if (rv != SECSuccess) { @@ -6090,7 +5586,7 @@ ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) goto loser; /* err set by ssl3_AppendHandshake* */ } - rv = ssl3_InitPendingCipherSpec(ss, pms); + rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); PK11_FreeSymKey(pms); pms = NULL; @@ -6114,27 +5610,27 @@ loser: /* DH shares need to be padded to the size of their prime. Some implementations * require this. TLS 1.3 also requires this. */ SECStatus -ssl_AppendPaddedDHKeyShare(const sslSocket *ss, const SECKEYPublicKey *pubKey, +ssl_AppendPaddedDHKeyShare(sslBuffer *buf, const SECKEYPublicKey *pubKey, PRBool appendLength) { SECStatus rv; unsigned int pad = pubKey->u.dh.prime.len - pubKey->u.dh.publicValue.len; if (appendLength) { - rv = ssl3_ExtAppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2); + rv = sslBuffer_AppendNumber(buf, pubKey->u.dh.prime.len, 2); if (rv != SECSuccess) { return rv; } } while (pad) { - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 1); + rv = sslBuffer_AppendNumber(buf, 0, 1); if (rv != SECSuccess) { return rv; } --pad; } - rv = ssl3_ExtAppendHandshake(ss, pubKey->u.dh.publicValue.data, - pubKey->u.dh.publicValue.len); + rv = sslBuffer_Append(buf, pubKey->u.dh.publicValue.data, + pubKey->u.dh.publicValue.len); if (rv != SECSuccess) { return rv; } @@ -6158,11 +5654,13 @@ ssl3_SendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) }; sslEphemeralKeyPair *keyPair = NULL; SECKEYPublicKey *pubKey; + PRUint8 dhData[1026]; /* Enough for the 8192-bit group. */ + sslBuffer dhBuf = SSL_BUFFER(dhData); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); /* Copy DH parameters from server key */ @@ -6217,22 +5715,27 @@ ssl3_SendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) } /* Note: send the DH share padded to avoid triggering bugs. */ - rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange, params->prime.len + 2); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } - rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_TRUE); + rv = ssl_AppendPaddedDHKeyShare(&dhBuf, pubKey, PR_TRUE); if (rv != SECSuccess) { goto loser; /* err set by ssl_AppendPaddedDHKeyShare */ } + rv = ssl3_AppendBufferToHandshake(ss, &dhBuf); + if (rv != SECSuccess) { + goto loser; /* err set by ssl3_AppendBufferToHandshake */ + } - rv = ssl3_InitPendingCipherSpec(ss, pms); + rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } + sslBuffer_Clear(&dhBuf); PK11_FreeSymKey(pms); ssl_FreeEphemeralKeyPair(keyPair); return SECSuccess; @@ -6242,6 +5745,7 @@ loser: PK11_FreeSymKey(pms); if (keyPair) ssl_FreeEphemeralKeyPair(keyPair); + sslBuffer_Clear(&dhBuf); return SECFailure; } @@ -6422,8 +5926,8 @@ ssl3_PickServerSignatureScheme(sslSocket *ss) /* Sets error code, if needed. */ return ssl_PickSignatureScheme(ss, keyPair->pubKey, keyPair->privKey, - ss->xtnData.clientSigSchemes, - ss->xtnData.numClientSigScheme, + ss->xtnData.sigSchemes, + ss->xtnData.numSigSchemes, PR_FALSE /* requireSha1 */); } @@ -6540,7 +6044,7 @@ ssl3_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey) len = buf.len + 2 + (isTLS12 ? 2 : 0); - rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len); if (rv != SECSuccess) { goto done; /* error code set by AppendHandshake */ } @@ -6564,11 +6068,9 @@ done: /* Once a cipher suite has been selected, make sure that the necessary secondary * information is properly set. */ SECStatus -ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite, - PRBool initHashes) +ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes) { - ss->ssl3.hs.cipher_suite = chosenSuite; - ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(chosenSuite); + ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); if (!ss->ssl3.hs.suite_def) { PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -6581,10 +6083,53 @@ ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite, if (!initHashes) { return SECSuccess; } - /* Now we've have a cipher suite, initialize the handshake hashes. */ + /* Now we have a cipher suite, initialize the handshake hashes. */ return ssl3_InitHandshakeHashes(ss); } +SECStatus +ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version, + ssl3CipherSuite suite, PRBool initHashes) +{ + unsigned int i; + if (ssl3_config_match_init(ss) == 0) { + PORT_Assert(PR_FALSE); + return SECFailure; + } + for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { + ssl3CipherSuiteCfg *suiteCfg = &ss->cipherSuites[i]; + if (suite == suiteCfg->cipher_suite) { + SSLVersionRange vrange = { version, version }; + if (!config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) { + /* config_match already checks whether the cipher suite is + * acceptable for the version, but the check is repeated here + * in order to give a more precise error code. */ + if (!ssl3_CipherSuiteAllowedForVersionRange(suite, &vrange)) { + PORT_SetError(SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION); + } else { + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + } + return SECFailure; + } + break; + } + } + if (i >= ssl_V3_SUITES_IMPLEMENTED) { + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + return SECFailure; + } + + /* Don't let the server change its mind. */ + if (ss->ssl3.hs.helloRetry && suite != ss->ssl3.hs.cipher_suite) { + (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); + return SECFailure; + } + + ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)suite; + return ssl3_SetupCipherSuite(ss, initHashes); +} + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 ServerHello message. * Caller must hold Handshake and RecvBuf locks. @@ -6592,14 +6137,16 @@ ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite, static SECStatus ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) { - PRUint32 temp; - PRBool suite_found = PR_FALSE; - int i; + PRUint32 cipher; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; + PRUint32 compression; SECStatus rv; SECItem sidBytes = { siBuffer, NULL, 0 }; - PRBool isTLS = PR_FALSE; + PRBool isHelloRetry; SSL3AlertDescription desc = illegal_parameter; + TLSExtension *versionExtension; + const PRUint8 *savedMsg = b; + const PRUint32 savedLength = length; #ifndef TLS_1_3_DRAFT_VERSION SSL3ProtocolVersion downgradeCheckVersion; #endif @@ -6608,7 +6155,6 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) SSL_GETPID(), ss->fd)); PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.initialized); if (ss->ssl3.hs.ws != wait_server_hello) { errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO; @@ -6630,11 +6176,95 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) ss->ssl3.clientPrivateKey = NULL; } + /* Note that if the server selects TLS 1.3, this will set the version to TLS + * 1.2. We will amend that once all other fields have been read. */ rv = ssl_ClientReadVersion(ss, &b, &length, &ss->version); if (rv != SECSuccess) { goto loser; /* alert has been sent */ } + rv = ssl3_ConsumeHandshake( + ss, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); + if (rv != SECSuccess) { + goto loser; /* alert has been sent */ + } + isHelloRetry = !PORT_Memcmp(ss->ssl3.hs.server_random, + ssl_hello_retry_random, SSL3_RANDOM_LENGTH); + + rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length); + if (rv != SECSuccess) { + goto loser; /* alert has been sent */ + } + if (sidBytes.len > SSL3_SESSIONID_BYTES) { + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_0) + desc = decode_error; + goto alert_loser; /* malformed. */ + } + + /* Read the cipher suite. */ + rv = ssl3_ConsumeHandshakeNumber(ss, &cipher, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* alert has been sent */ + } + + /* Compression method. */ + rv = ssl3_ConsumeHandshakeNumber(ss, &compression, 1, &b, &length); + if (rv != SECSuccess) { + goto loser; /* alert has been sent */ + } + if (compression != ssl_compression_null) { + desc = illegal_parameter; + errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; + goto alert_loser; + } + + /* Parse extensions. */ + if (length != 0) { + PRUint32 extensionLength; + rv = ssl3_ConsumeHandshakeNumber(ss, &extensionLength, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* alert already sent */ + } + if (extensionLength != length) { + desc = decode_error; + goto alert_loser; + } + rv = ssl3_ParseExtensions(ss, &b, &length); + if (rv != SECSuccess) { + goto alert_loser; /* malformed */ + } + } + + /* 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 */ + } + } + + PORT_Assert(!SSL_ALL_VERSIONS_DISABLED(&ss->vrange)); + /* Check that the version is within the configured range. */ + if (ss->vrange.min > ss->version || ss->vrange.max < ss->version) { + desc = (ss->version > SSL_LIBRARY_VERSION_3_0) + ? protocol_version + : handshake_failure; + errCode = SSL_ERROR_UNSUPPORTED_VERSION; + goto alert_loser; + } + + if (isHelloRetry && ss->ssl3.hs.helloRetry) { + SSL_TRC(3, ("%d: SSL3[%d]: received a second hello_retry_request", + SSL_GETPID(), ss->fd)); + desc = unexpected_message; + errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST; + goto alert_loser; + } + /* 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) { @@ -6657,18 +6287,10 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) * us to be getting this version number, but it's what we have. * (1294697). */ if (ss->firstHsDone && (ss->version != ss->ssl3.crSpec->version)) { - desc = illegal_parameter; + desc = protocol_version; errCode = SSL_ERROR_UNSUPPORTED_VERSION; goto alert_loser; } - ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version; - isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); - - rv = ssl3_ConsumeHandshake( - ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); - if (rv != SECSuccess) { - goto loser; /* alert has been sent */ - } #ifndef TLS_1_3_DRAFT_VERSION /* Check the ServerHello.random per @@ -6688,8 +6310,8 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) if (downgradeCheckVersion >= SSL_LIBRARY_VERSION_TLS_1_2 && downgradeCheckVersion > ss->version) { /* Both sections use the same sentinel region. */ - unsigned char *downgrade_sentinel = - ss->ssl3.hs.server_random.rand + + PRUint8 *downgrade_sentinel = + ss->ssl3.hs.server_random + SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); if (!PORT_Memcmp(downgrade_sentinel, tls13_downgrade_random, @@ -6704,110 +6326,64 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) } #endif - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* alert has been sent */ + /* 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) { + ssl_GetSpecWriteLock(ss); + ssl_SetSpecVersions(ss, ss->ssl3.cwSpec); + ssl_ReleaseSpecWriteLock(ss); + } + + /* Check that the session ID is as expected. */ + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + PRUint8 buf[SSL3_SESSIONID_BYTES]; + unsigned int expectedSidLen; + if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) { + expectedSidLen = SSL3_SESSIONID_BYTES; + ssl_MakeFakeSid(ss, buf); + } else { + expectedSidLen = 0; } - if (sidBytes.len > SSL3_SESSIONID_BYTES) { - if (isTLS) - desc = decode_error; - goto alert_loser; /* malformed. */ + if (sidBytes.len != expectedSidLen || + (expectedSidLen > 0 && + PORT_Memcmp(buf, sidBytes.data, expectedSidLen) != 0)) { + desc = illegal_parameter; + errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; + goto alert_loser; } } - /* find selected cipher suite in our list. */ - rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &b, &length); + /* Only initialize hashes if this isn't a Hello Retry. */ + rv = ssl_ClientSetCipherSuite(ss, ss->version, cipher, + !isHelloRetry); if (rv != SECSuccess) { - goto loser; /* alert has been sent */ - } - i = ssl3_config_match_init(ss); - PORT_Assert(i > 0); - if (i <= 0) { + desc = illegal_parameter; errCode = PORT_GetError(); - goto loser; + goto alert_loser; } - for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; - if (temp == suite->cipher_suite) { - SSLVersionRange vrange = { ss->version, ss->version }; - if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) { - /* config_match already checks whether the cipher suite is - * acceptable for the version, but the check is repeated here - * in order to give a more precise error code. */ - if (!ssl3_CipherSuiteAllowedForVersionRange(temp, &vrange)) { - desc = handshake_failure; - errCode = SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION; - goto alert_loser; - } - break; /* failure */ - } + dtls_ReceivedFirstMessageInFlight(ss); - suite_found = PR_TRUE; - break; /* success */ + if (isHelloRetry) { + rv = tls13_HandleHelloRetryRequest(ss, savedMsg, savedLength); + if (rv != SECSuccess) { + goto loser; } - } - if (!suite_found) { - desc = handshake_failure; - errCode = SSL_ERROR_NO_CYPHER_OVERLAP; - goto alert_loser; + return SECSuccess; } - rv = ssl3_SetCipherSuite(ss, (ssl3CipherSuite)temp, PR_TRUE); + rv = ssl3_HandleParsedExtensions(ss, ssl_hs_server_hello); + ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); if (rv != SECSuccess) { - desc = internal_error; - errCode = PORT_GetError(); goto alert_loser; } - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - /* find selected compression method in our list. */ - rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* alert has been sent */ - } - suite_found = PR_FALSE; - for (i = 0; i < ssl_compression_method_count; i++) { - if (temp == ssl_compression_methods[i]) { - if (!ssl_CompressionEnabled(ss, ssl_compression_methods[i])) { - break; /* failure */ - } - suite_found = PR_TRUE; - break; /* success */ - } - } - if (!suite_found) { - desc = handshake_failure; - errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP; - goto alert_loser; - } - ss->ssl3.hs.compression = (SSLCompressionMethod)temp; - } else { - ss->ssl3.hs.compression = ssl_compression_null; - } - - /* Note that if !isTLS and the extra stuff is not extensions, we - * do NOT goto alert_loser. - * There are some old SSL 3.0 implementations that do send stuff - * after the end of the server hello, and we deliberately ignore - * such stuff in the interest of maximal interoperability (being - * "generous in what you accept"). - * Update: Starting in NSS 3.12.6, we handle the renegotiation_info - * extension in SSL 3.0. - */ - if (length != 0) { - SECItem extensions; - rv = ssl3_ConsumeHandshakeVariable(ss, &extensions, 2, &b, &length); - if (rv != SECSuccess || length != 0) { - if (isTLS) - goto alert_loser; - } else { - rv = ssl3_HandleExtensions(ss, &extensions.data, - &extensions.len, server_hello); - if (rv != SECSuccess) - goto alert_loser; - } + rv = ssl_HashHandshakeMessage(ss, ssl_hs_server_hello, + savedMsg, savedLength); + if (rv != SECSuccess) { + goto loser; } if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { @@ -6835,6 +6411,51 @@ loser: } static SECStatus +ssl3_UnwrapMasterSecretClient(sslSocket *ss, sslSessionID *sid, PK11SymKey **ms) +{ + PK11SlotInfo *slot; + PK11SymKey *wrapKey; + CK_FLAGS keyFlags = 0; + SECItem wrappedMS = { + siBuffer, + sid->u.ssl3.keys.wrapped_master_secret, + sid->u.ssl3.keys.wrapped_master_secret_len + }; + + /* unwrap master secret */ + slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, + sid->u.ssl3.masterSlotID); + if (slot == NULL) { + return SECFailure; + } + if (!PK11_IsPresent(slot)) { + PK11_FreeSlot(slot); + return SECFailure; + } + wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex, + sid->u.ssl3.masterWrapMech, + sid->u.ssl3.masterWrapSeries, + ss->pkcs11PinArg); + PK11_FreeSlot(slot); + if (wrapKey == NULL) { + return SECFailure; + } + + if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ + keyFlags = CKF_SIGN | CKF_VERIFY; + } + + *ms = PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, + NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, + CKA_DERIVE, SSL3_MASTER_SECRET_LENGTH, keyFlags); + PK11_FreeSymKey(wrapKey); + if (!*ms) { + return SECFailure; + } + return SECSuccess; +} + +static SECStatus ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, int *retErrCode) { @@ -6860,7 +6481,7 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, /* we need to call ssl3_SetupPendingCipherSpec here so we can check the * key exchange algorithm. */ - rv = ssl3_SetupPendingCipherSpec(ss); + rv = ssl3_SetupBothPendingCipherSpecs(ss); if (rv != SECSuccess) { goto alert_loser; /* error code is set. */ } @@ -6883,9 +6504,7 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, goto alert_loser; } do { - ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - - SECItem wrappedMS; /* wrapped master secret. */ + PK11SymKey *masterSecret; /* [draft-ietf-tls-session-hash-06; Section 5.3] * @@ -6917,60 +6536,12 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, ss->sec.authKeyBits = sid->authKeyBits; ss->sec.keaType = sid->keaType; ss->sec.keaKeyBits = sid->keaKeyBits; + ss->sec.originalKeaGroup = ssl_LookupNamedGroup(sid->keaGroup); + ss->sec.signatureScheme = sid->sigScheme; - if (sid->u.ssl3.keys.msIsWrapped) { - PK11SlotInfo *slot; - PK11SymKey *wrapKey; /* wrapping key */ - CK_FLAGS keyFlags = 0; - - /* unwrap master secret */ - slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, - sid->u.ssl3.masterSlotID); - if (slot == NULL) { - break; /* not considered an error. */ - } - if (!PK11_IsPresent(slot)) { - PK11_FreeSlot(slot); - break; /* not considered an error. */ - } - wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex, - sid->u.ssl3.masterWrapMech, - sid->u.ssl3.masterWrapSeries, - ss->pkcs11PinArg); - PK11_FreeSlot(slot); - if (wrapKey == NULL) { - break; /* not considered an error. */ - } - - if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - keyFlags = - CKF_SIGN | CKF_VERIFY; - } - - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - pwSpec->master_secret = - PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, - NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, - CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); - errCode = PORT_GetError(); - PK11_FreeSymKey(wrapKey); - if (pwSpec->master_secret == NULL) { - break; /* errorCode set just after call to UnwrapSymKey. */ - } - } else { - /* need to import the raw master secret to session object */ - PK11SlotInfo *slot = PK11_GetInternalSlot(); - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - pwSpec->master_secret = - PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, - PK11_OriginUnwrap, CKA_ENCRYPT, - &wrappedMS, NULL); - PK11_FreeSlot(slot); - if (pwSpec->master_secret == NULL) { - break; - } + rv = ssl3_UnwrapMasterSecretClient(ss, sid, &masterSecret); + if (rv != SECSuccess) { + break; /* not considered an error */ } /* Got a Match */ @@ -6992,8 +6563,8 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); } - /* NULL value for PMS because we are reusing the old MS */ - rv = ssl3_InitPendingCipherSpec(ss, NULL); + /* We are re-using the old MS, so no need to derive again. */ + rv = ssl3_InitPendingCipherSpecs(ss, masterSecret, PR_FALSE); if (rv != SECSuccess) { goto alert_loser; /* err code was set */ } @@ -7098,11 +6669,11 @@ ssl_HandleDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) } rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH); - if (rv != SECSuccess) { + if (rv != SECSuccess || minDH <= 0) { minDH = SSL_DH_MIN_P_BITS; } dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p); - if (dh_p_bits < minDH) { + if (dh_p_bits < (unsigned)minDH) { errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY; goto alert_loser; } @@ -7283,7 +6854,7 @@ typedef struct dnameNode { */ SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, - PLArenaPool *arena, CERTDistNames *ca_list) + CERTDistNames *ca_list) { PRUint32 remaining; int nnames = 0; @@ -7298,7 +6869,7 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, if (remaining > *length) goto alert_loser; - ca_list->head = node = PORT_ArenaZNew(arena, dnameNode); + ca_list->head = node = PORT_ArenaZNew(ca_list->arena, dnameNode); if (node == NULL) goto no_mem; @@ -7324,14 +6895,14 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, if (remaining <= 0) break; /* success */ - node->next = PORT_ArenaZNew(arena, dnameNode); + node->next = PORT_ArenaZNew(ca_list->arena, dnameNode); node = node->next; if (node == NULL) goto no_mem; } ca_list->nnames = nnames; - ca_list->names = PORT_ArenaNewArray(arena, SECItem, nnames); + ca_list->names = PORT_ArenaNewArray(ca_list->arena, SECItem, nnames); if (nnames > 0 && ca_list->names == NULL) goto no_mem; @@ -7475,7 +7046,7 @@ ssl3_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) } } - rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list); + rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, &ca_list); if (rv != SECSuccess) goto done; /* alert sent in ssl3_ParseCertificateRequestCAs */ @@ -7575,7 +7146,7 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss, case SECFailure: default: send_no_certificate: - if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { + if (ss->version > SSL_LIBRARY_VERSION_3_0) { ss->ssl3.sendEmptyCert = PR_TRUE; } else { (void)SSL3_SendAlert(ss, alert_warning, no_certificate); @@ -7606,7 +7177,7 @@ ssl3_CheckFalseStart(sslSocket *ss) * sufficiently strong that the attack can gain no advantage. * Therefore we always require an 80-bit cipher. */ ssl_GetSpecReadLock(ss); - maybeFalseStart = ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10; + maybeFalseStart = ss->ssl3.cwSpec->cipherDef->secret_key_size >= 10; ssl_ReleaseSpecReadLock(ss); if (!maybeFalseStart) { @@ -7858,7 +7429,7 @@ ssl3_SendHelloRequest(sslSocket *ss) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - rv = ssl3_AppendHandshakeHeader(ss, hello_request, 0); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_hello_request, 0); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake */ } @@ -7927,6 +7498,7 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server) sid->references = 1; sid->cached = never_cached; sid->version = ss->version; + sid->sigScheme = ssl_sig_none; sid->u.ssl3.keys.resumable = PR_TRUE; sid->u.ssl3.policy = SSL_ALLOWED; @@ -8037,8 +7609,8 @@ SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites, PRBool initHashes) { - int j; - int i; + unsigned int j; + unsigned int i; for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; @@ -8049,7 +7621,8 @@ ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites, for (i = 0; i + 1 < suites->len; i += 2) { PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1]; if (suite_i == suite->cipher_suite) { - return ssl3_SetCipherSuite(ss, suite_i, initHashes); + ss->ssl3.hs.cipher_suite = suite_i; + return ssl3_SetupCipherSuite(ss, initHashes); } } } @@ -8148,7 +7721,6 @@ ssl3_ServerCallSNICallback(sslSocket *ss) * and save the name. */ SECStatus rv; SECItem *name = &ss->xtnData.sniNameArr[ret]; - int configedCiphers; SECItem *pwsName; /* get rid of the old name and save the newly picked. */ @@ -8177,8 +7749,7 @@ ssl3_ServerCallSNICallback(sslSocket *ss) ret = SSL_SNI_SEND_ALERT; break; } - configedCiphers = ssl3_config_match_init(ss); - if (configedCiphers <= 0) { + if (ssl3_config_match_init(ss) == 0) { /* no ciphers are working/supported */ errCode = PORT_GetError(); desc = handshake_failure; @@ -8189,7 +7760,7 @@ ssl3_ServerCallSNICallback(sslSocket *ss) * the name from the offered list and reconfigured the socket. */ ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn, - ssl3_SendServerNameXtn); + ssl_SendEmptyExtension); } else { /* Callback returned index outside of the boundary. */ PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize); @@ -8288,13 +7859,14 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) SECItem suites = { siBuffer, NULL, 0 }; SECItem comps = { siBuffer, NULL, 0 }; PRBool isTLS13; + const PRUint8 *savedMsg = b; + const PRUint32 savedLen = length; SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake", SSL_GETPID(), ss->fd)); PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.initialized); ss->ssl3.hs.preliminaryInfo = 0; if (!ss->sec.isServer || @@ -8319,6 +7891,9 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) } } + /* We should always be in a fresh state. */ + SSL_ASSERT_HASHES_EMPTY(ss); + /* Get peer name of client */ rv = ssl_GetPeerInfo(ss); if (rv != SECSuccess) { @@ -8328,7 +7903,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) /* We might be starting session renegotiation in which case we should * clear previous state. */ - ssl3_ResetExtensionData(&ss->xtnData); + ssl3_ResetExtensionData(&ss->xtnData, ss); ss->statelessResume = PR_FALSE; if (IS_DTLS(ss)) { @@ -8349,7 +7924,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) /* Grab the client random data. */ rv = ssl3_ConsumeHandshake( - ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); + ss, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed */ } @@ -8366,6 +7941,9 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) if (rv != SECSuccess) { goto loser; /* malformed */ } + if (cookieBytes.len != 0) { + goto loser; /* We never send cookies in DTLS 1.2. */ + } } /* Grab the list of cipher suites. */ @@ -8389,14 +7967,15 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) if (length) { /* Get length of hello extensions */ - PRUint32 extension_length; - rv = ssl3_ConsumeHandshakeNumber(ss, &extension_length, 2, &b, &length); + PRUint32 extensionLength; + rv = ssl3_ConsumeHandshakeNumber(ss, &extensionLength, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* alert already sent */ } - if (extension_length != length) { - ssl3_DecodeError(ss); /* send alert */ - goto loser; + if (extensionLength != length) { + errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; + desc = decode_error; + goto alert_loser; } rv = ssl3_ParseExtensions(ss, &b, &length); @@ -8427,17 +8006,35 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) goto alert_loser; } } + + if (ss->firstHsDone && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + desc = unexpected_message; + errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; + goto alert_loser; + } + isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version; + /* Update the write spec to match the selected version. */ + if (!ss->firstHsDone) { + ssl_GetSpecWriteLock(ss); + ssl_SetSpecVersions(ss, ss->ssl3.cwSpec); + ssl_ReleaseSpecWriteLock(ss); + } - /* You can't resume TLS 1.3 like this. */ - if (isTLS13 && sidBytes.len) { - goto alert_loser; + if (isTLS13 && sidBytes.len > 0 && !IS_DTLS(ss)) { + SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE); + rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.fakeSid, &sidBytes); + if (rv != SECSuccess) { + desc = internal_error; + errCode = PORT_GetError(); + goto alert_loser; + } } /* Generate the Server Random now so it is available * when we process the ClientKeyShare in TLS 1.3 */ - rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random); + rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random); if (rv != SECSuccess) { errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE; goto loser; @@ -8463,8 +8060,8 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) * we ship the final version of TLS 1.3. Bug 1306672. */ if (ss->vrange.max > ss->version) { - unsigned char *downgrade_sentinel = - ss->ssl3.hs.server_random.rand + + PRUint8 *downgrade_sentinel = + ss->ssl3.hs.server_random + SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); switch (ss->vrange.max) { @@ -8485,8 +8082,25 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) } #endif + /* If there is a cookie, then this is a second ClientHello (TLS 1.3). */ + if (ssl3_FindExtension(ss, ssl_tls13_cookie_xtn)) { + ss->ssl3.hs.helloRetry = PR_TRUE; + } + + if (ss->ssl3.hs.receivedCcs) { + /* This is only valid if we sent HelloRetryRequest, so we should have + * negotiated TLS 1.3 and there should be a cookie extension. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 || + !ss->ssl3.hs.helloRetry) { + desc = unexpected_message; + errCode = SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER; + goto alert_loser; + } + } + /* Now parse the rest of the extensions. */ - rv = ssl3_HandleParsedExtensions(ss, client_hello); + rv = ssl3_HandleParsedExtensions(ss, ssl_hs_client_hello); + ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); if (rv != SECSuccess) { goto loser; /* malformed */ } @@ -8509,6 +8123,12 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) if (comps.len != 1 || comps.data[0] != ssl_compression_null) { goto alert_loser; } + } else { + /* Other versions need to include null somewhere. */ + if (comps.len < 1 || + !memchr(comps.data, ssl_compression_null, comps.len)) { + goto alert_loser; + } } if (!ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { @@ -8521,34 +8141,30 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { PRUint8 *b2 = (PRUint8 *)emptyRIext; PRUint32 L2 = sizeof emptyRIext; - (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello); + (void)ssl3_HandleExtensions(ss, &b2, &L2, ssl_hs_client_hello); break; } } } - /* This is a second check for TLS 1.3 and re-handshake to stop us - * from re-handshake up to TLS 1.3, so it happens after version - * negotiation. */ - if (ss->firstHsDone && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - desc = unexpected_message; - errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; - goto alert_loser; - } - if (ss->firstHsDone && - (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN || - ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) && - !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { - desc = no_renegotiation; - level = alert_warning; - errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; - goto alert_loser; - } - if ((ss->opt.requireSafeNegotiation || - (ss->firstHsDone && ss->peerRequestedProtection)) && - !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { - desc = handshake_failure; - errCode = SSL_ERROR_UNSAFE_NEGOTIATION; - goto alert_loser; + + /* The check for renegotiation in TLS 1.3 is earlier. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + if (ss->firstHsDone && + (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN || + ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) && + !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { + desc = no_renegotiation; + level = alert_warning; + errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED; + goto alert_loser; + } + if ((ss->opt.requireSafeNegotiation || + (ss->firstHsDone && ss->peerRequestedProtection)) && + !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) { + desc = handshake_failure; + errCode = SSL_ERROR_UNSAFE_NEGOTIATION; + goto alert_loser; + } } /* We do stateful resumes only if we are in TLS < 1.3 and @@ -8621,21 +8237,14 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) if (IS_DTLS(ss)) { ssl3_DisableNonDTLSSuites(ss); + dtls_ReceivedFirstMessageInFlight(ss); } -#ifdef PARANOID - /* Look for a matching cipher suite. */ - j = ssl3_config_match_init(ss); - if (j <= 0) { /* no ciphers are working/supported by PK11 */ - errCode = PORT_GetError(); /* error code is already set. */ - goto alert_loser; - } -#endif - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - rv = tls13_HandleClientHelloPart2(ss, &suites, sid); + rv = tls13_HandleClientHelloPart2(ss, &suites, sid, savedMsg, savedLen); } else { - rv = ssl3_HandleClientHelloPart2(ss, &suites, &comps, sid); + rv = ssl3_HandleClientHelloPart2(ss, &suites, sid, + savedMsg, savedLen); } if (rv != SECSuccess) { errCode = PORT_GetError(); @@ -8652,22 +8261,60 @@ loser: } static SECStatus +ssl3_UnwrapMasterSecretServer(sslSocket *ss, sslSessionID *sid, PK11SymKey **ms) +{ + PK11SymKey *wrapKey; + CK_FLAGS keyFlags = 0; + SECItem wrappedMS = { + siBuffer, + sid->u.ssl3.keys.wrapped_master_secret, + sid->u.ssl3.keys.wrapped_master_secret_len + }; + + wrapKey = ssl3_GetWrappingKey(ss, NULL, sid->u.ssl3.masterWrapMech, + ss->pkcs11PinArg); + if (!wrapKey) { + return SECFailure; + } + + if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ + keyFlags = CKF_SIGN | CKF_VERIFY; + } + + /* unwrap the master secret. */ + *ms = PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, + NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, + CKA_DERIVE, SSL3_MASTER_SECRET_LENGTH, keyFlags); + PK11_FreeSymKey(wrapKey); + if (!*ms) { + return SECFailure; + } + return SECSuccess; +} + +static SECStatus ssl3_HandleClientHelloPart2(sslSocket *ss, SECItem *suites, - SECItem *comps, - sslSessionID *sid) + sslSessionID *sid, + const PRUint8 *msg, + unsigned int len) { - PRBool haveSpecWriteLock = PR_FALSE; PRBool haveXmitBufLock = PR_FALSE; int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; SSL3AlertDescription desc = illegal_parameter; SECStatus rv; unsigned int i; - int j; + unsigned int j; - /* If we already have a session for this client, be sure to pick the - ** same cipher suite and compression method we picked before. - ** This is not a loop, despite appearances. + rv = ssl_HashHandshakeMessage(ss, ssl_hs_client_hello, msg, len); + if (rv != SECSuccess) { + errCode = SEC_ERROR_LIBRARY_FAILURE; + desc = internal_error; + goto alert_loser; + } + + /* If we already have a session for this client, be sure to pick the same + ** cipher suite we picked before. This is not a loop, despite appearances. */ if (sid) do { @@ -8676,18 +8323,6 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, SSLVersionRange vrange = { ss->version, ss->version }; #endif - /* Check that the cached compression method is still enabled. */ - if (!ssl_CompressionEnabled(ss, sid->u.ssl3.compression)) - break; - - /* Check that the cached compression method is in the client's list */ - for (i = 0; i < comps->len; i++) { - if (comps->data[i] == sid->u.ssl3.compression) - break; - } - if (i == comps->len) - break; - suite = ss->cipherSuites; /* Find the entry for the cipher suite used in the cached session. */ for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) { @@ -8695,7 +8330,7 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, break; } PORT_Assert(j > 0); - if (j <= 0) + if (j == 0) break; #ifdef PARANOID /* Double check that the cached cipher suite is still enabled, @@ -8714,17 +8349,15 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, for (i = 0; i + 1 < suites->len; i += 2) { PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1]; if (suite_i == suite->cipher_suite) { - rv = ssl3_SetCipherSuite(ss, suite_i, PR_TRUE); + ss->ssl3.hs.cipher_suite = suite_i; + rv = ssl3_SetupCipherSuite(ss, PR_TRUE); if (rv != SECSuccess) { desc = internal_error; errCode = PORT_GetError(); goto alert_loser; } - /* Use the cached compression method. */ - ss->ssl3.hs.compression = - sid->u.ssl3.compression; - goto compression_found; + goto cipher_found; } } } while (0); @@ -8732,8 +8365,7 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, #ifndef PARANOID /* Look for a matching cipher suite. */ - j = ssl3_config_match_init(ss); - if (j <= 0) { /* no ciphers are working/supported by PK11 */ + if (ssl3_config_match_init(ss) == 0) { desc = internal_error; errCode = PORT_GetError(); /* error code is already set. */ goto alert_loser; @@ -8747,25 +8379,8 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, goto alert_loser; } - /* Select a compression algorithm. */ - for (i = 0; i < comps->len; i++) { - SSLCompressionMethod method = (SSLCompressionMethod)comps->data[i]; - if (!ssl_CompressionEnabled(ss, method)) - continue; - for (j = 0; j < ssl_compression_method_count; j++) { - if (method == ssl_compression_methods[j]) { - ss->ssl3.hs.compression = ssl_compression_methods[j]; - goto compression_found; - } - } - } - errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP; - /* null compression must be supported */ - goto alert_loser; - -compression_found: +cipher_found: suites->data = NULL; - comps->data = NULL; /* If there are any failures while processing the old sid, * we don't consider them to be errors. Instead, We just behave @@ -8775,12 +8390,10 @@ compression_found: */ if (sid != NULL) do { - ssl3CipherSpec *pwSpec; - SECItem wrappedMS; /* wrapped key */ + PK11SymKey *masterSecret; if (sid->version != ss->version || - sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite || - sid->u.ssl3.compression != ss->ssl3.hs.compression) { + sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite) { break; /* not an error */ } @@ -8829,54 +8442,13 @@ compression_found: } ss->sec.ci.sid = NULL; } - /* we need to resurrect the master secret.... */ - - ssl_GetSpecWriteLock(ss); - haveSpecWriteLock = PR_TRUE; - pwSpec = ss->ssl3.pwSpec; - if (sid->u.ssl3.keys.msIsWrapped) { - PK11SymKey *wrapKey; /* wrapping key */ - CK_FLAGS keyFlags = 0; - - wrapKey = ssl3_GetWrappingKey(ss, NULL, - sid->u.ssl3.masterWrapMech, - ss->pkcs11PinArg); - if (!wrapKey) { - /* we have a SID cache entry, but no wrapping key for it??? */ - break; - } - - if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - keyFlags = CKF_SIGN | CKF_VERIFY; - } - - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - /* unwrap the master secret. */ - pwSpec->master_secret = - PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, - NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, - CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); - PK11_FreeSymKey(wrapKey); - if (pwSpec->master_secret == NULL) { - break; /* not an error */ - } - } else { - /* need to import the raw master secret to session object */ - PK11SlotInfo *slot; - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - slot = PK11_GetInternalSlot(); - pwSpec->master_secret = - PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, - PK11_OriginUnwrap, CKA_ENCRYPT, &wrappedMS, - NULL); - PK11_FreeSlot(slot); - if (pwSpec->master_secret == NULL) { - break; /* not an error */ - } + /* we need to resurrect the master secret.... */ + rv = ssl3_UnwrapMasterSecretServer(ss, sid, &masterSecret); + if (rv != SECSuccess) { + break; /* not an error */ } + ss->sec.ci.sid = sid; if (sid->peerCert != NULL) { ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); @@ -8884,8 +8456,6 @@ compression_found: /* * Old SID passed all tests, so resume this old session. - * - * XXX make sure compression still matches */ SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_hits); if (ss->statelessResume) @@ -8896,6 +8466,8 @@ compression_found: ss->sec.authKeyBits = sid->authKeyBits; ss->sec.keaType = sid->keaType; ss->sec.keaKeyBits = sid->keaKeyBits; + ss->sec.originalKeaGroup = ssl_LookupNamedGroup(sid->keaGroup); + ss->sec.signatureScheme = sid->sigScheme; ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert); @@ -8930,13 +8502,8 @@ compression_found: goto loser; } - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - haveSpecWriteLock = PR_FALSE; - } - - /* NULL value for PMS because we are re-using the old MS */ - rv = ssl3_InitPendingCipherSpec(ss, NULL); + /* We are re-using the old MS, so no need to derive again. */ + rv = ssl3_InitPendingCipherSpecs(ss, masterSecret, PR_FALSE); if (rv != SECSuccess) { errCode = PORT_GetError(); goto loser; @@ -8961,12 +8528,8 @@ compression_found: return SECSuccess; } while (0); - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - haveSpecWriteLock = PR_FALSE; - } - if (sid) { /* we had a sid, but it's no longer valid, free it */ + ss->statelessResume = PR_FALSE; SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok); ss->sec.uncache(sid); ssl_FreeSID(sid); @@ -8985,9 +8548,8 @@ compression_found: */ if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) && ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def)) { - ssl3_RegisterExtensionSender(ss, &ss->xtnData, - ssl_session_ticket_xtn, - ssl3_SendSessionTicketXtn); + ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_session_ticket_xtn, + ssl_SendEmptyExtension); } rv = ssl3_ServerCallSNICallback(ss); @@ -9031,10 +8593,6 @@ compression_found: return SECSuccess; alert_loser: - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - haveSpecWriteLock = PR_FALSE; - } (void)SSL3_SendAlert(ss, alert_fatal, desc); /* FALLTHRU */ loser: @@ -9043,10 +8601,6 @@ loser: ssl_FreeSID(sid); } - if (haveSpecWriteLock) { - ssl_ReleaseSpecWriteLock(ss); - } - if (haveXmitBufLock) { ssl_ReleaseXmitBufLock(ss); } @@ -9060,7 +8614,7 @@ loser: * in asking to use the V3 handshake. */ SECStatus -ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, +ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int length, PRUint8 padding) { sslSessionID *sid = NULL; @@ -9068,11 +8622,11 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, unsigned char *random; SSL3ProtocolVersion version; SECStatus rv; - int i; - int j; - int sid_length; - int suite_length; - int rand_length; + unsigned int i; + unsigned int j; + unsigned int sid_length; + unsigned int suite_length; + unsigned int rand_length; int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; SSL3AlertDescription desc = handshake_failure; unsigned int total = SSL_HL_CLIENT_HELLO_HBYTES; @@ -9083,14 +8637,11 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, ssl_GetSSL3HandshakeLock(ss); - ssl3_ResetExtensionData(&ss->xtnData); - version = (buffer[1] << 8) | buffer[2]; if (version < SSL_LIBRARY_VERSION_3_0) { goto loser; } - ssl3_InitState(ss); ssl3_RestartHandshakeHashes(ss); if (ss->ssl3.hs.ws != wait_client_hello) { @@ -9122,6 +8673,11 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, goto alert_loser; } ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version; + if (!ss->firstHsDone) { + ssl_GetSpecWriteLock(ss); + ssl_SetSpecVersions(ss, ss->ssl3.cwSpec); + ssl_ReleaseSpecWriteLock(ss); + } /* if we get a non-zero SID, just ignore it. */ if (length != total) { @@ -9144,15 +8700,14 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, PORT_Assert(SSL_MAX_CHALLENGE_BYTES == SSL3_RANDOM_LENGTH); - PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH); - PORT_Memcpy( - &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length], - random, rand_length); + PORT_Memset(ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH); + PORT_Memcpy(&ss->ssl3.hs.client_random[SSL3_RANDOM_LENGTH - rand_length], + random, rand_length); - PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0], + PRINT_BUF(60, (ss, "client random:", ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH)); - i = ssl3_config_match_init(ss); - if (i <= 0) { + + if (ssl3_config_match_init(ss) == 0) { errCode = PORT_GetError(); /* error code is already set. */ goto alert_loser; } @@ -9161,8 +8716,6 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, ** ** NOTE: This suite selection algorithm should be the same as the one in ** ssl3_HandleClientHello(). - ** - ** See the comments about export cipher suites in ssl3_HandleClientHello(). */ for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; @@ -9173,7 +8726,8 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, for (i = 0; i + 2 < suite_length; i += 3) { PRUint32 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2]; if (suite_i == suite->cipher_suite) { - rv = ssl3_SetCipherSuite(ss, suite_i, PR_TRUE); + ss->ssl3.hs.cipher_suite = suite_i; + rv = ssl3_SetupCipherSuite(ss, PR_TRUE); if (rv != SECSuccess) { desc = internal_error; errCode = PORT_GetError(); @@ -9209,7 +8763,7 @@ suite_found: if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { PRUint8 *b2 = (PRUint8 *)emptyRIext; PRUint32 L2 = sizeof emptyRIext; - (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello); + (void)ssl3_HandleExtensions(ss, &b2, &L2, ssl_hs_client_hello); break; } } @@ -9221,8 +8775,6 @@ suite_found: goto alert_loser; } - ss->ssl3.hs.compression = ssl_compression_null; - rv = ssl3_SelectServerCert(ss); if (rv != SECSuccess) { errCode = PORT_GetError(); @@ -9266,6 +8818,64 @@ loser: return SECFailure; } +SECStatus +ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry, + const sslBuffer *extensionBuf, sslBuffer *messageBuf) +{ + SECStatus rv; + 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); + } + + rv = sslBuffer_AppendNumber(messageBuf, version, 2); + if (rv != SECSuccess) { + return SECFailure; + } + /* Random already generated in ssl3_HandleClientHello */ + rv = sslBuffer_Append(messageBuf, helloRetry ? ssl_hello_retry_random : ss->ssl3.hs.server_random, + SSL3_RANDOM_LENGTH); + if (rv != SECSuccess) { + return SECFailure; + } + + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + if (sid) { + rv = sslBuffer_AppendVariable(messageBuf, sid->u.ssl3.sessionID, + sid->u.ssl3.sessionIDLength, 1); + } else { + rv = sslBuffer_AppendNumber(messageBuf, 0, 1); + } + } else { + rv = sslBuffer_AppendVariable(messageBuf, ss->ssl3.hs.fakeSid.data, + ss->ssl3.hs.fakeSid.len, 1); + } + if (rv != SECSuccess) { + return SECFailure; + } + + rv = sslBuffer_AppendNumber(messageBuf, ss->ssl3.hs.cipher_suite, 2); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(messageBuf, ssl_compression_null, 1); + if (rv != SECSuccess) { + return SECFailure; + } + if (SSL_BUFFER_LEN(extensionBuf)) { + rv = sslBuffer_AppendBufferVariable(messageBuf, extensionBuf, 2); + if (rv != SECSuccess) { + return SECFailure; + } + } + + return SECSuccess; +} + /* The negotiated version number has been already placed in ss->version. ** ** Called from: ssl3_HandleClientHello (resuming session), @@ -9275,12 +8885,9 @@ loser: SECStatus ssl3_SendServerHello(sslSocket *ss) { - sslSessionID *sid; SECStatus rv; - PRUint32 maxBytes = 65535; - PRUint32 length; - PRInt32 extensions_len = 0; - SSL3ProtocolVersion version; + sslBuffer extensionBuf = SSL_BUFFER_EMPTY; + sslBuffer messageBuf = SSL_BUFFER_EMPTY; SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(), ss->fd)); @@ -9294,94 +8901,43 @@ ssl3_SendServerHello(sslSocket *ss) return SECFailure; } - sid = ss->sec.ci.sid; - - extensions_len = ssl3_CallHelloExtensionSenders( - ss, PR_FALSE, maxBytes, &ss->xtnData.serverHelloSenders[0]); - if (extensions_len > 0) - extensions_len += 2; /* Add sizeof total extension length */ - - /* TLS 1.3 doesn't use the session_id or compression_method - * fields in the ServerHello. */ - length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH; - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - length += 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength); - } - length += sizeof(ssl3CipherSuite); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - length += 1; /* Compression */ - } - length += extensions_len; - - rv = ssl3_AppendHandshakeHeader(ss, server_hello, length); + rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_server_hello); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - - if (IS_DTLS(ss) && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - version = dtls_TLSVersionToDTLSVersion(ss->version); - } else { - version = tls13_EncodeDraftVersion(ss->version); + goto loser; } - rv = ssl3_AppendHandshakeNumber(ss, version, 2); + rv = ssl_ConstructServerHello(ss, PR_FALSE, &extensionBuf, &messageBuf); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - /* Random already generated in ssl3_HandleClientHello */ - rv = ssl3_AppendHandshake( - ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - if (sid) { - rv = ssl3_AppendHandshakeVariable( - ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1); - } else { - rv = ssl3_AppendHandshakeNumber(ss, 0, 1); - } - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } + goto loser; } - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello, + SSL_BUFFER_LEN(&messageBuf)); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } + goto loser; /* err set by AppendHandshake. */ } - if (extensions_len) { - PRInt32 sent_len; - extensions_len -= 2; - rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); - if (rv != SECSuccess) - return rv; /* err set by ssl3_AppendHandshakeNumber */ - sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len, - &ss->xtnData.serverHelloSenders[0]); - PORT_Assert(sent_len == extensions_len); - if (sent_len != extensions_len) { - if (sent_len >= 0) - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } + rv = ssl3_AppendHandshake(ss, SSL_BUFFER_BASE(&messageBuf), + SSL_BUFFER_LEN(&messageBuf)); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ } if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_SetupPendingCipherSpec(ss); + rv = ssl3_SetupBothPendingCipherSpecs(ss); if (rv != SECSuccess) { - return rv; /* err set by ssl3_SetupPendingCipherSpec */ + goto loser; /* err set */ } } + sslBuffer_Clear(&extensionBuf); + sslBuffer_Clear(&messageBuf); return SECSuccess; + +loser: + sslBuffer_Clear(&extensionBuf); + sslBuffer_Clear(&messageBuf); + return SECFailure; } SECStatus @@ -9438,6 +8994,8 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) SECKEYPublicKey *pubKey; SECKEYPrivateKey *certPrivateKey; const sslNamedGroupDef *groupDef; + /* Do this on the heap, this could be over 2k long. */ + sslBuffer dhBuf = SSL_BUFFER_EMPTY; if (kea_def->kea != kea_dhe_dss && kea_def->kea != kea_dhe_rsa) { /* TODO: Support DH_anon. It might be sufficient to drop the signature. @@ -9461,7 +9019,7 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) } PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs); - if (ss->ssl3.pwSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) { hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme); } else { /* Use ssl_hash_none to represent the MD5+SHA1 combo. */ @@ -9493,11 +9051,11 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) 2 + pubKey->u.dh.prime.len + 2 + signed_hash.len; - if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { length += 2; } - rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } @@ -9514,12 +9072,16 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) goto loser; /* err set by AppendHandshake. */ } - rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_TRUE); + rv = ssl_AppendPaddedDHKeyShare(&dhBuf, pubKey, PR_TRUE); + if (rv != SECSuccess) { + goto loser; /* err set by AppendPaddedDHKeyShare. */ + } + rv = ssl3_AppendBufferToHandshake(ss, &dhBuf); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } - if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.signatureScheme, 2); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ @@ -9531,12 +9093,15 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } + + sslBuffer_Clear(&dhBuf); PORT_Free(signed_hash.data); return SECSuccess; loser: if (signed_hash.data) PORT_Free(signed_hash.data); + sslBuffer_Clear(&dhBuf); return SECFailure; } @@ -9571,14 +9136,15 @@ ssl3_SendServerKeyExchange(sslSocket *ss) } SECStatus -ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 *len) +ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf) { + unsigned int lengthOffset; unsigned int i; - PRUint8 *p = buf; + PRBool found = PR_FALSE; + SECStatus rv; - PORT_Assert(maxLen >= ss->ssl3.signatureSchemeCount * 2); - if (maxLen < ss->ssl3.signatureSchemeCount * 2) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = sslBuffer_Skip(buf, 2, &lengthOffset); + if (rv != SECSuccess) { return SECFailure; } @@ -9596,16 +9162,21 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) || (policy & NSS_USE_ALG_IN_SSL_KX)) { - p = ssl_EncodeUintX((PRUint32)ss->ssl3.signatureSchemes[i], 2, p); + rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2); + if (rv != SECSuccess) { + return SECFailure; + } + + found = PR_TRUE; } } - if (p == buf) { + if (!found) { PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM); return SECFailure; } - *len = p - buf; - return SECSuccess; + + return sslBuffer_InsertLength(buf, lengthOffset, 2); } static SECStatus @@ -9614,15 +9185,15 @@ ssl3_SendCertificateRequest(sslSocket *ss) PRBool isTLS12; const PRUint8 *certTypes; SECStatus rv; - int length; - SECItem *names; + PRUint32 length; + const SECItem *names; unsigned int calen; unsigned int nnames; - SECItem *name; - int i; + const SECItem *name; + unsigned int i; int certTypesLength; - PRUint8 sigAlgs[MAX_SIGNATURE_SCHEMES * 2]; - unsigned int sigAlgsLength = 0; + PRUint8 sigAlgs[2 + MAX_SIGNATURE_SCHEMES * 2]; + sslBuffer sigAlgsBuf = SSL_BUFFER(sigAlgs); SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake", SSL_GETPID(), ss->fd)); @@ -9630,7 +9201,7 @@ ssl3_SendCertificateRequest(sslSocket *ss) PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames); if (rv != SECSuccess) { @@ -9641,14 +9212,14 @@ ssl3_SendCertificateRequest(sslSocket *ss) length = 1 + certTypesLength + 2 + calen; if (isTLS12) { - rv = ssl3_EncodeSigAlgs(ss, sigAlgs, sizeof(sigAlgs), &sigAlgsLength); + rv = ssl3_EncodeSigAlgs(ss, &sigAlgsBuf); if (rv != SECSuccess) { return rv; } - length += 2 + sigAlgsLength; + length += SSL_BUFFER_LEN(&sigAlgsBuf); } - rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request, length); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -9657,7 +9228,8 @@ ssl3_SendCertificateRequest(sslSocket *ss) return rv; /* err set by AppendHandshake. */ } if (isTLS12) { - rv = ssl3_AppendHandshakeVariable(ss, sigAlgs, sigAlgsLength, 2); + rv = ssl3_AppendHandshake(ss, SSL_BUFFER_BASE(&sigAlgsBuf), + SSL_BUFFER_LEN(&sigAlgsBuf)); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -9687,7 +9259,7 @@ ssl3_SendServerHelloDone(sslSocket *ss) PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - rv = ssl3_AppendHandshakeHeader(ss, server_hello_done, 0); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello_done, 0); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -9703,8 +9275,7 @@ ssl3_SendServerHelloDone(sslSocket *ss) * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, - SSL3Hashes *hashes) +ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECItem signed_hash = { siBuffer, NULL, 0 }; SECStatus rv; @@ -9712,9 +9283,9 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL3AlertDescription desc = handshake_failure; PRBool isTLS; SSLSignatureScheme sigScheme; - SSLHashType hashAlg; - SSL3Hashes localHashes; - SSL3Hashes *hashesForVerify = NULL; + SSL3Hashes hashes; + const PRUint8 *savedMsg = b; + const PRUint32 savedLen = length; SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake", SSL_GETPID(), ss->fd)); @@ -9730,14 +9301,8 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, /* TLS 1.3 is handled by tls13_HandleCertificateVerify */ PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2); - if (!hashes) { - PORT_Assert(0); - desc = internal_error; - errCode = SEC_ERROR_LIBRARY_FAILURE; - goto alert_loser; - } - - if (ss->ssl3.hs.hashType == handshake_hash_record) { + if (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) { + PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_record); rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); if (rv != SECSuccess) { goto loser; /* malformed or unsupported. */ @@ -9750,25 +9315,20 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, goto alert_loser; } - hashAlg = ssl_SignatureSchemeToHashType(sigScheme); - - /* Read from the message buffer, but we need to use only up to the end - * of the previous handshake message. The length of the transcript up to - * that point is saved in |hashes->u.transcriptLen|. */ rv = ssl3_ComputeHandshakeHash(ss->ssl3.hs.messages.buf, - hashes->u.transcriptLen, - hashAlg, &localHashes); - - if (rv == SECSuccess) { - hashesForVerify = &localHashes; - } else { - errCode = SSL_ERROR_DIGEST_FAILURE; - desc = decrypt_error; - goto alert_loser; - } + ss->ssl3.hs.messages.len, + ssl_SignatureSchemeToHashType(sigScheme), + &hashes); } else { - hashesForVerify = hashes; + PORT_Assert(ss->ssl3.hs.hashType != handshake_hash_record); sigScheme = ssl_sig_none; + rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.prSpec, &hashes, 0); + } + + if (rv != SECSuccess) { + errCode = SSL_ERROR_DIGEST_FAILURE; + desc = decrypt_error; + goto alert_loser; } rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length); @@ -9779,7 +9339,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); /* XXX verify that the key & kea match */ - rv = ssl3_VerifySignedHashes(ss, sigScheme, hashesForVerify, &signed_hash); + rv = ssl3_VerifySignedHashes(ss, sigScheme, &hashes, &signed_hash); if (rv != SECSuccess) { errCode = PORT_GetError(); desc = isTLS ? decrypt_error : handshake_failure; @@ -9792,6 +9352,14 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, desc = isTLS ? decode_error : illegal_parameter; goto alert_loser; /* malformed */ } + + rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, + savedMsg, savedLen); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return rv; + } + ss->ssl3.hs.ws = wait_change_cipher; return SECSuccess; @@ -9832,9 +9400,9 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, ** slot already hold the SpecWriteLock. */ PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); + PORT_Assert(ss->ssl3.prSpec->epoch == ss->ssl3.pwSpec->epoch); - calg = spec->cipher_def->calg; + calg = spec->cipherDef->calg; /* First get an appropriate slot. */ mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN; @@ -9902,7 +9470,7 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); + PORT_Assert(ss->ssl3.prSpec->epoch == ss->ssl3.pwSpec->epoch); enc_pms.data = b; enc_pms.len = length; @@ -9999,7 +9567,7 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, } /* This step will derive the MS from the PMS, among other things. */ - rv = ssl3_InitPendingCipherSpec(ss, currentPms); + rv = ssl3_InitPendingCipherSpecs(ss, currentPms, PR_TRUE); PK11_FreeSymKey(currentPms); if (rv != SECSuccess) { @@ -10064,7 +9632,7 @@ ssl3_HandleDHClientKeyExchange(sslSocket *ss, return SECFailure; } - rv = ssl3_InitPendingCipherSpec(ss, pms); + rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); PK11_FreeSymKey(pms); ssl_FreeEphemeralKeyPairs(ss); return rv; @@ -10163,13 +9731,13 @@ ssl3_SendEmptyCertificate(sslSocket *ss) const SECItem *context; if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - PORT_Assert(ss->ssl3.hs.certificateRequest); - context = &ss->ssl3.hs.certificateRequest->context; + PORT_Assert(ss->ssl3.hs.clientCertRequested); + context = &ss->xtnData.certReqContext; len = context->len + 1; isTLS13 = PR_TRUE; } - rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate, len + 3); if (rv != SECSuccess) { return rv; } @@ -10195,13 +9763,14 @@ ssl3_SendNewSessionTicket(sslSocket *ss) SECStatus rv; NewSessionTicket nticket = { 0 }; - rv = ssl3_EncodeSessionTicket(ss, &nticket, &ticket); + rv = ssl3_EncodeSessionTicket(ss, &nticket, NULL, 0, + ss->ssl3.pwSpec->masterSecret, &ticket); if (rv != SECSuccess) goto loser; /* Serialize the handshake message. Length = * lifetime (4) + ticket length (2) + ticket. */ - rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_new_session_ticket, 4 + 2 + ticket.len); if (rv != SECSuccess) goto loser; @@ -10251,7 +9820,7 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) * until it has verified the server's Finished message." See the comment in * ssl3_FinishHandshake for more details. */ - ss->ssl3.hs.newSessionTicket.received_timestamp = PR_Now(); + ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_TimeUsec(); if (length < 4) { (void)SSL3_SendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); @@ -10393,8 +9962,8 @@ ssl3_SendCertificate(sslSocket *ss) if (isTLS13) { contextLen = 1; /* Size of the context length */ if (!ss->sec.isServer) { - PORT_Assert(ss->ssl3.hs.certificateRequest); - context = ss->ssl3.hs.certificateRequest->context; + PORT_Assert(ss->ssl3.hs.clientCertRequested); + context = ss->xtnData.certReqContext; contextLen += context.len; } } @@ -10412,7 +9981,7 @@ ssl3_SendCertificate(sslSocket *ss) } } - rv = ssl3_AppendHandshakeHeader(ss, certificate, + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate, contextLen + certChainLen + 3); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ @@ -10487,7 +10056,7 @@ ssl3_SendCertificateStatus(sslSocket *ss) /* Use the array's first item only (single stapling) */ len = 1 + statusToSend->items[0].len + 3; - rv = ssl3_AppendHandshakeHeader(ss, certificate_status, len); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_status, len); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -10618,6 +10187,10 @@ ssl3_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECFailure; } + if (ss->sec.isServer) { + dtls_ReceivedFirstMessageInFlight(ss); + } + return ssl3_CompleteHandleCertificate(ss, b, length); } @@ -10837,7 +10410,8 @@ ssl3_AuthCertificate(sslSocket *ss) } if (pubKey) { KeyType pubKeyType; - PRInt32 minKey; + PRUint32 minKey; + PRInt32 optval; /* This partly fixes Bug 124230 and may cause problems for * callers which depend on the old (wrong) behavior. */ ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); @@ -10848,29 +10422,29 @@ ssl3_AuthCertificate(sslSocket *ss) case rsaPssKey: case rsaOaepKey: rv = - NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minKey); - if (rv != - SECSuccess) { - minKey = - SSL_RSA_MIN_MODULUS_BITS; + NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &optval); + if (rv == SECSuccess && optval > 0) { + minKey = (PRUint32)optval; + } else { + minKey = SSL_RSA_MIN_MODULUS_BITS; } break; case dsaKey: rv = - NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &minKey); - if (rv != - SECSuccess) { - minKey = - SSL_DSA_MIN_P_BITS; + NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &optval); + if (rv == SECSuccess && optval > 0) { + minKey = (PRUint32)optval; + } else { + minKey = SSL_DSA_MIN_P_BITS; } break; case dhKey: rv = - NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minKey); - if (rv != - SECSuccess) { - minKey = - SSL_DH_MIN_P_BITS; + NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &optval); + if (rv == SECSuccess && optval > 0) { + minKey = (PRUint32)optval; + } else { + minKey = SSL_DH_MIN_P_BITS; } break; default: @@ -11029,8 +10603,8 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec, PK11Context *prf_context; unsigned int retLen; - PORT_Assert(spec->master_secret); - if (!spec->master_secret) { + PORT_Assert(spec->masterSecret); + if (!spec->masterSecret) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } @@ -11045,7 +10619,7 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec, param.data = (unsigned char *)&tls_mac_params; param.len = sizeof(tls_mac_params); prf_context = PK11_CreateContextBySymKey(CKM_TLS_MAC, CKA_SIGN, - spec->master_secret, ¶m); + spec->masterSecret, ¶m); if (!prf_context) return SECFailure; @@ -11070,40 +10644,39 @@ ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec, const unsigned char *val, unsigned int valLen, unsigned char *out, unsigned int outLen) { - SECStatus rv = SECSuccess; + SECItem param = { siBuffer, NULL, 0 }; + CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL; + PK11Context *prf_context; + unsigned int retLen; + SECStatus rv; - if (spec->master_secret) { - SECItem param = { siBuffer, NULL, 0 }; - CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL; - PK11Context *prf_context; - unsigned int retLen; + if (!spec->masterSecret) { + PORT_Assert(spec->masterSecret); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } - if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { - /* Bug 1312976 non-SHA256 exporters are broken. */ - if (ssl3_GetPrfHashMechanism(ss) != CKM_SHA256) { - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; - } - prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, - spec->master_secret, ¶m); - if (!prf_context) + if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + /* Bug 1312976 non-SHA256 exporters are broken. */ + if (ssl3_GetPrfHashMechanism(ss) != CKM_SHA256) { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; + } + mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; + } + prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, + spec->masterSecret, ¶m); + if (!prf_context) + return SECFailure; - rv = PK11_DigestBegin(prf_context); - rv |= PK11_DigestOp(prf_context, (unsigned char *)label, labelLen); - rv |= PK11_DigestOp(prf_context, val, valLen); - rv |= PK11_DigestFinal(prf_context, out, &retLen, outLen); - PORT_Assert(rv != SECSuccess || retLen == outLen); + rv = PK11_DigestBegin(prf_context); + rv |= PK11_DigestOp(prf_context, (unsigned char *)label, labelLen); + rv |= PK11_DigestOp(prf_context, val, valLen); + rv |= PK11_DigestFinal(prf_context, out, &retLen, outLen); + PORT_Assert(rv != SECSuccess || retLen == outLen); - PK11_DestroyContext(prf_context, PR_TRUE); - } else { - PORT_Assert(spec->master_secret); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - } + PK11_DestroyContext(prf_context, PR_TRUE); return rv; } @@ -11127,7 +10700,7 @@ ssl3_SendNextProto(sslSocket *ss) padding_len = 32 - ((ss->xtnData.nextProto.len + 2) % 32); - rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len + 2 + padding_len); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_next_proto, ss->xtnData.nextProto.len + 2 + padding_len); if (rv != SECSuccess) { return rv; /* error code set by AppendHandshakeHeader */ } @@ -11143,40 +10716,44 @@ ssl3_SendNextProto(sslSocket *ss) return rv; } -/* called from ssl3_SendFinished +/* called from ssl3_SendFinished and tls13_DeriveSecret. * * This function is simply a debugging aid and therefore does not return a * SECStatus. */ -static void -ssl3_RecordKeyLog(sslSocket *ss) +void +ssl3_RecordKeyLog(sslSocket *ss, const char *label, PK11SymKey *secret) { #ifdef NSS_ALLOW_SSLKEYLOGFILE SECStatus rv; SECItem *keyData; - char buf[14 /* "CLIENT_RANDOM " */ + - SSL3_RANDOM_LENGTH * 2 /* client_random */ + - 1 /* " " */ + - 48 * 2 /* master secret */ + - 1 /* new line */]; - unsigned int j; + /* Longest label is "CLIENT_HANDSHAKE_TRAFFIC_SECRET", master secret is 48 + * bytes which happens to be the largest in TLS 1.3 as well (SHA384). + * Maximum line length: "CLIENT_HANDSHAKE_TRAFFIC_SECRET" (31) + " " (1) + + * client_random (32*2) + " " (1) + + * traffic_secret (48*2) + "\n" (1) = 194. */ + char buf[200]; + unsigned int offset, len; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); if (!ssl_keylog_iob) return; - rv = PK11_ExtractKeyValue(ss->ssl3.cwSpec->master_secret); + rv = PK11_ExtractKeyValue(secret); if (rv != SECSuccess) return; - ssl_GetSpecReadLock(ss); - /* keyData does not need to be freed. */ - keyData = PK11_GetKeyData(ss->ssl3.cwSpec->master_secret); - if (!keyData || !keyData->data || keyData->len != 48) { - ssl_ReleaseSpecReadLock(ss); + keyData = PK11_GetKeyData(secret); + if (!keyData || !keyData->data) + return; + + len = strlen(label) + 1 + /* label + space */ + SSL3_RANDOM_LENGTH * 2 + 1 + /* client random (hex) + space */ + keyData->len * 2 + 1; /* secret (hex) + newline */ + PORT_Assert(len <= sizeof(buf)); + if (len > sizeof(buf)) return; - } /* https://developer.mozilla.org/en/NSS_Key_Log_Format */ @@ -11184,23 +10761,22 @@ ssl3_RecordKeyLog(sslSocket *ss) * keylog, so we have to do everything in a single call to * fwrite. */ - memcpy(buf, "CLIENT_RANDOM ", 14); - j = 14; - hexEncode(buf + j, ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); - j += SSL3_RANDOM_LENGTH * 2; - buf[j++] = ' '; - hexEncode(buf + j, keyData->data, 48); - j += 48 * 2; - buf[j++] = '\n'; - - PORT_Assert(j == sizeof(buf)); - - ssl_ReleaseSpecReadLock(ss); - - if (fwrite(buf, sizeof(buf), 1, ssl_keylog_iob) != 1) - return; - fflush(ssl_keylog_iob); - return; + strcpy(buf, label); + offset = strlen(label); + buf[offset++] += ' '; + hexEncode(buf + offset, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); + offset += SSL3_RANDOM_LENGTH * 2; + buf[offset++] = ' '; + hexEncode(buf + offset, keyData->data, keyData->len); + offset += keyData->len * 2; + buf[offset++] = '\n'; + + PORT_Assert(offset == len); + + PZ_Lock(ssl_keylog_lock); + if (fwrite(buf, len, 1, ssl_keylog_iob) == 1) + fflush(ssl_keylog_iob); + PZ_Unlock(ssl_keylog_lock); #endif } @@ -11242,7 +10818,7 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) else ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished; ss->ssl3.hs.finishedBytes = sizeof tlsFinished; - rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof tlsFinished); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, sizeof tlsFinished); if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ rv = ssl3_AppendHandshake(ss, &tlsFinished, sizeof tlsFinished); @@ -11255,7 +10831,7 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s; PORT_Assert(hashes.len == sizeof hashes.u.s); ss->ssl3.hs.finishedBytes = sizeof hashes.u.s; - rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, sizeof hashes.u.s); if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s); @@ -11267,7 +10843,7 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) goto fail; /* error code set by ssl3_FlushHandshake */ } - ssl3_RecordKeyLog(ss); + ssl3_RecordKeyLog(ss, "CLIENT_RANDOM", ss->ssl3.cwSpec->masterSecret); return SECSuccess; @@ -11279,8 +10855,8 @@ fail: * Caller holds the Spec read lock. */ SECStatus -ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, - ssl3CipherSpec *spec) +ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid, + PK11SymKey *secret) { PK11SymKey *wrappingKey = NULL; PK11SlotInfo *symKeySlot; @@ -11289,7 +10865,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, PRBool isServer = ss->sec.isServer; CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; - symKeySlot = PK11_GetSlotFromKey(spec->master_secret); + symKeySlot = PK11_GetSlotFromKey(secret); if (!isServer) { int wrapKeyIndex; int incarnation; @@ -11350,7 +10926,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, wmsItem.data = sid->u.ssl3.keys.wrapped_master_secret; wmsItem.len = sizeof sid->u.ssl3.keys.wrapped_master_secret; rv = PK11_WrapSymKey(mechanism, NULL, wrappingKey, - spec->master_secret, &wmsItem); + secret, &wmsItem); /* rv is examined below. */ sid->u.ssl3.keys.wrapped_master_secret_len = wmsItem.len; PK11_FreeSymKey(wrappingKey); @@ -11363,13 +10939,13 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, - const SSL3Hashes *hashes) +ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) { sslSessionID *sid = ss->sec.ci.sid; SECStatus rv = SECSuccess; PRBool isServer = ss->sec.isServer; PRBool isTLS; + SSL3Hashes hashes; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -11383,13 +10959,23 @@ ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, return SECFailure; } - if (!hashes) { - PORT_Assert(0); - SSL3_SendAlert(ss, alert_fatal, internal_error); + if (!ss->sec.isServer || !ss->opt.requestCertificate) { + dtls_ReceivedFirstMessageInFlight(ss); + } + + rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.crSpec, &hashes, + isServer ? sender_client : sender_server); + if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } + rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return rv; + } + isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0); if (isTLS) { TLSFinished tlsFinished; @@ -11402,7 +10988,7 @@ ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, #endif } rv = ssl3_ComputeTLSFinished(ss, ss->ssl3.crSpec, !isServer, - hashes, &tlsFinished); + &hashes, &tlsFinished); if (!isServer) ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished; else @@ -11425,12 +11011,12 @@ ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, } if (!isServer) - ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s; + ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s; else - ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s; - PORT_Assert(hashes->len == sizeof hashes->u.s); - ss->ssl3.hs.finishedBytes = sizeof hashes->u.s; - if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) { + ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s; + PORT_Assert(hashes.len == sizeof hashes.u.s); + ss->ssl3.hs.finishedBytes = sizeof hashes.u.s; + if (0 != NSS_SecureMemcmp(&hashes.u.s, b, length)) { (void)ssl3_HandshakeFailure(ss); PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); return SECFailure; @@ -11500,7 +11086,7 @@ xmit_loser: } if (sid->cached == never_cached && !ss->opt.noCache) { - rv = ssl3_FillInCachedSID(ss, sid); + rv = ssl3_FillInCachedSID(ss, sid, ss->ssl3.crSpec->masterSecret); /* If the wrap failed, we don't cache the sid. * The connection continues normally however. @@ -11524,21 +11110,26 @@ xmit_loser: } SECStatus -ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) +ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret) { - SECStatus rv; + PORT_Assert(secret); /* fill in the sid */ sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite; - sid->u.ssl3.compression = ss->ssl3.hs.compression; sid->u.ssl3.policy = ss->ssl3.policy; sid->version = ss->version; sid->authType = ss->sec.authType; sid->authKeyBits = ss->sec.authKeyBits; sid->keaType = ss->sec.keaType; sid->keaKeyBits = ss->sec.keaKeyBits; - sid->lastAccessTime = sid->creationTime = ssl_Time(); - sid->expirationTime = sid->creationTime + ssl3_sid_timeout; + if (ss->sec.keaGroup) { + sid->keaGroup = ss->sec.keaGroup->name; + } else { + sid->keaGroup = ssl_grp_none; + } + sid->sigScheme = ss->sec.signatureScheme; + sid->lastAccessTime = sid->creationTime = ssl_TimeUsec(); + sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC; sid->localCert = CERT_DupCertificate(ss->sec.localCert); if (ss->sec.isServer) { sid->namedCurve = ss->sec.serverCert->namedCurve; @@ -11552,25 +11143,8 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) } } - ssl_GetSpecReadLock(ss); /*************************************/ - /* Copy the master secret (wrapped or unwrapped) into the sid */ - if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) { - sid->u.ssl3.keys.wrapped_master_secret_len = - ss->ssl3.crSpec->msItem.len; - memcpy(sid->u.ssl3.keys.wrapped_master_secret, - ss->ssl3.crSpec->msItem.data, ss->ssl3.crSpec->msItem.len); - sid->u.ssl3.masterValid = PR_TRUE; - sid->u.ssl3.keys.msIsWrapped = PR_FALSE; - rv = SECSuccess; - } else { - rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid, - ss->ssl3.crSpec); - sid->u.ssl3.keys.msIsWrapped = PR_TRUE; - } - ssl_ReleaseSpecReadLock(ss); /*************************************/ - - return rv; + return ssl3_CacheWrappedSecret(ss, ss->sec.ci.sid, secret); } /* The return type is SECStatus instead of void because this function needs @@ -11619,8 +11193,66 @@ ssl3_FinishHandshake(sslSocket *ss) return SECSuccess; } +SECStatus +ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type, + PRUint32 dtlsSeq, + const PRUint8 *b, PRUint32 length) +{ + PRUint8 hdr[4]; + PRUint8 dtlsData[8]; + SECStatus rv; + + PRINT_BUF(50, (ss, "Hash handshake message:", b, length)); + + hdr[0] = (PRUint8)type; + hdr[1] = (PRUint8)(length >> 16); + hdr[2] = (PRUint8)(length >> 8); + hdr[3] = (PRUint8)(length); + + rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4); + if (rv != SECSuccess) + return rv; /* err code already set. */ + + /* Extra data to simulate a complete DTLS handshake fragment */ + if (IS_DTLS(ss)) { + /* Sequence number */ + dtlsData[0] = MSB(dtlsSeq); + dtlsData[1] = LSB(dtlsSeq); + + /* Fragment offset */ + dtlsData[2] = 0; + dtlsData[3] = 0; + dtlsData[4] = 0; + + /* Fragment length */ + dtlsData[5] = (PRUint8)(length >> 16); + dtlsData[6] = (PRUint8)(length >> 8); + dtlsData[7] = (PRUint8)(length); + + rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)dtlsData, + sizeof(dtlsData)); + if (rv != SECSuccess) + return rv; /* err code already set. */ + } + + /* The message body */ + rv = ssl3_UpdateHandshakeHashes(ss, b, length); + if (rv != SECSuccess) + return rv; /* err code already set. */ + + return SECSuccess; +} + +SECStatus +ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type, + const PRUint8 *b, PRUint32 length) +{ + return ssl_HashHandshakeMessageInt(ss, type, ss->ssl3.hs.recvMessageSeq, + b, length); +} + /* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3 - * hanshake message. + * handshake message. * Caller must hold Handshake and RecvBuf locks. */ SECStatus @@ -11628,130 +11260,43 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, PRBool endOfRecord) { SECStatus rv = SECSuccess; - SSL3HandshakeType type = ss->ssl3.hs.msg_type; - SSL3Hashes hashes; /* computed hashes are put here. */ - SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */ - PRUint8 hdr[4]; - PRUint8 dtlsData[8]; - PRBool computeHashes = PR_FALSE; PRUint16 epoch; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - /* - * We have to compute the hashes before we update them with the - * current message. - */ - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - if ((type == finished) && (ss->ssl3.hs.ws == wait_finished)) { - computeHashes = PR_TRUE; - } else if ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify)) { - if (ss->ssl3.hs.hashType == handshake_hash_record) { - /* We cannot compute the hash yet. We must wait until we have - * decoded the certificate_verify message in - * ssl3_HandleCertificateVerify, which will tell us which - * hash function we must use. - * - * (ssl3_HandleCertificateVerify cannot simply look at the - * buffer length itself, because at the time we reach it, - * additional handshake messages will have been added to the - * buffer, e.g. the certificate_verify message itself.) - * - * Therefore, we use SSL3Hashes.u.transcriptLen to save how much - * data there is and read directly from ss->ssl3.hs.messages - * when calculating the hashes. - * - * ssl3_HandleCertificateVerify will detect - * hashType == handshake_hash_record - * and use that information to calculate the hash. - */ - hashes.u.transcriptLen = ss->ssl3.hs.messages.len; - hashesPtr = &hashes; - } else { - computeHashes = PR_TRUE; - } - } - } else { - if (type == certificate_verify) { - computeHashes = TLS13_IN_HS_STATE(ss, wait_cert_verify); - } else if (type == finished) { - computeHashes = - TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished); - } - } - ssl_GetSpecReadLock(ss); /************************************/ - if (computeHashes) { - SSL3Sender sender = (SSL3Sender)0; - ssl3CipherSpec *rSpec = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.crSpec - : ss->ssl3.prSpec; - - if (type == finished) { - sender = ss->sec.isServer ? sender_client : sender_server; - rSpec = ss->ssl3.crSpec; - } - rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender); - if (rv == SECSuccess) { - hashesPtr = &hashes; - } - } - ssl_ReleaseSpecReadLock(ss); /************************************/ - if (rv != SECSuccess) { - return rv; /* error code was set by ssl3_ComputeHandshakeHashes*/ - } SSL_TRC(30, ("%d: SSL3[%d]: handle handshake message: %s", SSL_GETPID(), ss->fd, ssl3_DecodeHandshakeType(ss->ssl3.hs.msg_type))); - hdr[0] = (PRUint8)ss->ssl3.hs.msg_type; - hdr[1] = (PRUint8)(length >> 16); - hdr[2] = (PRUint8)(length >> 8); - hdr[3] = (PRUint8)(length); - - /* Start new handshake hashes when we start a new handshake. Unless this is - * TLS 1.3 and we sent a HelloRetryRequest. */ - if (ss->ssl3.hs.msg_type == client_hello && !ss->ssl3.hs.helloRetry) { + /* Start new handshake hashes when we start a new handshake. */ + if (ss->ssl3.hs.msg_type == ssl_hs_client_hello) { ssl3_RestartHandshakeHashes(ss); } - /* We should not include hello_request and hello_verify_request messages - * in the handshake hashes */ - if ((ss->ssl3.hs.msg_type != hello_request) && - (ss->ssl3.hs.msg_type != hello_verify_request)) { - rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4); - if (rv != SECSuccess) - return rv; /* err code already set. */ - - /* Extra data to simulate a complete DTLS handshake fragment */ - if (IS_DTLS(ss)) { - /* Sequence number */ - dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq); - dtlsData[1] = LSB(ss->ssl3.hs.recvMessageSeq); - - /* Fragment offset */ - dtlsData[2] = 0; - dtlsData[3] = 0; - dtlsData[4] = 0; - - /* Fragment length */ - dtlsData[5] = (PRUint8)(length >> 16); - dtlsData[6] = (PRUint8)(length >> 8); - dtlsData[7] = (PRUint8)(length); + switch (ss->ssl3.hs.msg_type) { + case ssl_hs_hello_request: + case ssl_hs_hello_verify_request: + /* We don't include hello_request and hello_verify_request messages + * in the handshake hashes */ + break; - rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)dtlsData, - sizeof(dtlsData)); - if (rv != SECSuccess) - return rv; /* err code already set. */ - } + /* Defer hashing of these messages until the message handlers. */ + case ssl_hs_client_hello: + case ssl_hs_server_hello: + case ssl_hs_certificate_verify: + case ssl_hs_finished: + break; - /* The message body */ - rv = ssl3_UpdateHandshakeHashes(ss, b, length); - if (rv != SECSuccess) - return rv; /* err code already set. */ + default: + rv = ssl_HashHandshakeMessage(ss, ss->ssl3.hs.msg_type, b, length); + if (rv != SECSuccess) { + return SECFailure; + } } PORT_SetError(0); /* each message starts with no error. */ if (ss->ssl3.hs.ws == wait_certificate_status && - ss->ssl3.hs.msg_type != certificate_status) { + ss->ssl3.hs.msg_type != ssl_hs_certificate_status) { /* If we negotiated the certificate_status extension then we deferred * certificate validation until we get the CertificateStatus messsage. * But the CertificateStatus message is optional. If the server did @@ -11768,7 +11313,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, epoch = ss->ssl3.crSpec->epoch; switch (ss->ssl3.hs.msg_type) { - case client_hello: + case ssl_hs_client_hello: if (!ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO); @@ -11776,7 +11321,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, } rv = ssl3_HandleClientHello(ss, b, length); break; - case server_hello: + case ssl_hs_server_hello: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO); @@ -11786,10 +11331,9 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, break; default: if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length, hashesPtr); + rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length); } else { - rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length, - hashesPtr); + rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length); } break; } @@ -11811,13 +11355,13 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, - PRUint32 length, SSL3Hashes *hashesPtr) + PRUint32 length) { SECStatus rv; PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); switch (ss->ssl3.hs.msg_type) { - case hello_request: + case ssl_hs_hello_request: if (length != 0) { (void)ssl3_DecodeError(ss); PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST); @@ -11831,13 +11375,7 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, rv = ssl3_HandleHelloRequest(ss); break; - case hello_retry_request: - /* This arrives here because - as a client - we haven't received a - * final decision on the version from the server. */ - rv = tls13_HandleHelloRetryRequest(ss, b, length); - break; - - case hello_verify_request: + case ssl_hs_hello_verify_request: if (!IS_DTLS(ss) || ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST); @@ -11845,13 +11383,13 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = dtls_HandleHelloVerifyRequest(ss, b, length); break; - case certificate: + case ssl_hs_certificate: rv = ssl3_HandleCertificate(ss, b, length); break; - case certificate_status: + case ssl_hs_certificate_status: rv = ssl3_HandleCertificateStatus(ss, b, length); break; - case server_key_exchange: + case ssl_hs_server_key_exchange: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH); @@ -11859,7 +11397,7 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleServerKeyExchange(ss, b, length); break; - case certificate_request: + case ssl_hs_certificate_request: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST); @@ -11867,7 +11405,7 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleCertificateRequest(ss, b, length); break; - case server_hello_done: + case ssl_hs_server_hello_done: if (length != 0) { (void)ssl3_DecodeError(ss); PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_DONE); @@ -11880,15 +11418,15 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleServerHelloDone(ss); break; - case certificate_verify: + case ssl_hs_certificate_verify: if (!ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY); return SECFailure; } - rv = ssl3_HandleCertificateVerify(ss, b, length, hashesPtr); + rv = ssl3_HandleCertificateVerify(ss, b, length); break; - case client_key_exchange: + case ssl_hs_client_key_exchange: if (!ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH); @@ -11896,7 +11434,7 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleClientKeyExchange(ss, b, length); break; - case new_session_ticket: + case ssl_hs_new_session_ticket: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET); @@ -11904,8 +11442,8 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleNewSessionTicket(ss, b, length); break; - case finished: - rv = ssl3_HandleFinished(ss, b, length, hashesPtr); + case ssl_hs_finished: + rv = ssl3_HandleFinished(ss, b, length); break; default: (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); @@ -11946,7 +11484,7 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) t = *(buf->buf++); buf->len--; if (ss->ssl3.hs.header_bytes++ == 0) - ss->ssl3.hs.msg_type = (SSL3HandshakeType)t; + ss->ssl3.hs.msg_type = (SSLHandshakeType)t; else ss->ssl3.hs.msg_len = (ss->ssl3.hs.msg_len << 8) + t; if (ss->ssl3.hs.header_bytes < 4) @@ -12276,31 +11814,34 @@ ssl_CBCExtractMAC(sslBuffer *plaintext, * */ static SECStatus -ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, +ssl3_UnprotectRecord(sslSocket *ss, + ssl3CipherSpec *spec, + SSL3Ciphertext *cText, sslBuffer *plaintext, SSL3AlertDescription *alert) { - ssl3CipherSpec *crSpec = ss->ssl3.crSpec; - const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def; + const ssl3BulkCipherDef *cipher_def = spec->cipherDef; PRBool isTLS; unsigned int good; unsigned int ivLen = 0; SSL3ContentType rType; unsigned int minLength; unsigned int originalLen = 0; - unsigned char header[13]; - unsigned int headerLen; + PRUint8 headerBuf[13]; + sslBuffer header = SSL_BUFFER(headerBuf); PRUint8 hash[MAX_MAC_LENGTH]; PRUint8 givenHashBuf[MAX_MAC_LENGTH]; PRUint8 *givenHash; unsigned int hashBytes = MAX_MAC_LENGTH + 1; SECStatus rv; + PORT_Assert(spec->direction == CipherSpecRead); + good = ~0U; - minLength = crSpec->mac_size; + minLength = spec->macDef->mac_size; if (cipher_def->type == type_block) { /* CBC records have a padding length byte at the end. */ minLength++; - if (crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { + if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { /* With >= TLS 1.1, CBC records have an explicit IV. */ minLength += cipher_def->iv_size; } @@ -12315,7 +11856,7 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, } if (cipher_def->type == type_block && - crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { + spec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { /* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states * "The receiver decrypts the entire GenericBlockCipher structure and * then discards the first cipher block corresponding to the IV @@ -12338,8 +11879,8 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, * the block it doesn't matter. The decryption of the next block * depends only on the ciphertext of the IV block. */ - rv = crSpec->decode(crSpec->decodeContext, iv, &decoded, - sizeof(iv), cText->buf->buf, ivLen); + rv = spec->cipher(spec->cipherContext, iv, &decoded, + sizeof(iv), cText->buf->buf, ivLen); good &= SECStatusToMask(rv); } @@ -12347,7 +11888,7 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, PRINT_BUF(80, (ss, "ciphertext:", cText->buf->buf + ivLen, cText->buf->len - ivLen)); - isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); if (isTLS && cText->buf->len - ivLen > (MAX_FRAGMENT_LENGTH + 2048)) { *alert = record_overflow; @@ -12364,19 +11905,18 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, unsigned int decryptedLen = cText->buf->len - cipher_def->explicit_nonce_size - cipher_def->tag_size; - headerLen = ssl3_BuildRecordPseudoHeader( - header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, - rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen); - PORT_Assert(headerLen <= sizeof(header)); - rv = crSpec->aead( - ss->sec.isServer ? &crSpec->client : &crSpec->server, - PR_TRUE, /* do decrypt */ - plaintext->buf, /* out */ - (int *)&plaintext->len, /* outlen */ - plaintext->space, /* maxout */ - cText->buf->buf, /* in */ - cText->buf->len, /* inlen */ - header, headerLen); + rv = ssl3_BuildRecordPseudoHeader( + spec->epoch, IS_DTLS(ss) ? cText->seq_num : spec->seqNum, + rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen, &header); + PORT_Assert(rv == SECSuccess); + rv = spec->aead(&spec->keyMaterial, + PR_TRUE, /* do decrypt */ + plaintext->buf, /* out */ + (int *)&plaintext->len, /* outlen */ + plaintext->space, /* maxout */ + cText->buf->buf, /* in */ + cText->buf->len, /* inlen */ + SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header)); if (rv != SECSuccess) { good = 0; } @@ -12387,8 +11927,8 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, } /* decrypt from cText buf to plaintext. */ - rv = crSpec->decode( - crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len, + rv = spec->cipher( + spec->cipherContext, plaintext->buf, (int *)&plaintext->len, plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen); if (rv != SECSuccess) { goto decrypt_loser; @@ -12401,7 +11941,7 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, /* If it's a block cipher, check and strip the padding. */ if (cipher_def->type == type_block) { const unsigned int blockSize = cipher_def->block_size; - const unsigned int macSize = crSpec->mac_size; + const unsigned int macSize = spec->macDef->mac_size; if (!isTLS) { good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding( @@ -12413,32 +11953,32 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, } /* compute the MAC */ - headerLen = ssl3_BuildRecordPseudoHeader( - header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, + rv = ssl3_BuildRecordPseudoHeader( + spec->epoch, IS_DTLS(ss) ? cText->seq_num : spec->seqNum, rType, isTLS, cText->version, IS_DTLS(ss), - plaintext->len - crSpec->mac_size); - PORT_Assert(headerLen <= sizeof(header)); + plaintext->len - spec->macDef->mac_size, &header); + PORT_Assert(rv == SECSuccess); if (cipher_def->type == type_block) { rv = ssl3_ComputeRecordMACConstantTime( - crSpec, (PRBool)(!ss->sec.isServer), header, headerLen, + spec, SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header), plaintext->buf, plaintext->len, originalLen, hash, &hashBytes); ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf, - crSpec->mac_size); + spec->macDef->mac_size); givenHash = givenHashBuf; /* plaintext->len will always have enough space to remove the MAC * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust * plaintext->len if the result has enough space for the MAC and we * tested the unadjusted size against minLength, above. */ - plaintext->len -= crSpec->mac_size; + plaintext->len -= spec->macDef->mac_size; } else { /* This is safe because we checked the minLength above. */ - plaintext->len -= crSpec->mac_size; + plaintext->len -= spec->macDef->mac_size; rv = ssl3_ComputeRecordMAC( - crSpec, (PRBool)(!ss->sec.isServer), header, headerLen, + spec, SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header), plaintext->buf, plaintext->len, hash, &hashBytes); /* We can read the MAC directly from the record because its location @@ -12448,8 +11988,8 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, good &= SECStatusToMask(rv); - if (hashBytes != (unsigned)crSpec->mac_size || - NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) { + if (hashBytes != (unsigned)spec->macDef->mac_size || + NSS_SecureMemcmp(givenHash, hash, spec->macDef->mac_size) != 0) { /* We're allowed to leak whether or not the MAC check was correct */ good = 0; } @@ -12465,7 +12005,84 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, return SECSuccess; } -/* if cText is non-null, then decipher, check MAC, and decompress the +static SECStatus +ssl3_HandleNonApplicationData(sslSocket *ss, SSL3ContentType rType, + DTLSEpoch epoch, sslSequenceNumber seqNum, + sslBuffer *databuf) +{ + SECStatus rv; + + ssl_GetSSL3HandshakeLock(ss); + + /* All the functions called in this switch MUST set error code if + ** they return SECFailure or SECWouldBlock. + */ + switch (rType) { + case content_change_cipher_spec: + rv = ssl3_HandleChangeCipherSpecs(ss, databuf); + break; + case content_alert: + rv = ssl3_HandleAlert(ss, databuf); + break; + case content_handshake: + if (!IS_DTLS(ss)) { + rv = ssl3_HandleHandshake(ss, databuf); + } else { + rv = dtls_HandleHandshake(ss, epoch, seqNum, databuf); + } + break; + case content_ack: + if (IS_DTLS(ss) && tls13_MaybeTls13(ss)) { + rv = dtls13_HandleAck(ss, databuf); + break; + } + /* Fall through. */ + default: + SSL_DBG(("%d: SSL3[%d]: bogus content type=%d", + SSL_GETPID(), ss->fd, rType)); + PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE); + ssl3_DecodeError(ss); + rv = SECFailure; + break; + } + + ssl_ReleaseSSL3HandshakeLock(ss); + return rv; +} + +/* Find the cipher spec to use for a given record. For TLS, this + * is the current cipherspec. For DTLS, we look up by epoch. + * In DTLS < 1.3 this just means the current epoch or nothing, + * but in DTLS >= 1.3, we keep multiple reading cipherspecs. + * Returns NULL if no appropriate cipher spec is found. + */ +static ssl3CipherSpec * +ssl3_GetCipherSpec(sslSocket *ss, sslSequenceNumber seq) +{ + ssl3CipherSpec *crSpec = ss->ssl3.crSpec; + ssl3CipherSpec *newSpec = NULL; + DTLSEpoch epoch = seq >> 48; + + if (!IS_DTLS(ss)) { + return crSpec; + } + if (crSpec->epoch == epoch) { + return crSpec; + } + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + /* Try to find the cipher spec. */ + newSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecRead, + epoch); + if (newSpec != NULL) { + return newSpec; + } + } + SSL_TRC(10, ("%d: DTLS[%d]: Couldn't find cipherspec from epoch %d", + SSL_GETPID(), ss->fd, epoch)); + return NULL; +} + +/* 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 * is lost. Then handle databuf according to its SSL record type, @@ -12475,8 +12092,8 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, * checked, and is already sitting in databuf. It is processed as an SSL * Handshake message. * - * DOES NOT process the decrypted/decompressed application data. - * On return, databuf contains the decrypted/decompressed record. + * DOES NOT process the decrypted application data. + * On return, databuf contains the decrypted record. * * Called from ssl3_GatherCompleteHandshake * ssl3_RestartHandshakeAfterCertReq @@ -12492,20 +12109,15 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) { SECStatus rv; PRBool isTLS; - sslSequenceNumber seq_num = 0; - ssl3CipherSpec *crSpec; + DTLSEpoch epoch; + sslSequenceNumber seqNum = 0; + ssl3CipherSpec *spec = NULL; + PRBool outOfOrderSpec = PR_FALSE; SSL3ContentType rType; sslBuffer *plaintext; - sslBuffer temp_buf = { NULL, 0, 0 }; SSL3AlertDescription alert = internal_error; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); - if (!ss->ssl3.initialized) { - ssl_GetSSL3HandshakeLock(ss); - ssl3_InitState(ss); - ssl_ReleaseSSL3HandshakeLock(ss); - } - /* check for Token Presence */ if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) { PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); @@ -12519,41 +12131,48 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) if (cText == NULL) { SSL_DBG(("%d: SSL3[%d]: HandleRecord, resuming handshake", SSL_GETPID(), ss->fd)); - rType = content_handshake; - goto process_it; + /* 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); } ssl_GetSpecReadLock(ss); /******************************************/ - crSpec = ss->ssl3.crSpec; - isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0); - + spec = ssl3_GetCipherSpec(ss, cText->seq_num); + 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) { + PORT_Assert(IS_DTLS(ss)); + SSL_TRC(3, ("%d: DTLS[%d]: Handling out-of-epoch record from epoch=%d", + SSL_GETPID(), ss->fd, spec->epoch)); + outOfOrderSpec = PR_TRUE; + } + isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); if (IS_DTLS(ss)) { - PRBool sameEpoch; - if (!dtls_IsRelevant(ss, cText, &sameEpoch, &seq_num)) { + if (!dtls_IsRelevant(ss, spec, cText, &seqNum)) { ssl_ReleaseSpecReadLock(ss); /*****************************/ databuf->len = 0; /* Needed to ensure data not left around */ - /* Maybe retransmit if needed. */ - return dtls_MaybeRetransmitHandshake(ss, cText, sameEpoch); + return SECSuccess; } } else { - seq_num = crSpec->read_seq_num + 1; + seqNum = spec->seqNum + 1; } - if (seq_num >= crSpec->cipher_def->max_records) { + if (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, seq_num)); + SSL_GETPID(), ss->fd, seqNum)); PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS); return SECFailure; } - /* If we will be decompressing the buffer we need to decrypt somewhere - * other than into databuf */ - if (crSpec->decompressor) { - plaintext = &temp_buf; - } else { - plaintext = databuf; - } + plaintext = databuf; plaintext->len = 0; /* filled in by Unprotect call below. */ /* We're waiting for another ClientHello, which will appear unencrypted. @@ -12588,12 +12207,12 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) /* 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 (crSpec->version < SSL_LIBRARY_VERSION_TLS_1_3 || - crSpec->cipher_def->calg == ssl_calg_null) { + 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, cText, plaintext, &alert); + rv = ssl3_UnprotectRecord(ss, spec, cText, plaintext, &alert); } else { - rv = tls13_UnprotectRecord(ss, cText, plaintext, &alert); + rv = tls13_UnprotectRecord(ss, spec, cText, plaintext, &alert); } #endif @@ -12602,14 +12221,25 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd)); - /* Clear the temp buffer used for decompression upon failure. */ - sslBuffer_Clear(&temp_buf); + /* Ensure that we don't process this data again. */ + databuf->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. */ + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 && + cText->type == 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 */ - databuf->len = 0; /* Needed to ensure data not left around */ return SECSuccess; } else { int errCode = PORT_GetError(); @@ -12622,10 +12252,11 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) } /* SECSuccess */ - crSpec->read_seq_num = seq_num; + spec->seqNum = PR_MAX(spec->seqNum, seqNum); if (IS_DTLS(ss)) { - dtls_RecordSetRecvd(&crSpec->recvdRecords, seq_num); + dtls_RecordSetRecvd(&spec->recvdRecords, seqNum); } + epoch = spec->epoch; ssl_ReleaseSpecReadLock(ss); /*****************************************/ @@ -12635,70 +12266,16 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) rType = cText->type; /* This must go after decryption because TLS 1.3 * has encrypted content types. */ - /* possibly decompress the record. If we aren't using compression then - * plaintext == databuf and so the uncompressed data is already in - * databuf. */ - if (crSpec->decompressor) { - if (databuf->space < plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION) { - rv = sslBuffer_Grow( - databuf, plaintext->len + SSL3_COMPRESSION_MAX_EXPANSION); - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, - plaintext->len + - SSL3_COMPRESSION_MAX_EXPANSION)); - /* sslBuffer_Grow has set a memory error code. */ - /* Perhaps we should send an alert. (but we have no memory!) */ - sslBuffer_Clear(&temp_buf); - return SECFailure; - } - } - - rv = crSpec->decompressor(crSpec->decompressContext, - databuf->buf, - (int *)&databuf->len, - databuf->space, - plaintext->buf, - plaintext->len); - - if (rv != SECSuccess) { - int err = ssl_MapLowLevelError(SSL_ERROR_DECOMPRESSION_FAILURE); - SSL3_SendAlert(ss, alert_fatal, - isTLS ? decompression_failure - : bad_record_mac); - - /* There appears to be a bug with (at least) Apache + OpenSSL where - * resumed SSLv3 connections don't actually use compression. See - * comments 93-95 of - * https://bugzilla.mozilla.org/show_bug.cgi?id=275744 - * - * So, if we get a decompression error, and the record appears to - * be already uncompressed, then we return a more specific error - * code to hopefully save somebody some debugging time in the - * future. - */ - if (plaintext->len >= 4) { - unsigned int len = ((unsigned int)plaintext->buf[1] << 16) | - ((unsigned int)plaintext->buf[2] << 8) | - (unsigned int)plaintext->buf[3]; - if (len == plaintext->len - 4) { - /* This appears to be uncompressed already */ - err = SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD; - } - } - - sslBuffer_Clear(&temp_buf); - PORT_SetError(err); - return SECFailure; - } - - sslBuffer_Clear(&temp_buf); + /* 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); } - /* - ** Having completed the decompression, check the length again. - */ - if (isTLS && databuf->len > (MAX_FRAGMENT_LENGTH + 1024)) { + /* Check the length of the plaintext. */ + if (isTLS && databuf->len > MAX_FRAGMENT_LENGTH) { SSL3_SendAlert(ss, alert_fatal, record_overflow); PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); return SECFailure; @@ -12720,45 +12297,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) return SECFailure; } -/* It's a record that must be handled by ssl itself, not the application. - */ -process_it: - /* XXX Get the xmit lock here. Odds are very high that we'll be xmiting - * data ang getting the xmit lock here prevents deadlocks. - */ - ssl_GetSSL3HandshakeLock(ss); - - /* All the functions called in this switch MUST set error code if - ** they return SECFailure or SECWouldBlock. - */ - switch (rType) { - case content_change_cipher_spec: - rv = ssl3_HandleChangeCipherSpecs(ss, databuf); - break; - case content_alert: - rv = ssl3_HandleAlert(ss, databuf); - break; - case content_handshake: - if (!IS_DTLS(ss)) { - rv = ssl3_HandleHandshake(ss, databuf); - } else { - rv = dtls_HandleHandshake(ss, databuf); - } - break; - /* - case content_application_data is handled before this switch - */ - default: - SSL_DBG(("%d: SSL3[%d]: bogus content type=%d", - SSL_GETPID(), ss->fd, cText->type)); - PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE); - ssl3_DecodeError(ss); - rv = SECFailure; - break; - } - - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; + return ssl3_HandleNonApplicationData(ss, rType, epoch, seqNum, databuf); } /* @@ -12776,83 +12315,36 @@ ssl_InitSecState(sslSecurityInfo *sec) sec->keaGroup = NULL; } -/* Called from ssl3_InitState, immediately below. */ -/* Caller must hold the SpecWriteLock. */ -void -ssl3_InitCipherSpec(ssl3CipherSpec *spec) -{ - spec->cipher_def = &bulk_cipher_defs[cipher_null]; - PORT_Assert(spec->cipher_def->cipher == cipher_null); - spec->mac_def = &mac_defs[mac_null]; - PORT_Assert(spec->mac_def->mac == mac_null); - spec->encode = Null_Cipher; - spec->decode = Null_Cipher; - spec->compressor = NULL; - spec->decompressor = NULL; - spec->destroyCompressContext = NULL; - spec->destroyDecompressContext = NULL; - spec->mac_size = 0; - spec->master_secret = NULL; - - spec->msItem.data = NULL; - spec->msItem.len = 0; - - spec->client.write_key = NULL; - spec->client.write_mac_key = NULL; - spec->client.write_mac_context = NULL; - - spec->server.write_key = NULL; - spec->server.write_mac_key = NULL; - spec->server.write_mac_context = NULL; - - spec->write_seq_num = 0; - spec->read_seq_num = 0; - spec->epoch = 0; - - spec->refCt = 128; /* Arbitrarily high number to prevent - * non-TLS 1.3 cipherSpecs from being - * GCed. This will be overwritten with - * a valid refCt for TLS 1.3. */ - dtls_InitRecvdRecords(&spec->recvdRecords); -} - -/* Called from: ssl3_SendRecord -** ssl3_SendClientHello() -** ssl3_HandleV2ClientHello() -** ssl3_HandleRecord() -** -** This function should perhaps acquire and release the SpecWriteLock. -*/ -void +SECStatus ssl3_InitState(sslSocket *ss) { - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - if (ss->ssl3.initialized) - return; /* Function should be idempotent */ + SECStatus rv; ss->ssl3.policy = SSL_ALLOWED; ssl_InitSecState(&ss->sec); ssl_GetSpecWriteLock(ss); - ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0]; - ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1]; - ssl3_InitCipherSpec(ss->ssl3.crSpec); - ssl3_InitCipherSpec(ss->ssl3.prSpec); - ss->ssl3.crSpec->version = ss->ssl3.prSpec->version = ss->vrange.max; + PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs); + rv = ssl_SetupNullCipherSpec(ss, CipherSpecRead); + rv |= ssl_SetupNullCipherSpec(ss, CipherSpecWrite); + ss->ssl3.pwSpec = ss->ssl3.prSpec = NULL; ssl_ReleaseSpecWriteLock(ss); + if (rv != SECSuccess) { + /* Rely on ssl_CreateNullCipherSpec() to set error code. */ + return SECFailure; + } ss->ssl3.hs.sendingSCSV = PR_FALSE; ss->ssl3.hs.preliminaryInfo = 0; - ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; + ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : idle_handshake; - ssl3_ResetExtensionData(&ss->xtnData); + ssl3_ResetExtensionData(&ss->xtnData, ss); PR_INIT_CLIST(&ss->ssl3.hs.remoteExtensions); if (IS_DTLS(ss)) { ss->ssl3.hs.sendMessageSeq = 0; ss->ssl3.hs.recvMessageSeq = 0; - ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS; + ss->ssl3.hs.rtTimer->timeout = DTLS_RETRANSMIT_INITIAL_MS; ss->ssl3.hs.rtRetries = 0; ss->ssl3.hs.recvdHighWater = -1; PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight); @@ -12868,8 +12360,6 @@ ssl3_InitState(sslSocket *ss) ss->ssl3.hs.serverHsTrafficSecret = NULL; ss->ssl3.hs.clientTrafficSecret = NULL; ss->ssl3.hs.serverTrafficSecret = NULL; - ss->ssl3.hs.certificateRequest = NULL; - PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs); PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space); ss->ssl3.hs.messages.buf = NULL; @@ -12881,9 +12371,7 @@ ssl3_InitState(sslSocket *ss) ss->ssl3.hs.zeroRttState = ssl_0rtt_none; - ssl_FilterSupportedGroups(ss); - - ss->ssl3.initialized = PR_TRUE; + return SECSuccess; } /* record the export policy for this cipher suite */ @@ -13137,8 +12625,7 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - if (!ss->firstHsDone || - (ss->ssl3.initialized && (ss->ssl3.hs.ws != idle_handshake))) { + if (!ss->firstHsDone || (ss->ssl3.hs.ws != idle_handshake)) { PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); return SECFailure; } @@ -13152,6 +12639,11 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); return SECFailure; } + if (ss->version > ss->vrange.max || ss->version < ss->vrange.min) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); + return SECFailure; + } + if (sid && flushCache) { ss->sec.uncache(sid); /* remove it from whichever cache it's in. */ ssl_FreeSID(sid); /* dec ref count and free if zero. */ @@ -13209,15 +12701,7 @@ ssl3_DestroySSL3Info(sslSocket *ss) SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE); SECITEM_FreeItem(&ss->ssl3.hs.srvVirtName, PR_FALSE); - - if (ss->ssl3.hs.certificateRequest) { - PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE); - ss->ssl3.hs.certificateRequest = NULL; - } - - /* free up the CipherSpecs */ - ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE /*freeSrvName*/); - ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE /*freeSrvName*/); + SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE); /* Destroy the DTLS data */ if (IS_DTLS(ss)) { @@ -13229,10 +12713,10 @@ ssl3_DestroySSL3Info(sslSocket *ss) /* Destroy remote extensions */ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); - ssl3_ResetExtensionData(&ss->xtnData); + ssl3_DestroyExtensionData(&ss->xtnData); - /* Destroy TLS 1.3 cipher specs */ - tls13_DestroyCipherSpecs(&ss->ssl3.hs.cipherSpecs); + /* Destroy cipher specs */ + ssl_DestroyCipherSpecs(&ss->ssl3.hs.cipherSpecs); /* Destroy TLS 1.3 keys */ if (ss->ssl3.hs.currentSecret) @@ -13261,8 +12745,6 @@ ssl3_DestroySSL3Info(sslSocket *ss) ss->ssl3.hs.zeroRttState = ssl_0rtt_none; /* Destroy TLS 1.3 buffered early data. */ tls13_DestroyEarlyData(&ss->ssl3.hs.bufferedEarlyData); - - ss->ssl3.initialized = PR_FALSE; } #define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER) @@ -13301,7 +12783,7 @@ ssl3_ApplyNSSPolicy(void) } if (ssl_GetBulkCipherDef(suite)->type != type_aead) { - policyOid = MAP_NULL(mac_defs[suite->mac_alg].oid); + policyOid = MAP_NULL(ssl_GetMacDefByAlg(suite->mac_alg)->oid); rv = NSS_GetAlgorithmPolicy(policyOid, &policy); if (rv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL)) { ssl_CipherPrefSetDefault(suite->cipher_suite, PR_FALSE); diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c index b440b4b02..913a14f63 100644 --- a/security/nss/lib/ssl/ssl3ecc.c +++ b/security/nss/lib/ssl/ssl3ecc.c @@ -111,7 +111,7 @@ ssl_ECPubKey2NamedGroup(const SECKEYPublicKey *pubKey) static SECStatus ssl3_ComputeECDHKeyHash(SSLHashType hashAlg, SECItem ec_params, SECItem server_ecpoint, - SSL3Random *client_rand, SSL3Random *server_rand, + PRUint8 *client_rand, PRUint8 *server_rand, SSL3Hashes *hashes) { PRUint8 *hashBuf; @@ -175,8 +175,8 @@ ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* Generate ephemeral EC keypair */ if (svrPubKey->keyType != ecKey) { @@ -219,7 +219,7 @@ ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) goto loser; } - rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange, pubKey->u.ec.publicValue.len + 1); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ @@ -232,7 +232,7 @@ ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) goto loser; /* err set by ssl3_AppendHandshake* */ } - rv = ssl3_InitPendingCipherSpec(ss, pms); + rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; @@ -250,19 +250,6 @@ loser: return SECFailure; } -/* This function encodes the key_exchange field in - * the KeyShareEntry structure. */ -SECStatus -tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss, const SECKEYPublicKey *pubKey) -{ - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - PORT_Assert(pubKey->keyType == ecKey); - - return ssl3_ExtAppendHandshake(ss, pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len); -} - /* ** Called from ssl3_HandleClientKeyExchange() */ @@ -326,7 +313,7 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b, return SECFailure; } - rv = ssl3_InitPendingCipherSpec(ss, pms); + rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); PK11_FreeSymKey(pms); if (rv != SECSuccess) { /* error code set by ssl3_InitPendingCipherSpec */ @@ -597,8 +584,8 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) * check to make sure the hash is signed by right guy */ rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, ec_point, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, + ss->ssl3.hs.client_random, + ss->ssl3.hs.server_random, &hashes); if (rv != SECSuccess) { @@ -703,7 +690,7 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss) ec_params.data[2] = keyPair->group->name & 0xff; pubKey = keyPair->keys->pubKey; - if (ss->ssl3.pwSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) { hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme); } else { /* Use ssl_hash_none to represent the MD5+SHA1 combo. */ @@ -711,15 +698,15 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss) } rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, pubKey->u.ec.publicValue, - &ss->ssl3.hs.client_random, - &ss->ssl3.hs.server_random, + ss->ssl3.hs.client_random, + ss->ssl3.hs.server_random, &hashes); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto loser; } - isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); rv = ssl3_SignHashes(ss, &hashes, ss->sec.serverCert->serverKeyPair->privKey, &signed_hash); @@ -731,7 +718,7 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss) 1 + pubKey->u.ec.publicValue.len + (isTLS12 ? 2 : 0) + 2 + signed_hash.len; - rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } @@ -870,20 +857,16 @@ ssl_IsDHEEnabled(const sslSocket *ss) } /* Send our Supported Groups extension. */ -PRInt32 -ssl_SendSupportedGroupsXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes) +SECStatus +ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - unsigned char enabledGroups[64]; - unsigned int enabledGroupsLen = 0; unsigned int i; PRBool ec; PRBool ff = PR_FALSE; - - if (!ss) - return 0; + PRBool found = PR_FALSE; + SECStatus rv; + unsigned int lengthOffset; /* We only send FF supported groups if we require DH named groups * or if TLS 1.3 is a possibility. */ @@ -892,13 +875,19 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, if (ss->opt.requireDHENamedGroups) { ff = ssl_IsDHEEnabled(ss); } - if (!ec && !ff) - return 0; + if (!ec && !ff) { + return SECSuccess; + } } else { ec = ff = PR_TRUE; } - PORT_Assert(sizeof(enabledGroups) > SSL_NAMED_GROUP_COUNT * 2); + /* Mark the location of the length. */ + rv = sslBuffer_Skip(buf, 2, &lengthOffset); + if (rv != SECSuccess) { + return SECFailure; + } + for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { const sslNamedGroupDef *group = ss->namedGroupPreferences[i]; if (!group) { @@ -911,78 +900,53 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, continue; } - if (append) { - (void)ssl_EncodeUintX(group->name, 2, &enabledGroups[enabledGroupsLen]); - } - enabledGroupsLen += 2; - } - - if (enabledGroupsLen == 0) { - return 0; - } - - extension_length = - 2 /* extension type */ + - 2 /* extension length */ + - 2 /* enabled groups length */ + - enabledGroupsLen; - - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - - if (append) { - SECStatus rv; - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_supported_groups_xtn, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_ExtAppendHandshakeVariable(ss, enabledGroups, - enabledGroupsLen, 2); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - xtnData->advertised[xtnData->numAdvertised++] = - ssl_supported_groups_xtn; + found = PR_TRUE; + rv = sslBuffer_AppendNumber(buf, group->name, 2); + if (rv != SECSuccess) { + return SECFailure; } } - return extension_length; + + if (!found) { + /* We added nothing, don't send the extension. */ + return SECSuccess; + } + + rv = sslBuffer_InsertLength(buf, lengthOffset, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + *added = PR_TRUE; + return SECSuccess; } /* Send our "canned" (precompiled) Supported Point Formats extension, * which says that we only support uncompressed points. */ -PRInt32 -ssl3_SendSupportedPointFormatsXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - static const PRUint8 ecPtFmt[6] = { - 0, 11, /* Extension type */ - 0, 2, /* octets that follow */ - 1, /* octets that follow */ - 0 /* uncompressed type only */ - }; + SECStatus rv; /* No point in doing this unless we have a socket that supports ECC. * Similarly, no point if we are going to do TLS 1.3 only or we have already * picked TLS 1.3 (server) given that it doesn't use point formats. */ if (!ss || !ssl_IsECCEnabled(ss) || ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_3 || - (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)) - return 0; - if (append && maxBytes >= (sizeof ecPtFmt)) { - SECStatus rv = ssl3_ExtAppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt)); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - xtnData->advertised[xtnData->numAdvertised++] = - ssl_ec_point_formats_xtn; - } + (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)) { + return SECSuccess; } - return sizeof(ecPtFmt); + rv = sslBuffer_AppendNumber(buf, 1, 1); /* length */ + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(buf, 0, 1); /* uncompressed type only */ + if (rv != SECSuccess) { + return SECFailure; + } + + *added = PR_TRUE; + return SECSuccess; } diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index 271084cf7..ade280903 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/lib/ssl/ssl3ext.c @@ -14,8 +14,20 @@ #include "sslimpl.h" #include "sslproto.h" #include "ssl3exthandle.h" +#include "tls13err.h" #include "tls13exthandle.h" +/* Callback function that handles a received extension. */ +typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); + +/* Row in a table of hello extension handlers. */ +typedef struct { + SSLExtensionType ex_type; + ssl3ExtensionHandlerFunc ex_handler; +} ssl3ExtensionHandler; + /* Table of handlers for received TLS hello extensions, one per extension. * In the second generation, this table will be dynamic, and functions * will be registered here. @@ -31,16 +43,15 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = { { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn }, { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn }, { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn }, - { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, + { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn }, { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn }, { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn }, { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn }, { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn }, { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn }, - { ssl_tls13_psk_key_exchange_modes_xtn, - &tls13_ServerHandlePskKeyExchangeModesXtn }, - { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn }, - { -1, NULL } + { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn }, + { ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn }, + { 0, NULL } }; /* These two tables are used by the client, to handle server hello @@ -59,36 +70,38 @@ 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_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn }, - { -1, NULL } + { 0, NULL } }; static const ssl3ExtensionHandler helloRetryRequestHandlers[] = { { ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr }, { ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie }, - { -1, NULL } + { 0, NULL } }; static const ssl3ExtensionHandler serverHelloHandlersSSL3[] = { { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, - { -1, NULL } + { 0, NULL } }; static const ssl3ExtensionHandler newSessionTicketHandlers[] = { - { ssl_tls13_ticket_early_data_info_xtn, - &tls13_ClientHandleTicketEarlyDataInfoXtn }, - { -1, NULL } + { ssl_tls13_early_data_xtn, + &tls13_ClientHandleTicketEarlyDataXtn }, + { 0, NULL } }; /* This table is used by the client to handle server certificates in TLS 1.3 */ static const ssl3ExtensionHandler serverCertificateHandlers[] = { { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn }, { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, - { -1, NULL } + { 0, NULL } }; static const ssl3ExtensionHandler certificateRequestHandlers[] = { - { -1, NULL } + { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn }, + { ssl_tls13_certificate_authorities_xtn, + &tls13_ClientHandleCertAuthoritiesXtn }, + { 0, NULL } }; /* Tables of functions to format TLS hello extensions, one function per @@ -101,14 +114,14 @@ static const ssl3ExtensionHandler certificateRequestHandlers[] = { * the client hello is empty (for example, the extended master secret * extension, if it were listed last). See bug 1243641. */ -static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = +static const sslExtensionBuilder clientHelloSendersTLS[] = { - { ssl_server_name_xtn, &ssl3_SendServerNameXtn }, + { ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn }, { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn }, { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }, { ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn }, { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn }, - { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, + { 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 }, @@ -121,22 +134,155 @@ static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] * client hello is empty. They are not intolerant of TLS 1.2, so list * signature_algorithms at the end. See bug 1243641. */ { ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn }, - { ssl_tls13_short_header_xtn, &tls13_SendShortHeaderXtn }, - { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, + { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn }, { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn }, - { ssl_tls13_psk_key_exchange_modes_xtn, - &tls13_ClientSendPskKeyExchangeModesXtn }, - { ssl_padding_xtn, &ssl3_ClientSendPaddingExtension }, + { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn }, /* The pre_shared_key extension MUST be last. */ { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn }, - /* any extra entries will appear as { 0, NULL } */ + { 0, NULL } }; -static const ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = { - { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn } - /* any extra entries will appear as { 0, NULL } */ +static const sslExtensionBuilder clientHelloSendersSSL3[] = { + { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }, + { 0, NULL } +}; + +static const sslExtensionBuilder tls13_cert_req_senders[] = { + { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn }, + { ssl_tls13_certificate_authorities_xtn, &tls13_SendCertAuthoritiesXtn }, + { 0, NULL } +}; + +static const sslExtensionBuilder tls13_hrr_senders[] = { + { ssl_tls13_key_share_xtn, &tls13_ServerSendHrrKeyShareXtn }, + { ssl_tls13_cookie_xtn, &tls13_ServerSendHrrCookieXtn }, + { ssl_tls13_supported_versions_xtn, &tls13_ServerSendSupportedVersionsXtn }, + { 0, NULL } +}; + +static const struct { + SSLExtensionType type; + SSLExtensionSupport support; +} ssl_supported_extensions[] = { + { ssl_server_name_xtn, ssl_ext_native_only }, + { ssl_cert_status_xtn, ssl_ext_native }, + { ssl_supported_groups_xtn, ssl_ext_native_only }, + { ssl_ec_point_formats_xtn, ssl_ext_native }, + { ssl_signature_algorithms_xtn, ssl_ext_native_only }, + { ssl_use_srtp_xtn, ssl_ext_native }, + { ssl_app_layer_protocol_xtn, ssl_ext_native_only }, + { ssl_signed_cert_timestamp_xtn, ssl_ext_native }, + { ssl_padding_xtn, ssl_ext_native }, + { ssl_extended_master_secret_xtn, ssl_ext_native_only }, + { ssl_session_ticket_xtn, ssl_ext_native_only }, + { ssl_tls13_key_share_xtn, ssl_ext_native_only }, + { ssl_tls13_pre_shared_key_xtn, ssl_ext_native_only }, + { ssl_tls13_early_data_xtn, ssl_ext_native_only }, + { ssl_tls13_supported_versions_xtn, ssl_ext_native_only }, + { ssl_tls13_cookie_xtn, ssl_ext_native_only }, + { 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 } }; +static SSLExtensionSupport +ssl_GetExtensionSupport(PRUint16 type) +{ + unsigned int i; + for (i = 0; i < PR_ARRAY_SIZE(ssl_supported_extensions); ++i) { + if (type == ssl_supported_extensions[i].type) { + return ssl_supported_extensions[i].support; + } + } + return ssl_ext_none; +} + +SECStatus +SSLExp_GetExtensionSupport(PRUint16 type, SSLExtensionSupport *support) +{ + *support = ssl_GetExtensionSupport(type); + return SECSuccess; +} + +SECStatus +SSLExp_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension, + SSLExtensionWriter writer, void *writerArg, + SSLExtensionHandler handler, void *handlerArg) +{ + sslSocket *ss = ssl_FindSocket(fd); + PRCList *cursor; + sslCustomExtensionHooks *hook; + + if (!ss) { + return SECFailure; /* Code already set. */ + } + + /* Need to specify both or neither, but not just one. */ + if ((writer && !handler) || (!writer && handler)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (ssl_GetExtensionSupport(extension) == ssl_ext_native_only) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (ss->firstHsDone || ((ss->ssl3.hs.ws != idle_handshake) && + (ss->ssl3.hs.ws != wait_client_hello))) { + PORT_SetError(PR_INVALID_STATE_ERROR); + return SECFailure; + } + + /* Remove any old handler. */ + for (cursor = PR_NEXT_LINK(&ss->extensionHooks); + cursor != &ss->extensionHooks; + cursor = PR_NEXT_LINK(cursor)) { + hook = (sslCustomExtensionHooks *)cursor; + if (hook->type == extension) { + PR_REMOVE_LINK(&hook->link); + PORT_Free(hook); + break; + } + } + + if (!writer && !handler) { + return SECSuccess; + } + + hook = PORT_ZNew(sslCustomExtensionHooks); + if (!hook) { + return SECFailure; /* This removed the old one, oh well. */ + } + + hook->type = extension; + hook->writer = writer; + hook->writerArg = writerArg; + hook->handler = handler; + hook->handlerArg = handlerArg; + PR_APPEND_LINK(&hook->link, &ss->extensionHooks); + return SECSuccess; +} + +static sslCustomExtensionHooks * +ssl_FindCustomExtensionHooks(sslSocket *ss, PRUint16 extension) +{ + PRCList *cursor; + + for (cursor = PR_NEXT_LINK(&ss->extensionHooks); + cursor != &ss->extensionHooks; + cursor = PR_NEXT_LINK(cursor)) { + sslCustomExtensionHooks *hook = (sslCustomExtensionHooks *)cursor; + if (hook->type == extension) { + return hook; + } + } + + return NULL; +} + static PRBool arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type) { @@ -156,8 +302,11 @@ ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type) xtnData->numNegotiated, ex_type); } +/* This checks for whether an extension was advertised. On the client, this + * covers extensions that are sent in ClientHello; on the server, extensions + * sent in CertificateRequest (TLS 1.3 only). */ PRBool -ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type) +ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type) { const TLSExtensionData *xtnData = &ss->xtnData; return arrayContainsExtension(xtnData->advertised, @@ -240,6 +389,44 @@ ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type) return NULL; } +static SECStatus +ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage, + TLSExtension *extension, + const ssl3ExtensionHandler *handler) +{ + SECStatus rv = SECSuccess; + SSLAlertDescription alert = handshake_failure; + sslCustomExtensionHooks *customHooks; + + customHooks = ssl_FindCustomExtensionHooks(ss, extension->type); + if (customHooks) { + if (customHooks->handler) { + rv = customHooks->handler(ss->fd, handshakeMessage, + extension->data.data, + extension->data.len, + &alert, customHooks->handlerArg); + } + } else { + /* Find extension_type in table of Hello Extension Handlers. */ + for (; handler->ex_handler != NULL; ++handler) { + if (handler->ex_type == extension->type) { + rv = (*handler->ex_handler)(ss, &ss->xtnData, &extension->data); + break; + } + } + } + + if (rv != SECSuccess) { + if (!ss->ssl3.fatalAlertSent) { + /* Send an alert if the handler didn't already. */ + (void)SSL3_SendAlert(ss, alert_fatal, alert); + } + return SECFailure; + } + + return SECSuccess; +} + /* Go through the hello extensions in |ss->ssl3.hs.remoteExtensions|. * For each one, find the extension handler in the table, and * if present, invoke that handler. @@ -250,42 +437,46 @@ ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type) * right phase. */ SECStatus -ssl3_HandleParsedExtensions(sslSocket *ss, - SSL3HandshakeType handshakeMessage) +ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) { const ssl3ExtensionHandler *handlers; /* HelloRetryRequest doesn't set ss->version. It might be safe to * do so, but we weren't entirely sure. TODO(ekr@rtfm.com). */ PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) || - (handshakeMessage == hello_retry_request); + (message == ssl_hs_hello_retry_request); + /* The following messages can include extensions that were not included in + * the original ClientHello. */ + PRBool allowNotOffered = (message == ssl_hs_client_hello) || + (message == ssl_hs_certificate_request) || + (message == ssl_hs_new_session_ticket); PRCList *cursor; - switch (handshakeMessage) { - case client_hello: + switch (message) { + case ssl_hs_client_hello: handlers = clientHelloHandlers; break; - case new_session_ticket: + case ssl_hs_new_session_ticket: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); handlers = newSessionTicketHandlers; break; - case hello_retry_request: + case ssl_hs_hello_retry_request: handlers = helloRetryRequestHandlers; break; - case encrypted_extensions: + case ssl_hs_encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); /* fall through */ - case server_hello: + case ssl_hs_server_hello: if (ss->version > SSL_LIBRARY_VERSION_3_0) { handlers = serverHelloHandlersTLS; } else { handlers = serverHelloHandlersSSL3; } break; - case certificate: + case ssl_hs_certificate: PORT_Assert(!ss->sec.isServer); handlers = serverCertificateHandlers; break; - case certificate_request: + case ssl_hs_certificate_request: PORT_Assert(!ss->sec.isServer); handlers = certificateRequestHandlers; break; @@ -299,28 +490,39 @@ ssl3_HandleParsedExtensions(sslSocket *ss, cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { TLSExtension *extension = (TLSExtension *)cursor; - const ssl3ExtensionHandler *handler; + SECStatus rv; /* Check whether the server sent an extension which was not advertised - * in the ClientHello */ - if (!ss->sec.isServer && - !ssl3_ClientExtensionAdvertised(ss, extension->type) && - (handshakeMessage != new_session_ticket) && - (extension->type != ssl_tls13_cookie_xtn)) { + * in the ClientHello. + * + * Note that a TLS 1.3 server should check if CertificateRequest + * extensions were sent. But the extensions used for CertificateRequest + * do not have any response, so we rely on + * ssl3_ExtensionAdvertised to return false on the server. That + * results in the server only rejecting any extension. */ + if (!allowNotOffered && (extension->type != ssl_tls13_cookie_xtn) && + !ssl3_ExtensionAdvertised(ss, extension->type)) { (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); return SECFailure; } /* Check that this is a legal extension in TLS 1.3 */ - if (isTLS13 && !tls13_ExtensionAllowed(extension->type, handshakeMessage)) { - if (handshakeMessage == client_hello) { - /* Skip extensions not used in TLS 1.3 */ - continue; + if (isTLS13 && + !ssl_FindCustomExtensionHooks(ss, extension->type)) { + switch (tls13_ExtensionStatus(extension->type, message)) { + case tls13_extension_allowed: + break; + case tls13_extension_unknown: + if (allowNotOffered) { + continue; /* Skip over unknown extensions. */ + } + /* Fall through. */ + case tls13_extension_disallowed: + tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, + unsupported_extension); + return SECFailure; } - tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, - unsupported_extension); - return SECFailure; } /* Special check for this being the last extension if it's @@ -334,23 +536,9 @@ ssl3_HandleParsedExtensions(sslSocket *ss, return SECFailure; } - /* find extension_type in table of Hello Extension Handlers */ - for (handler = handlers; handler->ex_type >= 0; handler++) { - /* if found, call this handler */ - if (handler->ex_type == extension->type) { - SECStatus rv; - - rv = (*handler->ex_handler)(ss, &ss->xtnData, - (PRUint16)extension->type, - &extension->data); - if (rv != SECSuccess) { - if (!ss->ssl3.fatalAlertSent) { - /* send a generic alert if the handler didn't already */ - (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); - } - return SECFailure; - } - } + rv = ssl_CallExtensionHandler(ss, message, extension, handlers); + if (rv != SECSuccess) { + return SECFailure; } } return SECSuccess; @@ -361,7 +549,7 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SECStatus ssl3_HandleExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length, - SSL3HandshakeType handshakeMessage) + SSLHandshakeType handshakeMessage) { SECStatus rv; @@ -383,21 +571,30 @@ SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - ssl3HelloExtensionSenderFunc cb) + sslExtensionBuilderFunc cb) { int i; - ssl3HelloExtensionSender *sender; + sslExtensionBuilder *sender; if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { sender = &xtnData->serverHelloSenders[0]; } else { - if (tls13_ExtensionAllowed(ex_type, server_hello)) { - PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions)); + if (tls13_ExtensionStatus(ex_type, ssl_hs_server_hello) == + tls13_extension_allowed) { + PORT_Assert(tls13_ExtensionStatus(ex_type, + ssl_hs_encrypted_extensions) == + tls13_extension_disallowed); sender = &xtnData->serverHelloSenders[0]; - } else if (tls13_ExtensionAllowed(ex_type, certificate)) { + } else if (tls13_ExtensionStatus(ex_type, + ssl_hs_encrypted_extensions) == + tls13_extension_allowed) { + sender = &xtnData->encryptedExtensionsSenders[0]; + } else if (tls13_ExtensionStatus(ex_type, ssl_hs_certificate) == + tls13_extension_allowed) { sender = &xtnData->certificateSenders[0]; } else { - PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions)); - sender = &xtnData->encryptedExtensionsSenders[0]; + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } } for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { @@ -418,32 +615,289 @@ ssl3_RegisterExtensionSender(const sslSocket *ss, return SECFailure; } -/* call each of the extension senders and return the accumulated length */ -PRInt32 -ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, - const ssl3HelloExtensionSender *sender) +static SECStatus +ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf, + SSLHandshakeType message) { - PRInt32 total_exten_len = 0; - int i; + sslBuffer tail = SSL_BUFFER_EMPTY; + SECStatus rv; + PRCList *cursor; - if (!sender) { - if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) { - sender = &clientHelloSendersTLS[0]; - } else { - sender = &clientHelloSendersSSL3[0]; + /* Save any extensions that want to be last. */ + if (ss->xtnData.lastXtnOffset) { + rv = sslBuffer_Append(&tail, buf->buf + ss->xtnData.lastXtnOffset, + buf->len - ss->xtnData.lastXtnOffset); + if (rv != SECSuccess) { + return SECFailure; } + buf->len = ss->xtnData.lastXtnOffset; } - for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { - if (sender->ex_sender) { - PRInt32 extLen = (*sender->ex_sender)(ss, &ss->xtnData, append, maxBytes); - if (extLen < 0) - return -1; - maxBytes -= extLen; - total_exten_len += extLen; + /* Reserve the maximum amount of space possible. */ + rv = sslBuffer_Grow(buf, 65535); + if (rv != SECSuccess) { + return SECFailure; + } + + for (cursor = PR_NEXT_LINK(&ss->extensionHooks); + cursor != &ss->extensionHooks; + cursor = PR_NEXT_LINK(cursor)) { + sslCustomExtensionHooks *hook = + (sslCustomExtensionHooks *)cursor; + PRBool append = PR_FALSE; + unsigned int len = 0; + + if (hook->writer) { + /* The writer writes directly into |buf|. Provide space that allows + * for the existing extensions, any tail, plus type and length. */ + unsigned int space = buf->space - (buf->len + tail.len + 4); + append = (*hook->writer)(ss->fd, message, + buf->buf + buf->len + 4, &len, space, + hook->writerArg); + if (len > space) { + PORT_SetError(SEC_ERROR_APPLICATION_CALLBACK_ERROR); + goto loser; + } + } + if (!append) { + continue; + } + + rv = sslBuffer_AppendNumber(buf, hook->type, 2); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + rv = sslBuffer_AppendNumber(buf, len, 2); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + buf->len += len; + + if (message == ssl_hs_client_hello || + message == ssl_hs_certificate_request) { + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = hook->type; } } - return total_exten_len; + + sslBuffer_Append(buf, tail.buf, tail.len); + sslBuffer_Clear(&tail); + return SECSuccess; + +loser: + sslBuffer_Clear(&tail); + return SECFailure; +} + +/* Call extension handlers for the given message. */ +SECStatus +ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message) +{ + const sslExtensionBuilder *sender; + SECStatus rv; + + PORT_Assert(buf->len == 0); + + switch (message) { + case ssl_hs_client_hello: + if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) { + sender = clientHelloSendersTLS; + } else { + sender = clientHelloSendersSSL3; + } + break; + + case ssl_hs_server_hello: + sender = ss->xtnData.serverHelloSenders; + break; + + case ssl_hs_certificate_request: + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + sender = tls13_cert_req_senders; + break; + + case ssl_hs_certificate: + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + sender = ss->xtnData.certificateSenders; + break; + + case ssl_hs_encrypted_extensions: + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + sender = ss->xtnData.encryptedExtensionsSenders; + break; + + case ssl_hs_hello_retry_request: + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + sender = tls13_hrr_senders; + break; + + default: + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + for (; sender->ex_sender != NULL; ++sender) { + PRBool append = PR_FALSE; + unsigned int start = buf->len; + unsigned int length; + + if (ssl_FindCustomExtensionHooks(ss, sender->ex_type)) { + continue; + } + + /* Save space for the extension type and length. Note that we don't grow + * the buffer now; rely on sslBuffer_Append* to do that. */ + buf->len += 4; + rv = (*sender->ex_sender)(ss, &ss->xtnData, buf, &append); + if (rv != SECSuccess) { + goto loser; + } + + /* Save the length and go back to the start. */ + length = buf->len - start - 4; + buf->len = start; + if (!append) { + continue; + } + + buf->len = start; + rv = sslBuffer_AppendNumber(buf, sender->ex_type, 2); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + rv = sslBuffer_AppendNumber(buf, length, 2); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + /* Skip over the extension body. */ + buf->len += length; + + if (message == ssl_hs_client_hello || + message == ssl_hs_certificate_request) { + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = + sender->ex_type; + } + } + + if (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) { + rv = ssl_CallCustomExtensionSenders(ss, buf, message); + if (rv != SECSuccess) { + goto loser; + } + } + + if (buf->len > 0xffff) { + PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG); + goto loser; + } + + return SECSuccess; + +loser: + sslBuffer_Clear(buf); + return SECFailure; +} + +/* This extension sender can be used anywhere that an always empty extension is + * needed. Mostly that is for ServerHello where sender registration is dynamic; + * ClientHello senders are usually conditional in some way. */ +SECStatus +ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append) +{ + *append = PR_TRUE; + return SECSuccess; +} + +/* Takes the size of the ClientHello, less the record header, and determines how + * much padding is required. */ +static unsigned int +ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength) +{ + unsigned int recordLength = 1 /* handshake message type */ + + 3 /* handshake message length */ + + clientHelloLength; + unsigned int extensionLen; + + /* Don't pad for DTLS, for SSLv3, or for renegotiation. */ + if (IS_DTLS(ss) || + ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 || + ss->firstHsDone) { + return 0; + } + + /* A padding extension may be included to ensure that the record containing + * the ClientHello doesn't have a length between 256 and 511 bytes + * (inclusive). Initial ClientHello records with such lengths trigger bugs + * in F5 devices. */ + if (recordLength < 256 || recordLength >= 512) { + return 0; + } + + extensionLen = 512 - recordLength; + /* Extensions take at least four bytes to encode. Always include at least + * one byte of data if we are padding. Some servers will time out or + * terminate the connection if the last ClientHello extension is empty. */ + if (extensionLen < 5) { + extensionLen = 5; + } + + return extensionLen - 4; +} + +/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a + * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures + * that we don't trigger bugs in F5 products. + * + * This takes an existing extension buffer, |buf|, and the length of the + * remainder of the ClientHello, |prefixLen|. It modifies the extension buffer + * to insert padding at the right place. + */ +SECStatus +ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen, + sslBuffer *buf) +{ + static unsigned char padding[252] = { 0 }; + unsigned int paddingLen; + unsigned int tailLen; + SECStatus rv; + + /* Account for the size of the header, the length field of the extensions + * block and the size of the existing extensions. */ + paddingLen = ssl_CalculatePaddingExtLen(ss, prefixLen + 2 + buf->len); + if (!paddingLen) { + return SECSuccess; + } + + /* Move the tail if there is one. This only happens if we are sending the + * TLS 1.3 PSK extension, which needs to be at the end. */ + if (ss->xtnData.lastXtnOffset) { + PORT_Assert(buf->len > ss->xtnData.lastXtnOffset); + tailLen = buf->len - ss->xtnData.lastXtnOffset; + rv = sslBuffer_Grow(buf, buf->len + 4 + paddingLen); + if (rv != SECSuccess) { + return SECFailure; + } + PORT_Memmove(buf->buf + ss->xtnData.lastXtnOffset + 4 + paddingLen, + buf->buf + ss->xtnData.lastXtnOffset, + tailLen); + buf->len = ss->xtnData.lastXtnOffset; + } else { + tailLen = 0; + } + + rv = sslBuffer_AppendNumber(buf, ssl_padding_xtn, 2); + if (rv != SECSuccess) { + return SECFailure; /* Code already set. */ + } + rv = sslBuffer_AppendVariable(buf, padding, paddingLen, 2); + if (rv != SECSuccess) { + return SECFailure; /* Code already set. */ + } + + buf->len += tailLen; + + return SECSuccess; } void @@ -460,52 +914,59 @@ ssl3_DestroyRemoteExtensions(PRCList *list) /* Initialize the extension data block. */ void -ssl3_InitExtensionData(TLSExtensionData *xtnData) +ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) { + unsigned int advertisedMax; + PRCList *cursor; + /* Set things up to the right starting state. */ PORT_Memset(xtnData, 0, sizeof(*xtnData)); xtnData->peerSupportsFfdheGroups = PR_FALSE; PR_INIT_CLIST(&xtnData->remoteKeyShares); + + /* Allocate enough to allow for native extensions, plus any custom ones. */ + if (ss->sec.isServer) { + advertisedMax = PR_MAX(PR_ARRAY_SIZE(certificateRequestHandlers), + PR_ARRAY_SIZE(tls13_cert_req_senders)); + } else { + advertisedMax = PR_MAX(PR_ARRAY_SIZE(clientHelloHandlers), + PR_ARRAY_SIZE(clientHelloSendersTLS)); + ++advertisedMax; /* For the RI SCSV, which we also track. */ + } + for (cursor = PR_NEXT_LINK(&ss->extensionHooks); + cursor != &ss->extensionHooks; + cursor = PR_NEXT_LINK(cursor)) { + ++advertisedMax; + } + xtnData->advertised = PORT_ZNewArray(PRUint16, advertisedMax); } -/* Free everything that has been allocated and then reset back to - * the starting state. */ void -ssl3_ResetExtensionData(TLSExtensionData *xtnData) +ssl3_DestroyExtensionData(TLSExtensionData *xtnData) { - /* Clean up. */ ssl3_FreeSniNameArray(xtnData); - PORT_Free(xtnData->clientSigSchemes); + PORT_Free(xtnData->sigSchemes); SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); tls13_DestroyKeyShares(&xtnData->remoteKeyShares); - - /* Now reinit. */ - ssl3_InitExtensionData(xtnData); -} - -/* Thunks to let extension handlers operate on const sslSocket* objects. */ -SECStatus -ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src, - PRInt32 bytes) -{ - return ssl3_AppendHandshake((sslSocket *)ss, void_src, bytes); -} - -SECStatus -ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num, - PRInt32 lenSize) -{ - return ssl3_AppendHandshakeNumber((sslSocket *)ss, num, lenSize); + SECITEM_FreeItem(&xtnData->certReqContext, PR_FALSE); + SECITEM_FreeItem(&xtnData->applicationToken, PR_FALSE); + if (xtnData->certReqAuthorities.arena) { + PORT_FreeArena(xtnData->certReqAuthorities.arena, PR_FALSE); + xtnData->certReqAuthorities.arena = NULL; + } + PORT_Free(xtnData->advertised); } -SECStatus -ssl3_ExtAppendHandshakeVariable(const sslSocket *ss, - const PRUint8 *src, PRInt32 bytes, - PRInt32 lenSize) +/* Free everything that has been allocated and then reset back to + * the starting state. */ +void +ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) { - return ssl3_AppendHandshakeVariable((sslSocket *)ss, src, bytes, lenSize); + ssl3_DestroyExtensionData(xtnData); + ssl3_InitExtensionData(xtnData, ss); } +/* Thunks to let extension handlers operate on const sslSocket* objects. */ void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h index 90407375a..d0f75a599 100644 --- a/security/nss/lib/ssl/ssl3ext.h +++ b/security/nss/lib/ssl/ssl3ext.h @@ -9,54 +9,38 @@ #ifndef __ssl3ext_h_ #define __ssl3ext_h_ +#include "sslencode.h" + typedef enum { sni_nametype_hostname } SNINameType; typedef struct TLSExtensionDataStr TLSExtensionData; -/* registerable callback function that either appends extension to buffer +/* Registerable callback function that either appends extension to buffer * or returns length of data that it would have appended. */ -typedef PRInt32 (*ssl3HelloExtensionSenderFunc)(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); - -/* registerable callback function that handles a received extension, - * of the given type. - */ -typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss, - TLSExtensionData *xtnData, - PRUint16 ex_type, - SECItem *data); +typedef SECStatus (*sslExtensionBuilderFunc)(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); /* row in a table of hello extension senders */ typedef struct { PRInt32 ex_type; - ssl3HelloExtensionSenderFunc ex_sender; -} ssl3HelloExtensionSender; - -/* row in a table of hello extension handlers */ -typedef struct { - PRInt32 ex_type; - ssl3ExtensionHandlerFunc ex_handler; -} ssl3ExtensionHandler; + sslExtensionBuilderFunc ex_sender; +} sslExtensionBuilder; struct TLSExtensionDataStr { /* registered callbacks that send server hello extensions */ - ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS]; - ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS]; - ssl3HelloExtensionSender certificateSenders[SSL_MAX_EXTENSIONS]; + sslExtensionBuilder serverHelloSenders[SSL_MAX_EXTENSIONS]; + sslExtensionBuilder encryptedExtensionsSenders[SSL_MAX_EXTENSIONS]; + sslExtensionBuilder certificateSenders[SSL_MAX_EXTENSIONS]; - /* Keep track of the extensions that are negotiated. */ + /* Keep track of the extensions that are advertised or negotiated. */ PRUint16 numAdvertised; + PRUint16 *advertised; /* Allocated dynamically. */ PRUint16 numNegotiated; - PRUint16 advertised[SSL_MAX_EXTENSIONS]; PRUint16 negotiated[SSL_MAX_EXTENSIONS]; - /* Amount of padding we need to add. */ - PRUint16 paddingLen; - /* SessionTicket Extension related data. */ PRBool ticketTimestampVerified; PRBool emptySessionTicket; @@ -86,10 +70,13 @@ struct TLSExtensionDataStr { PRBool peerSupportsFfdheGroups; /* if the peer supports named ffdhe groups */ /* clientSigAndHash contains the contents of the signature_algorithms - * extension (if any) from the client. This is only valid for TLS 1.2 - * or later. */ - SSLSignatureScheme *clientSigSchemes; - unsigned int numClientSigScheme; + * extension (if any) the other side supports. This is only valid for TLS + * 1.2 or later. In TLS 1.3, it is also used for CertificateRequest. */ + SSLSignatureScheme *sigSchemes; + unsigned int numSigSchemes; + + SECItem certReqContext; + CERTDistNames certReqAuthorities; /* In a client: if the server supports Next Protocol Negotiation, then * this is the protocol that was negotiated. @@ -99,9 +86,18 @@ struct TLSExtensionDataStr { PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */ - SECItem pskBinder; /* The PSK binder for the first PSK (TLS 1.3) */ - unsigned long pskBinderPrefixLen; /* The length of the binder input. */ - PRCList remoteKeyShares; /* The other side's public keys (TLS 1.3) */ + unsigned int lastXtnOffset; /* Where to insert padding. 0 = end. */ + PRCList remoteKeyShares; /* The other side's public keys (TLS 1.3) */ + + /* The following are used by a TLS 1.3 server. */ + SECItem pskBinder; /* The binder for the first PSK. */ + unsigned int pskBindersLen; /* The length of the binders. */ + PRUint32 ticketAge; /* Used to accept early data. */ + SECItem cookie; /* HRR Cookie. */ + const sslNamedGroupDef *selectedGroup; /* For HRR. */ + /* The application token contains a value that was passed to the client via + * a session ticket, or the cookie in a HelloRetryRequest. */ + SECItem applicationToken; }; typedef struct TLSExtensionStr { @@ -110,40 +106,44 @@ typedef struct TLSExtensionStr { SECItem data; /* Pointers into the handshake data. */ } TLSExtension; +typedef struct sslCustomExtensionHooks { + PRCList link; + PRUint16 type; + SSLExtensionWriter writer; + void *writerArg; + SSLExtensionHandler handler; + void *handlerArg; +} sslCustomExtensionHooks; + SECStatus ssl3_HandleExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length, - SSL3HandshakeType handshakeMessage); + SSLHandshakeType handshakeMessage); SECStatus ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length); SECStatus ssl3_HandleParsedExtensions(sslSocket *ss, - SSL3HandshakeType handshakeMessage); + SSLHandshakeType handshakeMessage); TLSExtension *ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type); void ssl3_DestroyRemoteExtensions(PRCList *list); -void ssl3_InitExtensionData(TLSExtensionData *xtnData); -void ssl3_ResetExtensionData(TLSExtensionData *xtnData); +void ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss); +void ssl3_DestroyExtensionData(TLSExtensionData *xtnData); +void ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss); PRBool ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type); -PRBool ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type); +PRBool ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type); SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - ssl3HelloExtensionSenderFunc cb); -PRInt32 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, - const ssl3HelloExtensionSender *sender); - -void ssl3_CalculatePaddingExtLen(sslSocket *ss, - unsigned int clientHelloLength); + sslExtensionBuilderFunc cb); +SECStatus ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, + SSLHandshakeType message); +SECStatus ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen, + sslBuffer *buf); /* Thunks to let us operate on const sslSocket* objects. */ -SECStatus ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src, - PRInt32 bytes); -SECStatus ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num, - PRInt32 lenSize); -SECStatus ssl3_ExtAppendHandshakeVariable(const sslSocket *ss, - const PRUint8 *src, PRInt32 bytes, - PRInt32 lenSize); void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc); void ssl3_ExtDecodeError(const sslSocket *ss); @@ -156,4 +156,10 @@ SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i, PRUint32 bytes, PRUint8 **b, PRUint32 *length); +SECStatus SSLExp_GetExtensionSupport(PRUint16 type, + SSLExtensionSupport *support); +SECStatus SSLExp_InstallExtensionHooks( + PRFileDesc *fd, PRUint16 extension, SSLExtensionWriter writer, + void *writerArg, SSLExtensionHandler handler, void *handlerArg); + #endif diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index 370bd8b3e..c0fbda7ab 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -13,7 +13,6 @@ #include "blapit.h" #include "prinit.h" #include "selfencrypt.h" -#include "ssl3encode.h" #include "ssl3ext.h" #include "ssl3exthandle.h" #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */ @@ -22,70 +21,48 @@ * unless that name is a dotted decimal string. * Used by client and server. */ -PRInt32 -ssl3_SendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { + unsigned int len; + PRNetAddr netAddr; SECStatus rv; - if (!ss) - return 0; - if (!ss->sec.isServer) { - PRUint32 len; - PRNetAddr netAddr; - - /* must have a hostname */ - if (!ss->url || !ss->url[0]) - return 0; - /* must not be an IPv4 or IPv6 address */ - if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { - /* is an IP address (v4 or v6) */ - return 0; - } - len = PORT_Strlen(ss->url); - if (append && maxBytes >= len + 9) { - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_ExtAppendHandshakeNumber(ss, len + 5, 2); - if (rv != SECSuccess) - return -1; - /* length of server_name_list */ - rv = ssl3_ExtAppendHandshakeNumber(ss, len + 3, 2); - if (rv != SECSuccess) - return -1; - /* Name Type (sni_host_name) */ - rv = ssl3_ExtAppendHandshake(ss, "\0", 1); - if (rv != SECSuccess) - return -1; - /* HostName (length and value) */ - rv = ssl3_ExtAppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - xtnData->advertised[xtnData->numAdvertised++] = - ssl_server_name_xtn; - } - } - return len + 9; + + /* must have a hostname */ + if (!ss->url || !ss->url[0]) { + return SECSuccess; } - /* Server side */ - if (append && maxBytes >= 4) { - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; + /* must not be an IPv4 or IPv6 address */ + if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) { + /* is an IP address (v4 or v6) */ + return SECSuccess; + } + len = PORT_Strlen(ss->url); + /* length of server_name_list */ + rv = sslBuffer_AppendNumber(buf, len + 3, 2); + if (rv != SECSuccess) { + return SECFailure; + } + /* Name Type (sni_host_name) */ + rv = sslBuffer_AppendNumber(buf, 0, 1); + if (rv != SECSuccess) { + return SECFailure; + } + /* HostName (length and value) */ + rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)ss->url, len, 2); + if (rv != SECSuccess) { + return SECFailure; } - return 4; + + *added = PR_TRUE; + return SECSuccess; } /* Handle an incoming SNI extension. */ SECStatus -ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECItem *names = NULL; PRUint32 listLenBytes = 0; @@ -194,88 +171,54 @@ ssl3_FreeSniNameArray(TLSExtensionData *xtnData) * sends an empty ticket. Servers always send empty tickets. */ PRInt32 -ssl3_SendSessionTicketXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; NewSessionTicket *session_ticket = NULL; sslSessionID *sid = ss->sec.ci.sid; + SECStatus rv; + + PORT_Assert(!ss->sec.isServer); /* Never send an extension with a ticket for TLS 1.3, but * OK to send the empty one in case the server does 1.2. */ if (sid->cached == in_client_cache && sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - return 0; + return SECSuccess; } /* Ignore the SessionTicket extension if processing is disabled. */ - if (!ss->opt.enableSessionTickets) - return 0; - - /* Empty extension length = extension_type (2-bytes) + - * length(extension_data) (2-bytes) - */ - extension_length = 4; + if (!ss->opt.enableSessionTickets) { + return SECSuccess; + } - /* If we are a client then send a session ticket if one is availble. - * Servers that support the extension and are willing to negotiate the - * the extension always respond with an empty extension. + /* Send a session ticket if one is available. + * + * The caller must be holding sid->u.ssl3.lock for reading. We cannot + * just acquire and release the lock within this function because the + * caller will call this function twice, and we need the inputs to be + * consistent between the two calls. Note that currently the caller + * will only be holding the lock when we are the client and when we're + * attempting to resume an existing session. */ - if (!ss->sec.isServer) { - /* The caller must be holding sid->u.ssl3.lock for reading. We cannot - * just acquire and release the lock within this function because the - * caller will call this function twice, and we need the inputs to be - * consistent between the two calls. Note that currently the caller - * will only be holding the lock when we are the client and when we're - * attempting to resume an existing session. - */ + session_ticket = &sid->u.ssl3.locked.sessionTicket; + if (session_ticket->ticket.data && + (xtnData->ticketTimestampVerified || + ssl_TicketTimeValid(session_ticket))) { - session_ticket = &sid->u.ssl3.locked.sessionTicket; - if (session_ticket->ticket.data) { - if (xtnData->ticketTimestampVerified) { - extension_length += session_ticket->ticket.len; - } else if (!append && ssl_TicketTimeValid(session_ticket)) { - extension_length += session_ticket->ticket.len; - xtnData->ticketTimestampVerified = PR_TRUE; - } - } - } + xtnData->ticketTimestampVerified = PR_FALSE; - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; - } - if (append) { - SECStatus rv; - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2); - if (rv != SECSuccess) - goto loser; - if (session_ticket && session_ticket->ticket.data && - xtnData->ticketTimestampVerified) { - rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data, - session_ticket->ticket.len, 2); - xtnData->ticketTimestampVerified = PR_FALSE; - xtnData->sentSessionTicketInClientHello = PR_TRUE; - } else { - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + rv = sslBuffer_Append(buf, session_ticket->ticket.data, + session_ticket->ticket.len); + if (rv != SECSuccess) { + return SECFailure; } - if (rv != SECSuccess) - goto loser; - if (!ss->sec.isServer) { - xtnData->advertised[xtnData->numAdvertised++] = - ssl_session_ticket_xtn; - } + xtnData->sentSessionTicketInClientHello = PR_TRUE; } - return extension_length; -loser: - xtnData->ticketTimestampVerified = PR_FALSE; - return -1; + *added = PR_TRUE; + return SECSuccess; } PRBool @@ -301,16 +244,18 @@ ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag) /* handle an incoming Next Protocol Negotiation extension. */ SECStatus -ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +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++] = ex_type; + 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 @@ -344,7 +289,7 @@ ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length) /* protocol selection handler for ALPN (server side) and NPN (client side) */ static SECStatus ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data) + PRUint16 extension, SECItem *data) { SECStatus rv; unsigned char resultBuffer[255]; @@ -381,7 +326,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); - if (ex_type == ssl_app_layer_protocol_xtn && + 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. */ @@ -390,13 +335,14 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = extension; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result); } /* handle an incoming ALPN extension at the server */ SECStatus -ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { PRUint32 count; SECStatus rv; @@ -423,15 +369,16 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU return SECSuccess; } - rv = ssl3_SelectAppProtocol(ss, xtnData, ex_type, data); + rv = ssl3_SelectAppProtocol(ss, xtnData, ssl_app_layer_protocol_xtn, data); if (rv != SECSuccess) { return rv; } /* prepare to send back a response, if we negotiated */ if (xtnData->nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) { - rv = ssl3_RegisterExtensionSender( - ss, xtnData, ex_type, ssl3_ServerSendAppProtoXtn); + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_app_layer_protocol_xtn, + ssl3_ServerSendAppProtoXtn); if (rv != SECSuccess) { ssl3_ExtSendAlert(ss, alert_fatal, internal_error); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -442,9 +389,10 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU } SECStatus -ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +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)) { @@ -470,11 +418,12 @@ ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECFailure; } - return ssl3_SelectAppProtocol(ss, xtnData, ex_type, data); + return ssl3_SelectAppProtocol(ss, xtnData, ssl_next_proto_nego_xtn, data); } SECStatus -ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; PRUint32 list_len; @@ -521,265 +470,168 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED; - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name); } -PRInt32 -ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - /* Renegotiations do not send this extension. */ if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) { - return 0; - } - - extension_length = 4; - - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - if (append) { - SECStatus rv; - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - goto loser; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_next_proto_nego_xtn; + return SECSuccess; } - return extension_length; - -loser: - return -1; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - unsigned char *alpn_protos = NULL; + SECStatus rv; + const unsigned int len = ss->opt.nextProtoNego.len; /* Renegotiations do not send this extension. */ if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) { - return 0; + return SECSuccess; } - extension_length = 2 /* extension type */ + 2 /* extension length */ + - 2 /* protocol name list length */ + - ss->opt.nextProtoNego.len; + /* 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 (maxBytes < (PRUint32)extension_length) { - return 0; - } - if (append) { - /* NPN requires that the client's fallback protocol is first in the - * list. However, ALPN sends protocols in preference order. So we - * allocate a buffer and move the first protocol to the end of the - * list. */ - SECStatus rv; - const unsigned int len = ss->opt.nextProtoNego.len; + if (len > 0) { + /* Each protocol string is prefixed with a single byte length. */ + unsigned int i; - alpn_protos = PORT_Alloc(len); - if (alpn_protos == NULL) { + rv = sslBuffer_AppendNumber(buf, len, 2); + if (rv != SECSuccess) { return SECFailure; } - if (len > 0) { - /* Each protocol string is prefixed with a single byte length. */ - unsigned int i = ss->opt.nextProtoNego.data[0] + 1; - if (i <= len) { - memcpy(alpn_protos, &ss->opt.nextProtoNego.data[i], len - i); - memcpy(alpn_protos + len - i, ss->opt.nextProtoNego.data, i); - } else { - /* This seems to be invalid data so we'll send as-is. */ - memcpy(alpn_protos, ss->opt.nextProtoNego.data, len); - } - } - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2); - if (rv != SECSuccess) { - goto loser; - } - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) { - goto loser; - } - rv = ssl3_ExtAppendHandshakeVariable(ss, alpn_protos, len, 2); - PORT_Free(alpn_protos); - alpn_protos = NULL; - if (rv != SECSuccess) { - goto loser; + 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; + } } - xtnData->advertised[xtnData->numAdvertised++] = - ssl_app_layer_protocol_xtn; } - return extension_length; - -loser: - if (alpn_protos) { - PORT_Free(alpn_protos); - } - return -1; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; + SECStatus rv; - /* we're in over our heads if any of these fail */ + /* We're in over our heads if any of these fail */ PORT_Assert(ss->opt.enableALPN); PORT_Assert(xtnData->nextProto.data); PORT_Assert(xtnData->nextProto.len > 0); PORT_Assert(xtnData->nextProtoState == SSL_NEXT_PROTO_NEGOTIATED); PORT_Assert(!ss->firstHsDone); - extension_length = 2 /* extension type */ + 2 /* extension length */ + - 2 /* protocol name list */ + 1 /* name length */ + - xtnData->nextProto.len; - - if (maxBytes < (PRUint32)extension_length) { - return 0; + rv = sslBuffer_AppendNumber(buf, xtnData->nextProto.len + 1, 2); + if (rv != SECSuccess) { + return SECFailure; } - if (append) { - SECStatus rv; - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->nextProto.len + 1, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_ExtAppendHandshakeVariable(ss, xtnData->nextProto.data, - xtnData->nextProto.len, 1); - if (rv != SECSuccess) { - return -1; - } + rv = sslBuffer_AppendVariable(buf, xtnData->nextProto.data, + xtnData->nextProto.len, 1); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { - ssl3HelloExtensionSenderFunc sender; + sslExtensionBuilderFunc sender; PORT_Assert(ss->sec.isServer); /* remember that we got this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { sender = tls13_ServerSendStatusRequestXtn; } else { sender = ssl3_ServerSendStatusRequestXtn; } - return ssl3_RegisterExtensionSender(ss, xtnData, ex_type, sender); + return ssl3_RegisterExtensionSender(ss, xtnData, ssl_cert_status_xtn, sender); } -PRInt32 -ssl3_ServerSendStatusRequestXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; const sslServerCert *serverCert = ss->sec.serverCert; - SECStatus rv; if (!serverCert->certStatusArray || !serverCert->certStatusArray->len) { - return 0; - } - - extension_length = 2 + 2; - if (maxBytes < (PRUint32)extension_length) { - return 0; - } - if (append) { - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - /* The certificate status data is sent in ssl3_SendCertificateStatus. */ + return SECSuccess; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } /* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the * client side. See RFC 6066 section 8. */ -PRInt32 -ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - - if (!ss->opt.enableOCSPStapling) - return 0; - - /* extension_type (2-bytes) + - * length(extension_data) (2-bytes) + - * status_type (1) + - * responder_id_list length (2) + - * request_extensions length (2) - */ - extension_length = 9; + SECStatus rv; - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; + if (!ss->opt.enableOCSPStapling) { + return SECSuccess; } - if (append) { - SECStatus rv; - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - return -1; - rv = ssl3_ExtAppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1); - if (rv != SECSuccess) - return -1; - /* A zero length responder_id_list means that the responders are - * implicitly known to the server. */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - /* A zero length request_extensions means that there are no extensions. - * Specifically, we don't set the id-pkix-ocsp-nonce extension. This - * means that the server can replay a cached OCSP response to us. */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - - xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn; + rv = sslBuffer_AppendNumber(buf, 1 /* status_type ocsp */, 1); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + /* A zero length responder_id_list means that the responders are + * implicitly known to the server. */ + rv = sslBuffer_AppendNumber(buf, 0, 2); + if (rv != SECSuccess) { + return SECFailure; + } + /* A zero length request_extensions means that there are no extensions. + * Specifically, we don't set the id-pkix-ocsp-nonce extension. This + * means that the server can replay a cached OCSP response to us. */ + rv = sslBuffer_AppendNumber(buf, 0, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { /* In TLS 1.3, the extension carries the OCSP response. */ @@ -797,36 +649,32 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; return SECSuccess; } PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ -#define TLS_EX_SESS_TICKET_VERSION (0x0105) +#define TLS_EX_SESS_TICKET_VERSION (0x010a) /* * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket */ SECStatus -ssl3_EncodeSessionTicket(sslSocket *ss, - const NewSessionTicket *ticket, - SECItem *ticket_data) +ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, + const PRUint8 *appToken, unsigned int appTokenLen, + PK11SymKey *secret, SECItem *ticket_data) { SECStatus rv; - SECItem plaintext; - SECItem plaintext_item = { 0, NULL, 0 }; - PRUint32 plaintext_length; + sslBuffer plaintext = SSL_BUFFER_EMPTY; SECItem ticket_buf = { 0, NULL, 0 }; - PRBool ms_is_wrapped; + sslSessionID sid; unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; SECItem ms_item = { 0, NULL, 0 }; - PRUint32 cert_length = 0; - PRUint32 now; + PRTime now; SECItem *srvName = NULL; - CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, - * must be >= 0 */ - ssl3CipherSpec *spec; + CK_MECHANISM_TYPE msWrapMech; SECItem *alpnSelection = NULL; + PRUint32 ticketAgeBaseline; SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake", SSL_GETPID(), ss->fd)); @@ -834,107 +682,69 @@ ssl3_EncodeSessionTicket(sslSocket *ss, PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len; - } + /* Extract the master secret wrapped. */ - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - spec = ss->ssl3.cwSpec; - } else { - spec = ss->ssl3.pwSpec; - } - if (spec->msItem.len && spec->msItem.data) { - /* The master secret is available unwrapped. */ - ms_item.data = spec->msItem.data; - ms_item.len = spec->msItem.len; - ms_is_wrapped = PR_FALSE; - } else { - /* Extract the master secret wrapped. */ - sslSessionID sid; - PORT_Memset(&sid, 0, sizeof(sslSessionID)); + PORT_Memset(&sid, 0, sizeof(sslSessionID)); - rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec); - if (rv == SECSuccess) { - if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) - goto loser; - memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret, - sid.u.ssl3.keys.wrapped_master_secret_len); - ms_item.data = wrapped_ms; - ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len; - msWrapMech = sid.u.ssl3.masterWrapMech; - } else { - /* TODO: else send an empty ticket. */ + PORT_Assert(secret); + rv = ssl3_CacheWrappedSecret(ss, &sid, secret); + if (rv == SECSuccess) { + if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) goto loser; - } - ms_is_wrapped = PR_TRUE; + memcpy(wrapped_ms, sid.u.ssl3.keys.wrapped_master_secret, + sid.u.ssl3.keys.wrapped_master_secret_len); + ms_item.data = wrapped_ms; + ms_item.len = sid.u.ssl3.keys.wrapped_master_secret_len; + msWrapMech = sid.u.ssl3.masterWrapMech; + } else { + /* TODO: else send an empty ticket. */ + goto loser; } /* Prep to send negotiated name */ srvName = &ss->sec.ci.sid->u.ssl3.srvName; - PORT_Assert(ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED || - ss->xtnData.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED || - ss->xtnData.nextProto.len == 0); - alpnSelection = &ss->xtnData.nextProto; - - plaintext_length = - sizeof(PRUint16) /* ticket version */ - + sizeof(SSL3ProtocolVersion) /* ssl_version */ - + sizeof(ssl3CipherSuite) /* ciphersuite */ - + 1 /* compression */ - + 10 /* cipher spec parameters */ - + 1 /* certType arguments */ - + 1 /* SessionTicket.ms_is_wrapped */ - + 4 /* msWrapMech */ - + 2 /* master_secret.length */ - + ms_item.len /* master_secret */ - + 1 /* client_auth_type */ - + cert_length /* cert */ - + 2 + srvName->len /* name len + length field */ - + 1 /* extendedMasterSecretUsed */ - + sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */ - + sizeof(ticket->flags) /* ticket flags */ - + 1 + alpnSelection->len /* alpn value + length field */ - + 4; /* maxEarlyData */ - - if (SECITEM_AllocItem(NULL, &plaintext_item, plaintext_length) == NULL) - goto loser; - - plaintext = plaintext_item; - /* ticket version */ - rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION, - sizeof(PRUint16)); + rv = sslBuffer_AppendNumber(&plaintext, TLS_EX_SESS_TICKET_VERSION, + sizeof(PRUint16)); if (rv != SECSuccess) goto loser; /* ssl_version */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->version, - sizeof(SSL3ProtocolVersion)); + rv = sslBuffer_AppendNumber(&plaintext, ss->version, + sizeof(SSL3ProtocolVersion)); if (rv != SECSuccess) goto loser; /* ciphersuite */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.cipher_suite, - sizeof(ssl3CipherSuite)); + rv = sslBuffer_AppendNumber(&plaintext, ss->ssl3.hs.cipher_suite, + sizeof(ssl3CipherSuite)); if (rv != SECSuccess) goto loser; - /* compression */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1); + /* cipher spec parameters */ + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authType, 1); if (rv != SECSuccess) goto loser; - - /* cipher spec parameters */ - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authType, 1); + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authKeyBits, 4); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4); + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaType, 1); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1); + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaKeyBits, 4); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4); + if (ss->sec.keaGroup) { + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaGroup->name, 4); + if (rv != SECSuccess) + goto loser; + } else { + /* No kea group. Write 0 as invalid value. */ + rv = sslBuffer_AppendNumber(&plaintext, 0, 4); + if (rv != SECSuccess) + goto loser; + } + rv = sslBuffer_AppendNumber(&plaintext, ss->sec.signatureScheme, 4); if (rv != SECSuccess) goto loser; @@ -945,102 +755,120 @@ ssl3_EncodeSessionTicket(sslSocket *ss, PORT_Assert(cert->namedCurve); /* EC curves only use the second of the two bytes. */ PORT_Assert(cert->namedCurve->name < 256); - rv = ssl3_AppendNumberToItem(&plaintext, cert->namedCurve->name, 1); + rv = sslBuffer_AppendNumber(&plaintext, cert->namedCurve->name, 1); } else { - rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); + rv = sslBuffer_AppendNumber(&plaintext, 0, 1); } if (rv != SECSuccess) goto loser; /* master_secret */ - rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4); + rv = sslBuffer_AppendNumber(&plaintext, msWrapMech, 4); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len); + rv = sslBuffer_AppendVariable(&plaintext, ms_item.data, ms_item.len, 2); if (rv != SECSuccess) goto loser; /* client identity */ if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); - if (rv != SECSuccess) - goto loser; - rv = ssl3_AppendNumberToItem(&plaintext, - ss->sec.ci.sid->peerCert->derCert.len, 2); + rv = sslBuffer_AppendNumber(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendToItem(&plaintext, - ss->sec.ci.sid->peerCert->derCert.data, - ss->sec.ci.sid->peerCert->derCert.len); + rv = sslBuffer_AppendVariable(&plaintext, + ss->sec.ci.sid->peerCert->derCert.data, + ss->sec.ci.sid->peerCert->derCert.len, 2); if (rv != SECSuccess) goto loser; } else { - rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); + rv = sslBuffer_AppendNumber(&plaintext, 0, 1); if (rv != SECSuccess) goto loser; } /* timestamp */ - now = ssl_Time(); - rv = ssl3_AppendNumberToItem(&plaintext, now, - sizeof(ticket->ticket_lifetime_hint)); + now = ssl_TimeUsec(); + PORT_Assert(sizeof(now) == 8); + rv = sslBuffer_AppendNumber(&plaintext, now, 8); if (rv != SECSuccess) goto loser; /* HostName (length and value) */ - rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); + rv = sslBuffer_AppendVariable(&plaintext, srvName->data, srvName->len, 2); if (rv != SECSuccess) goto loser; - if (srvName->len) { - rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len); - if (rv != SECSuccess) - goto loser; - } /* extendedMasterSecretUsed */ - rv = ssl3_AppendNumberToItem( + rv = sslBuffer_AppendNumber( &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1); if (rv != SECSuccess) goto loser; /* Flags */ - rv = ssl3_AppendNumberToItem(&plaintext, ticket->flags, - sizeof(ticket->flags)); + rv = sslBuffer_AppendNumber(&plaintext, ticket->flags, + sizeof(ticket->flags)); if (rv != SECSuccess) goto loser; /* ALPN value. */ + PORT_Assert(ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED || + ss->xtnData.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED || + ss->xtnData.nextProto.len == 0); + alpnSelection = &ss->xtnData.nextProto; PORT_Assert(alpnSelection->len < 256); - rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection->len, 1); + rv = sslBuffer_AppendVariable(&plaintext, alpnSelection->data, + alpnSelection->len, 1); if (rv != SECSuccess) goto loser; - if (alpnSelection->len) { - rv = ssl3_AppendToItem(&plaintext, alpnSelection->data, - alpnSelection->len); - if (rv != SECSuccess) - goto loser; - } - rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4); + rv = sslBuffer_AppendNumber(&plaintext, ssl_max_early_data_size, 4); if (rv != SECSuccess) goto loser; - /* Check that we are totally full. */ - PORT_Assert(plaintext.len == 0); + /* + * We store this in the ticket: + * ticket_age_baseline = 1rtt - ticket_age_add + * + * When the client resumes, it will provide: + * obfuscated_age = ticket_age_client + ticket_age_add + * + * We expect to receive the ticket at: + * ticket_create + 1rtt + ticket_age_server + * + * We calculate the client's estimate of this as: + * ticket_create + ticket_age_baseline + obfuscated_age + * = ticket_create + 1rtt + ticket_age_client + * + * This is compared to the expected time, which should differ only as a + * result of clock errors or errors in the RTT estimate. + */ + ticketAgeBaseline = (ssl_TimeUsec() - ss->ssl3.hs.serverHelloTime) / PR_USEC_PER_MSEC; + ticketAgeBaseline -= ticket->ticket_age_add; + rv = sslBuffer_AppendNumber(&plaintext, ticketAgeBaseline, 4); + if (rv != SECSuccess) + goto loser; + + /* Application token */ + rv = sslBuffer_AppendVariable(&plaintext, appToken, appTokenLen, 2); + if (rv != SECSuccess) + goto loser; + + /* This really only happens if appTokenLen is too much, and that always + * comes from the using application. */ + if (SSL_BUFFER_LEN(&plaintext) > 0xffff) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } - /* 128 just gives us enough room for overhead. */ - if (SECITEM_AllocItem(NULL, &ticket_buf, plaintext_length + 128) == NULL) { + ticket_buf.len = ssl_SelfEncryptGetProtectedSize(SSL_BUFFER_LEN(&plaintext)); + PORT_Assert(ticket_buf.len > 0); + if (SECITEM_AllocItem(NULL, &ticket_buf, ticket_buf.len) == NULL) { goto loser; } /* Finally, encrypt the ticket. */ - rv = ssl_SelfEncryptProtect(ss, plaintext_item.data, plaintext_item.len, + rv = ssl_SelfEncryptProtect(ss, SSL_BUFFER_BASE(&plaintext), + SSL_BUFFER_LEN(&plaintext), ticket_buf.data, &ticket_buf.len, ticket_buf.len); if (rv != SECSuccess) { goto loser; @@ -1049,13 +877,11 @@ ssl3_EncodeSessionTicket(sslSocket *ss, /* Give ownership of memory to caller. */ *ticket_data = ticket_buf; - SECITEM_FreeItem(&plaintext_item, PR_FALSE); + sslBuffer_Clear(&plaintext); return SECSuccess; loser: - if (plaintext_item.data) { - SECITEM_FreeItem(&plaintext_item, PR_FALSE); - } + sslBuffer_Clear(&plaintext); if (ticket_buf.data) { SECITEM_FreeItem(&ticket_buf, PR_FALSE); } @@ -1067,18 +893,22 @@ loser: * message is expected during the handshake. */ SECStatus -ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); + if (data->len != 0) { return SECSuccess; /* Ignore the extension. */ } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn; return SECSuccess; } +PR_STATIC_ASSERT((TLS_EX_SESS_TICKET_VERSION >> 8) == 1); + static SECStatus ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, SessionTicket *parsedTicket) @@ -1105,6 +935,12 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, return SECFailure; } + /* All ticket versions start with 0x01, so check to see if this + * is a ticket or some other self-encrypted thing. */ + if ((temp >> 8) != 1) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + return SECFailure; + } /* Skip the ticket if the version is wrong. This won't result in a * handshake failure, just a failure to resume. */ if (temp != TLS_EX_SESS_TICKET_VERSION) { @@ -1132,14 +968,6 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, } parsedTicket->cipher_suite = (ssl3CipherSuite)temp; - /* Read compression_method. */ - rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - parsedTicket->compression_method = (SSLCompressionMethod)temp; - /* Read cipher spec parameters. */ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); if (rv != SECSuccess) { @@ -1165,6 +993,18 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, return SECFailure; } parsedTicket->keaKeyBits = temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->originalKeaGroup = temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->signatureScheme = (SSLSignatureScheme)temp; /* Read the optional named curve. */ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); @@ -1185,14 +1025,6 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, } /* Read the master secret (and how it is wrapped). */ - rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - PORT_Assert(temp == PR_TRUE || temp == PR_FALSE); - parsedTicket->ms_is_wrapped = (PRBool)temp; - rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -1240,13 +1072,21 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - /* Read timestamp. */ + + /* Read timestamp. This is a 64-bit value and + * ssl3_ExtConsumeHandshakeNumber only reads 32-bits at a time. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->timestamp = (PRTime)temp << 32; rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - parsedTicket->timestamp = temp; + parsedTicket->timestamp |= (PRTime)temp; /* Read server name */ rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->srvName, 2, @@ -1287,6 +1127,20 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, } parsedTicket->maxEarlyData = temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->ticketAgeBaseline = temp; + + rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->applicationToken, + 2, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + #ifndef UNSAFE_FUZZER_MODE /* Done parsing. Check that all bytes have been consumed. */ if (len != 0) { @@ -1313,13 +1167,15 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket, /* Copy over parameters. */ sid->version = parsedTicket->ssl_version; + sid->creationTime = parsedTicket->timestamp; sid->u.ssl3.cipherSuite = parsedTicket->cipher_suite; - sid->u.ssl3.compression = parsedTicket->compression_method; sid->authType = parsedTicket->authType; sid->authKeyBits = parsedTicket->authKeyBits; sid->keaType = parsedTicket->keaType; sid->keaKeyBits = parsedTicket->keaKeyBits; + sid->keaGroup = parsedTicket->originalKeaGroup; sid->namedCurve = parsedTicket->namedCurve; + sid->sigScheme = parsedTicket->signatureScheme; rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket, rawTicket); @@ -1338,7 +1194,6 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket, parsedTicket->master_secret, parsedTicket->ms_length); sid->u.ssl3.keys.wrapped_master_secret_len = parsedTicket->ms_length; sid->u.ssl3.masterWrapMech = parsedTicket->msWrapMech; - sid->u.ssl3.keys.msIsWrapped = parsedTicket->ms_is_wrapped; sid->u.ssl3.masterValid = PR_TRUE; sid->u.ssl3.keys.resumable = PR_TRUE; sid->u.ssl3.keys.extendedMasterSecretUsed = parsedTicket->extendedMasterSecretUsed; @@ -1381,10 +1236,12 @@ loser: /* Generic ticket processing code, common to all TLS versions. */ SECStatus -ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) +ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, + SECItem *appToken) { SECItem decryptedTicket = { siBuffer, NULL, 0 }; SessionTicket parsedTicket; + sslSessionID *sid = NULL; SECStatus rv; if (ss->sec.ci.sid != NULL) { @@ -1393,12 +1250,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) ss->sec.ci.sid = NULL; } - if (!SECITEM_AllocItem(NULL, &decryptedTicket, data->len)) { + if (!SECITEM_AllocItem(NULL, &decryptedTicket, ticket->len)) { return SECFailure; } /* Decrypt the ticket. */ - rv = ssl_SelfEncryptUnprotect(ss, data->data, data->len, + rv = ssl_SelfEncryptUnprotect(ss, ticket->data, ticket->len, decryptedTicket.data, &decryptedTicket.len, decryptedTicket.len); @@ -1428,16 +1285,28 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) } /* Use the ticket if it is valid and unexpired. */ - if (parsedTicket.valid && - parsedTicket.timestamp + ssl_ticket_lifetime > ssl_Time()) { - sslSessionID *sid; + if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC > + ssl_TimeUsec()) { - rv = ssl_CreateSIDFromTicket(ss, data, &parsedTicket, &sid); + rv = ssl_CreateSIDFromTicket(ss, ticket, &parsedTicket, &sid); if (rv != SECSuccess) { goto loser; /* code already set */ } + if (appToken && parsedTicket.applicationToken.len) { + rv = SECITEM_CopyItem(NULL, appToken, + &parsedTicket.applicationToken); + if (rv != SECSuccess) { + goto loser; /* code already set */ + } + } + ss->statelessResume = PR_TRUE; ss->sec.ci.sid = sid; + + /* We have the baseline value for the obfuscated ticket age here. Save + * that in xtnData temporarily. This value is updated in + * tls13_ServerHandlePreSharedKeyXtn with the final estimate. */ + ss->xtnData.ticketAge = parsedTicket.ticketAgeBaseline; } SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); @@ -1445,15 +1314,19 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) return SECSuccess; loser: + if (sid) { + ssl_FreeSID(sid); + } SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket)); return SECFailure; } SECStatus -ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); /* Ignore the SessionTicket extension if processing is disabled. */ if (!ss->opt.enableSessionTickets) { @@ -1466,7 +1339,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn; /* Parse the received ticket sent in by the client. We are * lenient about some parse errors, falling back to a fullshake @@ -1477,7 +1350,8 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } - return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data); + return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data, + NULL); } /* Extension format: @@ -1487,60 +1361,45 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData * Verify Data (TLS): 12 bytes (client) or 24 bytes (server) * Verify Data (SSL): 36 bytes (client) or 72 bytes (server) */ -PRInt32 -ssl3_SendRenegotiationInfoXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { PRInt32 len = 0; - PRInt32 needed; + SECStatus rv; - /* In draft-ietf-tls-renegotiation-03, it is NOT RECOMMENDED to send - * both the SCSV and the empty RI, so when we send SCSV in - * the initial handshake, we don't also send RI. + /* In RFC 5746, it is NOT RECOMMENDED to send both the SCSV and the empty + * RI, so when we send SCSV in the initial handshake, we don't also send RI. */ - if (!ss || ss->ssl3.hs.sendingSCSV) + if (ss->ssl3.hs.sendingSCSV) { return 0; + } if (ss->firstHsDone) { len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 : ss->ssl3.hs.finishedBytes; } - needed = 5 + len; - if (maxBytes < (PRUint32)needed) { - return 0; - } - if (append) { - SECStatus rv; - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_ExtAppendHandshakeNumber(ss, len + 1, 2); - if (rv != SECSuccess) - return -1; - /* verify_Data from previous Finished message(s) */ - rv = ssl3_ExtAppendHandshakeVariable(ss, - ss->ssl3.hs.finishedMsgs.data, len, 1); - if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - xtnData->advertised[xtnData->numAdvertised++] = - ssl_renegotiation_info_xtn; - } + + /* verify_Data from previous Finished message(s) */ + rv = sslBuffer_AppendVariable(buf, + ss->ssl3.hs.finishedMsgs.data, len, 1); + if (rv != SECSuccess) { + return SECFailure; } - return needed; + + *added = PR_TRUE; + return SECSuccess; } /* This function runs in both the client and server. */ SECStatus -ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv = SECSuccess; PRUint32 len = 0; + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); + if (ss->firstHsDone) { len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes : ss->ssl3.hs.finishedBytes * 2; @@ -1558,97 +1417,78 @@ ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, /* remember that we got this extension and it was correct. */ CONST_CAST(sslSocket, ss) ->peerRequestedProtection = 1; - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_renegotiation_info_xtn; if (ss->sec.isServer) { /* prepare to send back the appropriate response */ - rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_renegotiation_info_xtn, ssl3_SendRenegotiationInfoXtn); } return rv; } -PRInt32 -ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRUint32 ext_data_len; - PRInt16 i; + unsigned int i; SECStatus rv; - if (!ss) - return 0; - - if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) - return 0; /* Not relevant */ - - ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1; + if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) { + return SECSuccess; /* Not relevant */ + } - if (append && maxBytes >= 4 + ext_data_len) { - /* Extension type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2); - if (rv != SECSuccess) - return -1; - /* Length of extension data */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ext_data_len, 2); - if (rv != SECSuccess) - return -1; - /* Length of the SRTP cipher list */ - rv = ssl3_ExtAppendHandshakeNumber(ss, - 2 * ss->ssl3.dtlsSRTPCipherCount, - 2); - if (rv != SECSuccess) - return -1; - /* The SRTP ciphers */ - for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) { - rv = ssl3_ExtAppendHandshakeNumber(ss, - ss->ssl3.dtlsSRTPCiphers[i], - 2); - if (rv != SECSuccess) - return -1; + /* Length of the SRTP cipher list */ + rv = sslBuffer_AppendNumber(buf, 2 * ss->ssl3.dtlsSRTPCipherCount, 2); + if (rv != SECSuccess) { + return SECFailure; + } + /* The SRTP ciphers */ + for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) { + rv = sslBuffer_AppendNumber(buf, ss->ssl3.dtlsSRTPCiphers[i], 2); + if (rv != SECSuccess) { + return SECFailure; } - /* Empty MKI value */ - ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); - - xtnData->advertised[xtnData->numAdvertised++] = - ssl_use_srtp_xtn; + } + /* Empty MKI value */ + rv = sslBuffer_AppendNumber(buf, 0, 1); + if (rv != SECSuccess) { + return SECFailure; } - return 4 + ext_data_len; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { SECStatus rv; - /* Server side */ - if (!append || maxBytes < 9) { - return 9; - } - - /* Extension type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2); - if (rv != SECSuccess) - return -1; - /* Length of extension data */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 5, 2); - if (rv != SECSuccess) - return -1; /* Length of the SRTP cipher list */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2); - if (rv != SECSuccess) - return -1; + rv = sslBuffer_AppendNumber(buf, 2, 2); + if (rv != SECSuccess) { + return SECFailure; + } /* The selected cipher */ - rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->dtlsSRTPCipherSuite, 2); - if (rv != SECSuccess) - return -1; + rv = sslBuffer_AppendNumber(buf, xtnData->dtlsSRTPCipherSuite, 2); + if (rv != SECSuccess) { + return SECFailure; + } /* Empty MKI value */ - ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); + rv = sslBuffer_AppendNumber(buf, 0, 1); + if (rv != SECSuccess) { + return SECFailure; + } - return 9; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1718,7 +1558,8 @@ ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi } SECStatus -ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1789,11 +1630,12 @@ ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi ssl3_ServerSendUseSRTPXtn); } -/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension - * from a client. - * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ +/* ssl3_HandleSigAlgsXtn handles the signature_algorithms extension from a + * client. In TLS 1.3, the client uses this to parse CertificateRequest + * extensions. See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ SECStatus -ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; @@ -1802,15 +1644,15 @@ ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi return SECSuccess; } - if (xtnData->clientSigSchemes) { - PORT_Free(xtnData->clientSigSchemes); - xtnData->clientSigSchemes = NULL; + if (xtnData->sigSchemes) { + PORT_Free(xtnData->sigSchemes); + xtnData->sigSchemes = NULL; } rv = ssl_ParseSignatureSchemes(ss, NULL, - &xtnData->clientSigSchemes, - &xtnData->numClientSigScheme, + &xtnData->sigSchemes, + &xtnData->numSigSchemes, &data->data, &data->len); - if (rv != SECSuccess || xtnData->numClientSigScheme == 0) { + if (rv != SECSuccess || xtnData->numSigSchemes == 0) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); return SECFailure; @@ -1823,177 +1665,52 @@ ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_signature_algorithms_xtn; return SECSuccess; } /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS * 1.2 ClientHellos. */ -PRInt32 -ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - PRUint8 buf[MAX_SIGNATURE_SCHEMES * 2]; - PRUint32 len; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) { - return 0; - } - - rv = ssl3_EncodeSigAlgs(ss, buf, sizeof(buf), &len); - if (rv != SECSuccess) { - return -1; - } - - extension_length = - 2 /* extension type */ + - 2 /* extension length */ + - 2 /* supported_signature_algorithms length */ + - len; - - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - SECStatus rv; - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_ExtAppendHandshakeNumber(ss, len + 2, 2); - if (rv != SECSuccess) { - return -1; - } - - rv = ssl3_ExtAppendHandshakeVariable(ss, buf, len, 2); - if (rv != SECSuccess) { - return -1; - } - - xtnData->advertised[xtnData->numAdvertised++] = - ssl_signature_algorithms_xtn; - } - - return extension_length; -} - -/* Takes the size of the ClientHello, less the record header, and determines how - * much padding is required. */ -void -ssl3_CalculatePaddingExtLen(sslSocket *ss, - unsigned int clientHelloLength) -{ - unsigned int recordLength = 1 /* handshake message type */ + - 3 /* handshake message length */ + - clientHelloLength; - unsigned int extensionLen; - - /* Don't pad for DTLS, for SSLv3, or for renegotiation. */ - if (IS_DTLS(ss) || - ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 || - ss->firstHsDone) { - return; - } - - /* A padding extension may be included to ensure that the record containing - * the ClientHello doesn't have a length between 256 and 511 bytes - * (inclusive). Initial ClientHello records with such lengths trigger bugs - * in F5 devices. */ - if (recordLength < 256 || recordLength >= 512) { - return; - } - - extensionLen = 512 - recordLength; - /* Extensions take at least four bytes to encode. Always include at least - * one byte of data if we are padding. Some servers will time out or - * terminate the connection if the last ClientHello extension is empty. */ - if (extensionLen < 4 + 1) { - extensionLen = 4 + 1; - } - - ss->xtnData.paddingLen = extensionLen - 4; -} - -/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a - * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures - * that we don't trigger bugs in F5 products. */ -PRInt32 -ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes) -{ - static unsigned char padding[252] = { 0 }; - unsigned int extensionLen; - SECStatus rv; - - /* On the length-calculation pass, report zero total length. The record - * will be larger on the second pass if needed. */ - if (!append || !xtnData->paddingLen) { - return 0; - } - - extensionLen = xtnData->paddingLen + 4; - if (extensionLen > maxBytes || - xtnData->paddingLen > sizeof(padding)) { - PORT_Assert(0); - return -1; + return SECSuccess; } - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2); - if (rv != SECSuccess) { - return -1; - } - rv = ssl3_ExtAppendHandshakeVariable(ss, padding, xtnData->paddingLen, 2); + rv = ssl3_EncodeSigAlgs(ss, buf); if (rv != SECSuccess) { - return -1; + return SECFailure; } - return extensionLen; + *added = PR_TRUE; + return SECSuccess; } -PRInt32 -ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - if (!ss->opt.enableExtendedMS) { - return 0; + return SECSuccess; } /* Always send the extension in this function, since the * client always sends it and this function is only called on * the server if we negotiated the extension. */ - extension_length = 4; /* Type + length (0) */ - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - SECStatus rv; - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - goto loser; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_extended_master_secret_xtn; - } - - return extension_length; - -loser: - return -1; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) { return SECSuccess; } @@ -2013,54 +1730,34 @@ ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnDat SSL_GETPID(), ss->fd)); /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_extended_master_secret_xtn; if (ss->sec.isServer) { - return ssl3_RegisterExtensionSender( - ss, xtnData, ex_type, ssl3_SendExtendedMasterSecretXtn); + return ssl3_RegisterExtensionSender(ss, xtnData, + ssl_extended_master_secret_xtn, + ssl_SendEmptyExtension); } return SECSuccess; } /* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp * extension for TLS ClientHellos. */ -PRInt32 -ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length = 2 /* extension_type */ + - 2 /* length(extension_data) */; - /* Only send the extension if processing is enabled. */ - if (!ss->opt.enableSignedCertTimestamps) - return 0; - - if (append && maxBytes >= extension_length) { - SECStatus rv; - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, - ssl_signed_cert_timestamp_xtn, - 2); - if (rv != SECSuccess) - goto loser; - /* zero length */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - goto loser; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_signed_cert_timestamp_xtn; - } else if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; + if (!ss->opt.enableSignedCertTimestamps) { + return SECSuccess; } - return extension_length; -loser: - return -1; + *added = PR_TRUE; + return SECSuccess; } SECStatus -ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { /* We do not yet know whether we'll be resuming a session or creating @@ -2080,54 +1777,34 @@ ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *x } *scts = *data; /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; return SECSuccess; } -PRInt32 +SECStatus ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps; + SECStatus rv; if (!scts->len) { /* No timestamps to send */ - return 0; + return SECSuccess; } - extension_length = 2 /* extension_type */ + - 2 /* length(extension_data) */ + - scts->len; - - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - if (append) { - SECStatus rv; - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, - ssl_signed_cert_timestamp_xtn, - 2); - if (rv != SECSuccess) { - return -1; - } - /* extension_data */ - rv = ssl3_ExtAppendHandshakeVariable(ss, scts->data, scts->len, 2); - if (rv != SECSuccess) { - return -1; - } + rv = sslBuffer_Append(buf, scts->data, scts->len); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data) { if (data->len != 0) { @@ -2136,22 +1813,25 @@ ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; PORT_Assert(ss->sec.isServer); - return ssl3_RegisterExtensionSender( - ss, xtnData, ex_type, ssl3_ServerSendSignedCertTimestampXtn); + return ssl3_RegisterExtensionSender(ss, xtnData, + ssl_signed_cert_timestamp_xtn, + ssl3_ServerSendSignedCertTimestampXtn); } /* Just make sure that the remote client supports uncompressed points, * Since that is all we support. Disable ECC cipher suites if it doesn't. */ SECStatus -ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data) { int i; + PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); + if (data->len < 2 || data->len > 255 || !data->data || data->len != (unsigned int)data->data[0] + 1) { ssl3_ExtDecodeError(ss); @@ -2160,10 +1840,9 @@ ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnDa for (i = data->len; --i > 0;) { if (data->data[i] == 0) { /* indicate that we should send a reply */ - SECStatus rv; - rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, - &ssl3_SendSupportedPointFormatsXtn); - return rv; + return ssl3_RegisterExtensionSender( + ss, xtnData, ssl_ec_point_formats_xtn, + &ssl3_SendSupportedPointFormatsXtn); } } @@ -2248,7 +1927,7 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) */ SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data) + SECItem *data) { SECStatus rv; @@ -2258,7 +1937,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, /* TLS 1.3 permits the server to send this extension so make it so. */ if (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, + rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn); if (rv != SECSuccess) { return SECFailure; /* error already set. */ @@ -2266,7 +1945,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Remember that we negotiated this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn; return SECSuccess; } diff --git a/security/nss/lib/ssl/ssl3exthandle.h b/security/nss/lib/ssl/ssl3exthandle.h index 5fdbe9053..b84bd074c 100644 --- a/security/nss/lib/ssl/ssl3exthandle.h +++ b/security/nss/lib/ssl/ssl3exthandle.h @@ -9,90 +9,114 @@ #ifndef __ssl3exthandle_h_ #define __ssl3exthandle_h_ -PRInt32 ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); -SECStatus ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +#include "sslencode.h" + +SECStatus ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -PRInt32 ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -PRInt32 ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -PRInt32 ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -PRInt32 ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -SECStatus ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +SECStatus ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ClientSendAppProtoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ServerSendAppProtoXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); -SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -PRInt32 ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -SECStatus ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - SECItem *data); +SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data); -PRInt32 ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); +SECStatus ssl3_ClientSendPaddingExtension(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); -PRInt32 ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data); -PRInt32 ssl3_SendServerNameXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -SECStatus ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -PRInt32 ssl3_SendSessionTicketXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); - -PRInt32 ssl_SendSupportedGroupsXtn(const sslSocket *ss, +SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, + /* out */ SECItem *appToken); +SECStatus ssl3_ClientSendServerNameXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); -PRInt32 ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss, + SECItem *data); +SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); + sslBuffer *buf, PRBool *added); + +SECStatus ssl_SendSupportedGroupsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus ssl3_SendSupportedPointFormatsXtn(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 cf6f4cb33..20404f4da 100644 --- a/security/nss/lib/ssl/ssl3gthr.c +++ b/security/nss/lib/ssl/ssl3gthr.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Gather (Read) entire SSL3 records from socket into buffer. * @@ -98,7 +99,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs) PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); if (gs->state == GS_INIT) { gs->state = GS_HEADER; - gs->remainder = ss->ssl3.hs.shortHeaders ? 2 : 5; + gs->remainder = 5; gs->offset = 0; gs->writeOffset = 0; gs->readOffset = 0; @@ -156,19 +157,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs) /* Should have a non-SSLv2 record header in gs->hdr. Extract * the length of the following encrypted data, and then * read in the rest of the record into gs->inbuf. */ - if (ss->ssl3.hs.shortHeaders) { - PRUint16 len = (gs->hdr[0] << 8) | gs->hdr[1]; - if (!(len & 0x8000)) { - SSL_DBG(("%d: SSL3[%d]: incorrectly formatted header")); - SSL3_SendAlert(ss, alert_fatal, illegal_parameter); - gs->state = GS_INIT; - PORT_SetError(SSL_ERROR_BAD_MAC_READ); - return SECFailure; - } - gs->remainder = len & ~0x8000; - } else { - gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4]; - } + gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4]; } else { /* Probably an SSLv2 record header. No need to handle any * security escapes (gs->hdr[0] & 0x40) as we wouldn't get @@ -361,6 +350,9 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags) } } + 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; @@ -394,7 +386,8 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) SSL3Ciphertext cText; PRBool keepGoing = PR_TRUE; - SSL_TRC(30, ("ssl3_GatherCompleteHandshake")); + SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake", + SSL_GETPID(), ss->fd)); /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake, * which requires the 1stHandshakeLock, which must be acquired before the @@ -405,9 +398,12 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) do { PRBool handleRecordNow = PR_FALSE; + PRBool processingEarlyData; ssl_GetSSL3HandshakeLock(ss); + processingEarlyData = ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted; + /* Without this, we may end up wrongly reporting * SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the * peer while we are waiting to be restarted. @@ -493,18 +489,12 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) * If it's a change cipher spec, alert, or handshake message, * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess. */ - if (ss->ssl3.hs.shortHeaders) { - cText.type = content_application_data; - cText.version = SSL_LIBRARY_VERSION_TLS_1_0; - } else { - cText.type = (SSL3ContentType)ss->gs.hdr[0]; - cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2]; - } + 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; - cText.version = dtls_DTLSVersionToTLSVersion(cText.version); /* DTLS sequence number */ PORT_Memcpy(&seq_num, &ss->gs.hdr[3], sizeof(seq_num)); cText.seq_num = PR_ntohll(seq_num); @@ -555,12 +545,22 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) } else { ss->ssl3.hs.canFalseStart = PR_FALSE; } + } else if (processingEarlyData && + ss->ssl3.hs.zeroRttState == ssl_0rtt_done && + !PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) { + /* If we were processing early data and we are no longer, then force + * the handshake to block. This ensures that early data is + * delivered to the application before the handshake completes. */ + ssl_ReleaseSSL3HandshakeLock(ss); + PORT_SetError(PR_WOULD_BLOCK_ERROR); + return SECWouldBlock; } ssl_ReleaseSSL3HandshakeLock(ss); } while (keepGoing); - /* Service the DTLS timer so that the holddown timer eventually fires. */ - if (IS_DTLS(ss)) { + /* Service the DTLS timer so that the post-handshake timers + * fire. */ + if (IS_DTLS(ss) && (ss->ssl3.hs.ws == idle_handshake)) { dtls_CheckTimer(ss); } ss->gs.readOffset = 0; diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index ac31cf263..d1f46db97 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -16,13 +16,12 @@ 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 18 +#define TLS_1_3_DRAFT_VERSION 23 typedef PRUint16 ssl3CipherSuite; /* The cipher suites are defined in sslproto.h */ #define MAX_CERT_TYPES 10 -#define MAX_COMPRESSION_METHODS 10 #define MAX_MAC_LENGTH 64 #define MAX_PADDING_LENGTH 64 #define MAX_KEY_LENGTH 64 @@ -30,7 +29,6 @@ typedef PRUint16 ssl3CipherSuite; #define SSL3_RANDOM_LENGTH 32 #define SSL3_RECORD_HEADER_LENGTH 5 -#define TLS13_RECORD_HEADER_LENGTH_SHORT 2 /* SSL3_RECORD_HEADER_LENGTH + epoch/sequence_number */ #define DTLS_RECORD_HEADER_LENGTH 13 @@ -41,47 +39,18 @@ typedef enum { content_change_cipher_spec = 20, content_alert = 21, content_handshake = 22, - content_application_data = 23 + content_application_data = 23, + content_alt_handshake = 24, + content_ack = 25 } SSL3ContentType; -typedef struct { - SSL3ContentType type; - SSL3ProtocolVersion version; - PRUint16 length; - SECItem fragment; -} SSL3Plaintext; - -typedef struct { - SSL3ContentType type; - SSL3ProtocolVersion version; - PRUint16 length; - SECItem fragment; -} SSL3Compressed; - -typedef struct { - SECItem content; - PRUint8 MAC[MAX_MAC_LENGTH]; -} SSL3GenericStreamCipher; - -typedef struct { - SECItem content; - PRUint8 MAC[MAX_MAC_LENGTH]; - PRUint8 padding[MAX_PADDING_LENGTH]; - PRUint8 padding_length; -} SSL3GenericBlockCipher; - typedef enum { change_cipher_spec_choice = 1 } SSL3ChangeCipherSpecChoice; -typedef struct { - SSL3ChangeCipherSpecChoice choice; -} SSL3ChangeCipherSpec; - typedef enum { alert_warning = 1, alert_fatal = 2 } SSL3AlertLevel; typedef enum { close_notify = 0, - end_of_early_data = 1, /* TLS 1.3 */ unexpected_message = 10, bad_record_mac = 20, decryption_failed_RESERVED = 21, /* do not send; see RFC 5246 */ @@ -122,64 +91,13 @@ typedef enum { no_alert = 256 } SSL3AlertDescription; -typedef struct { - SSL3AlertLevel level; - SSL3AlertDescription description; -} SSL3Alert; - -typedef enum { - hello_request = 0, - client_hello = 1, - server_hello = 2, - hello_verify_request = 3, - new_session_ticket = 4, - hello_retry_request = 6, - encrypted_extensions = 8, - certificate = 11, - server_key_exchange = 12, - certificate_request = 13, - server_hello_done = 14, - certificate_verify = 15, - client_key_exchange = 16, - finished = 20, - certificate_status = 22, - next_proto = 67 -} SSL3HandshakeType; - -typedef struct { - PRUint8 empty; -} SSL3HelloRequest; - -typedef struct { - PRUint8 rand[SSL3_RANDOM_LENGTH]; -} SSL3Random; +typedef PRUint8 SSL3Random[SSL3_RANDOM_LENGTH]; typedef struct { PRUint8 id[32]; PRUint8 length; } SSL3SessionID; -typedef struct { - SSL3ProtocolVersion client_version; - SSL3Random random; - SSL3SessionID session_id; - SECItem cipher_suites; - PRUint8 cm_count; - SSLCompressionMethod compression_methods[MAX_COMPRESSION_METHODS]; -} SSL3ClientHello; - -typedef struct { - SSL3ProtocolVersion server_version; - SSL3Random random; - SSL3SessionID session_id; - ssl3CipherSuite cipher_suite; - SSLCompressionMethod compression_method; -} SSL3ServerHello; - -typedef struct { - SECItem list; -} SSL3Certificate; - /* SSL3SignType moved to ssl.h */ /* The SSL key exchange method used */ @@ -201,24 +119,6 @@ typedef enum { kea_tls13_any, } SSL3KeyExchangeAlgorithm; -typedef struct { - SECItem modulus; - SECItem exponent; -} SSL3ServerRSAParams; - -typedef struct { - SECItem p; - SECItem g; - SECItem Ys; -} SSL3ServerDHParams; - -typedef struct { - union { - SSL3ServerDHParams dh; - SSL3ServerRSAParams rsa; - } u; -} SSL3ServerParams; - /* SSL3HashesIndividually contains a combination MD5/SHA1 hash, as used in TLS * prior to 1.2. */ typedef struct { @@ -235,17 +135,9 @@ typedef struct { union { PRUint8 raw[64]; SSL3HashesIndividually s; - unsigned int transcriptLen; } u; } SSL3Hashes; -typedef struct { - union { - PRUint8 anonymous; - SSL3Hashes certified; - } u; -} SSL3ServerKeyExchange; - typedef enum { ct_RSA_sign = 1, ct_DSS_sign = 2, @@ -256,16 +148,8 @@ typedef enum { ct_ECDSA_sign = 64, ct_RSA_fixed_ECDH = 65, ct_ECDSA_fixed_ECDH = 66 - } SSL3ClientCertificateType; -typedef struct { - PRUint8 client_version[2]; - PRUint8 random[46]; -} SSL3RSAPreMasterSecret; - -typedef PRUint8 SSL3MasterSecret[48]; - typedef enum { sender_client = 0x434c4e54, sender_server = 0x53525652 diff --git a/security/nss/lib/ssl/sslbloom.c b/security/nss/lib/ssl/sslbloom.c new file mode 100644 index 000000000..3d5f9d1f1 --- /dev/null +++ b/security/nss/lib/ssl/sslbloom.c @@ -0,0 +1,94 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * A bloom filter. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "sslbloom.h" +#include "prnetdb.h" +#include "secport.h" + +static inline unsigned int +sslBloom_Size(unsigned int bits) +{ + return (bits >= 3) ? (1 << (bits - 3)) : 1; +} + +SECStatus +sslBloom_Init(sslBloomFilter *filter, unsigned int k, unsigned int bits) +{ + PORT_Assert(filter); + PORT_Assert(bits > 0); + PORT_Assert(bits <= sizeof(PRUint32) * 8); + PORT_Assert(k > 0); + + filter->filter = PORT_ZNewArray(PRUint8, sslBloom_Size(bits)); + if (!filter->filter) { + return SECFailure; /* Error code already set. */ + } + + filter->k = k; + filter->bits = bits; + return SECSuccess; +} + +void +sslBloom_Zero(sslBloomFilter *filter) +{ + PORT_Memset(filter->filter, 0, sslBloom_Size(filter->bits)); +} + +void +sslBloom_Fill(sslBloomFilter *filter) +{ + PORT_Memset(filter->filter, 0xff, sslBloom_Size(filter->bits)); +} + +static PRBool +sslBloom_AddOrCheck(sslBloomFilter *filter, const PRUint8 *hashes, PRBool add) +{ + unsigned int iteration; + unsigned int bitIndex; + PRUint32 tmp = 0; + PRUint8 mask; + unsigned int bytes = (filter->bits + 7) / 8; + unsigned int shift = (bytes * 8) - filter->bits; + PRBool found = PR_TRUE; + + PORT_Assert(bytes <= sizeof(unsigned int)); + + for (iteration = 0; iteration < filter->k; ++iteration) { + PORT_Memcpy(((PRUint8 *)&tmp) + (sizeof(tmp) - bytes), + hashes, bytes); + hashes += bytes; + bitIndex = PR_ntohl(tmp) >> shift; + + mask = 1 << (bitIndex % 8); + found = found && filter->filter[bitIndex / 8] & mask; + if (add) { + filter->filter[bitIndex / 8] |= mask; + } + } + return found; +} + +PRBool +sslBloom_Add(sslBloomFilter *filter, const PRUint8 *hashes) +{ + return sslBloom_AddOrCheck(filter, hashes, PR_TRUE); +} + +PRBool +sslBloom_Check(sslBloomFilter *filter, const PRUint8 *hashes) +{ + return sslBloom_AddOrCheck(filter, hashes, PR_FALSE); +} + +void +sslBloom_Destroy(sslBloomFilter *filter) +{ + PORT_Free(filter->filter); + PORT_Memset(filter, 0, sizeof(*filter)); +} diff --git a/security/nss/lib/ssl/sslbloom.h b/security/nss/lib/ssl/sslbloom.h new file mode 100644 index 000000000..032c94b0f --- /dev/null +++ b/security/nss/lib/ssl/sslbloom.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * A bloom filter. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __sslbloom_h_ +#define __sslbloom_h_ + +#include "prtypes.h" +#include "seccomon.h" + +typedef struct sslBloomFilterStr { + unsigned int k; /* The number of hashes. */ + unsigned int bits; /* The number of bits in each hash: bits = log2(m) */ + PRUint8 *filter; /* The filter itself. */ +} sslBloomFilter; + +SECStatus sslBloom_Init(sslBloomFilter *filter, unsigned int k, unsigned int bits); +void sslBloom_Zero(sslBloomFilter *filter); +void sslBloom_Fill(sslBloomFilter *filter); +/* Add the given hashes to the filter. It's the caller's responsibility to + * ensure that there is at least |ceil(k*bits/8)| bytes of data available in + * |hashes|. Returns PR_TRUE if the entry was already present or it was likely + * to be present. */ +PRBool sslBloom_Add(sslBloomFilter *filter, const PRUint8 *hashes); +PRBool sslBloom_Check(sslBloomFilter *filter, const PRUint8 *hashes); +void sslBloom_Destroy(sslBloomFilter *filter); + +#endif /* __sslbloom_h_ */ diff --git a/security/nss/lib/ssl/sslcert.c b/security/nss/lib/ssl/sslcert.c index cc1d3c683..6cd02e402 100644 --- a/security/nss/lib/ssl/sslcert.c +++ b/security/nss/lib/ssl/sslcert.c @@ -46,7 +46,7 @@ ssl_SetupCAListOnce(void *arg) } SECStatus -ssl_SetupCAList(sslSocket *ss) +ssl_SetupCAList(const sslSocket *ss) { if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_server_ca_list.setup, &ssl_SetupCAListOnce, @@ -58,11 +58,11 @@ ssl_SetupCAList(sslSocket *ss) } SECStatus -ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calen, - SECItem **names, unsigned int *nnames) +ssl_GetCertificateRequestCAs(const sslSocket *ss, unsigned int *calen, + const SECItem **names, unsigned int *nnames) { - SECItem *name; - CERTDistNames *ca_list; + const SECItem *name; + const CERTDistNames *ca_list; unsigned int i; *calen = 0; diff --git a/security/nss/lib/ssl/sslencode.c b/security/nss/lib/ssl/sslencode.c new file mode 100644 index 000000000..2f127fe8f --- /dev/null +++ b/security/nss/lib/ssl/sslencode.c @@ -0,0 +1,296 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nss.h" +#include "prnetdb.h" +#include "ssl.h" +#include "sslimpl.h" + +/* Helper function to encode an unsigned integer into a buffer. */ +static void +ssl_EncodeUintX(PRUint8 *to, PRUint64 value, unsigned int bytes) +{ + PRUint64 encoded; + + PORT_Assert(bytes > 0 && bytes <= sizeof(encoded)); + + encoded = PR_htonll(value); + PORT_Memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), + bytes); +} + +/* Grow a buffer to hold newLen bytes of data. When used for recv/xmit buffers, + * the caller must hold xmitBufLock or recvBufLock, as appropriate. */ +SECStatus +sslBuffer_Grow(sslBuffer *b, unsigned int newLen) +{ + if (b->fixed) { + PORT_Assert(newLen <= b->space); + if (newLen > b->space) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return SECSuccess; + } + + newLen = PR_MAX(newLen, b->len + 1024); + if (newLen > b->space) { + unsigned char *newBuf; + if (b->buf) { + newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen); + } else { + newBuf = (unsigned char *)PORT_Alloc(newLen); + } + if (!newBuf) { + return SECFailure; + } + b->buf = newBuf; + b->space = newLen; + } + return SECSuccess; +} + +SECStatus +sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len) +{ + SECStatus rv = sslBuffer_Grow(b, b->len + len); + if (rv != SECSuccess) { + return SECFailure; /* Code already set. */ + } + PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len); + b->len += len; + return SECSuccess; +} + +SECStatus +sslBuffer_AppendNumber(sslBuffer *b, PRUint64 v, unsigned int size) +{ + SECStatus rv = sslBuffer_Grow(b, b->len + size); + if (rv != SECSuccess) { + return SECFailure; + } + ssl_EncodeUintX(SSL_BUFFER_NEXT(b), v, size); + b->len += size; + return SECSuccess; +} + +SECStatus +sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len, + unsigned int size) +{ + PORT_Assert(size <= 4 && size > 0); + if (len >= (1ULL << (8 * size))) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + if (sslBuffer_Grow(b, b->len + len + size) != SECSuccess) { + return SECFailure; + } + + ssl_EncodeUintX(SSL_BUFFER_NEXT(b), len, size); + b->len += size; + PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len); + b->len += len; + return SECSuccess; +} + +SECStatus +sslBuffer_AppendBuffer(sslBuffer *b, const sslBuffer *append) +{ + return sslBuffer_Append(b, append->buf, append->len); +} + +SECStatus +sslBuffer_AppendBufferVariable(sslBuffer *b, const sslBuffer *append, + unsigned int size) +{ + return sslBuffer_AppendVariable(b, append->buf, append->len, size); +} + +SECStatus +sslBuffer_Skip(sslBuffer *b, unsigned int size, unsigned int *savedOffset) +{ + if (sslBuffer_Grow(b, b->len + size) != SECSuccess) { + return SECFailure; + } + + if (savedOffset) { + *savedOffset = b->len; + } + b->len += size; + return SECSuccess; +} + +/* A common problem is that a buffer is used to construct a variable length + * structure of unknown length. The length field for that structure is then + * populated afterwards. This function makes this process a little easier. + * + * To use this, before encoding the variable length structure, skip the spot + * where the length would be using sslBuffer_Skip(). After encoding the + * structure, and before encoding anything else, call this function passing the + * value returned from sslBuffer_Skip() as |at| to have the length inserted. + */ +SECStatus +sslBuffer_InsertLength(sslBuffer *b, unsigned int at, unsigned int size) +{ + unsigned int len; + + PORT_Assert(b->len >= at + size); + PORT_Assert(b->space >= at + size); + len = b->len - (at + size); + + PORT_Assert(size <= 4 && size > 0); + if (len >= (1ULL << (8 * size))) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + ssl_EncodeUintX(SSL_BUFFER_BASE(b) + at, len, size); + return SECSuccess; +} + +void +sslBuffer_Clear(sslBuffer *b) +{ + if (!b->fixed) { + if (b->buf) { + PORT_Free(b->buf); + b->buf = NULL; + } + b->space = 0; + } + b->len = 0; +} + +SECStatus +ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, unsigned int size) +{ + if (size > item->len) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + *buf = item->data; + item->data += size; + item->len -= size; + return SECSuccess; +} + +SECStatus +ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, unsigned int size) +{ + int i; + + if (size > item->len || size > sizeof(*num)) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + *num = 0; + for (i = 0; i < size; i++) { + *num = (*num << 8) + item->data[i]; + } + + item->data += size; + item->len -= size; + + return SECSuccess; +} + +/************************************************************************** + * Append Handshake functions. + * All these functions set appropriate error codes. + * Most rely on ssl3_AppendHandshake to set the error code. + **************************************************************************/ +#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */ +#define MIN_SEND_BUF_LENGTH 4000 + +SECStatus +ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes) +{ + unsigned char *src = (unsigned char *)void_src; + int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len; + SECStatus rv; + + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); /* protects sendBuf. */ + + if (!bytes) + return SECSuccess; + if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) { + rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH, + PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes))); + if (rv != SECSuccess) + return SECFailure; /* sslBuffer_Grow sets a memory error code. */ + room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len; + } + + PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes)); + rv = ssl3_UpdateHandshakeHashes(ss, src, bytes); + if (rv != SECSuccess) + return SECFailure; /* error code set by ssl3_UpdateHandshakeHashes */ + + while (bytes > room) { + if (room > 0) + PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, + room); + ss->sec.ci.sendBuf.len += room; + rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); + if (rv != SECSuccess) { + return SECFailure; /* error code set by ssl3_FlushHandshake */ + } + bytes -= room; + src += room; + room = ss->sec.ci.sendBuf.space; + PORT_Assert(ss->sec.ci.sendBuf.len == 0); + } + PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, bytes); + ss->sec.ci.sendBuf.len += bytes; + return SECSuccess; +} + +SECStatus +ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num, unsigned int lenSize) +{ + PRUint8 b[sizeof(num)]; + SSL_TRC(60, ("%d: number:", SSL_GETPID())); + ssl_EncodeUintX(b, num, lenSize); + return ssl3_AppendHandshake(ss, b, lenSize); +} + +SECStatus +ssl3_AppendHandshakeVariable(sslSocket *ss, const PRUint8 *src, + unsigned int bytes, unsigned int lenSize) +{ + SECStatus rv; + + PORT_Assert((bytes < (1 << 8) && lenSize == 1) || + (bytes < (1L << 16) && lenSize == 2) || + (bytes < (1L << 24) && lenSize == 3)); + + SSL_TRC(60, ("%d: append variable:", SSL_GETPID())); + rv = ssl3_AppendHandshakeNumber(ss, bytes, lenSize); + if (rv != SECSuccess) { + return SECFailure; /* error code set by AppendHandshake. */ + } + SSL_TRC(60, ("data:")); + return ssl3_AppendHandshake(ss, src, bytes); +} + +SECStatus +ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf) +{ + return ssl3_AppendHandshake(ss, buf->buf, buf->len); +} + +SECStatus +ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf, + unsigned int lenSize) +{ + return ssl3_AppendHandshakeVariable(ss, buf->buf, buf->len, lenSize); +} diff --git a/security/nss/lib/ssl/sslencode.h b/security/nss/lib/ssl/sslencode.h new file mode 100644 index 000000000..a1b04d88f --- /dev/null +++ b/security/nss/lib/ssl/sslencode.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __sslencode_h_ +#define __sslencode_h_ + +/* A buffer object, used for assembling messages. */ +typedef struct sslBufferStr { + PRUint8 *buf; + unsigned int len; + unsigned int space; + /* Set to true if the storage for the buffer is fixed, such as a stack + * variable or a view on another buffer. Growing a fixed buffer fails. */ + PRBool fixed; +} sslBuffer; + +#define SSL_BUFFER_EMPTY \ + { \ + NULL, 0, 0, PR_FALSE \ + } +#define SSL_BUFFER_FIXED(b, maxlen) \ + { \ + b, 0, maxlen, PR_TRUE \ + } +#define SSL_BUFFER(b) SSL_BUFFER_FIXED(b, sizeof(b)) +#define SSL_BUFFER_BASE(b) ((b)->buf) +#define SSL_BUFFER_LEN(b) ((b)->len) +#define SSL_BUFFER_NEXT(b) ((b)->buf + (b)->len) +#define SSL_BUFFER_SPACE(b) ((b)->space - (b)->len) + +SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen); +SECStatus sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len); +SECStatus sslBuffer_AppendNumber(sslBuffer *b, PRUint64 v, unsigned int size); +SECStatus sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, + unsigned int len, unsigned int size); +SECStatus sslBuffer_AppendBuffer(sslBuffer *b, const sslBuffer *append); +SECStatus sslBuffer_AppendBufferVariable(sslBuffer *b, const sslBuffer *append, + unsigned int size); +SECStatus sslBuffer_Skip(sslBuffer *b, unsigned int size, + unsigned int *savedOffset); +SECStatus sslBuffer_InsertLength(sslBuffer *b, unsigned int at, + unsigned int size); +void sslBuffer_Clear(sslBuffer *b); + +/* All of these functions modify the underlying SECItem, and so should + * be performed on a shallow copy.*/ +SECStatus ssl3_ConsumeFromItem(SECItem *item, + PRUint8 **buf, unsigned int size); +SECStatus ssl3_ConsumeNumberFromItem(SECItem *item, + PRUint32 *num, unsigned int size); + +SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src, + unsigned int bytes); +SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss, + SSLHandshakeType t, unsigned int length); +SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num, + unsigned int lenSize); +SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss, const PRUint8 *src, + unsigned int bytes, unsigned int lenSize); +SECStatus ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf); +SECStatus ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf, + unsigned int lenSize); + +#endif /* __sslencode_h_ */ diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h index 865077cda..90815dd79 100644 --- a/security/nss/lib/ssl/sslerr.h +++ b/security/nss/lib/ssl/sslerr.h @@ -234,6 +234,7 @@ typedef enum { SSL_ERROR_MALFORMED_PRE_SHARED_KEY = (SSL_ERROR_BASE + 147), SSL_ERROR_MALFORMED_EARLY_DATA = (SSL_ERROR_BASE + 148), SSL_ERROR_END_OF_EARLY_DATA_ALERT = (SSL_ERROR_BASE + 149), + /* error 149 is obsolete */ SSL_ERROR_MISSING_ALPN_EXTENSION = (SSL_ERROR_BASE + 150), SSL_ERROR_RX_UNEXPECTED_EXTENSION = (SSL_ERROR_BASE + 151), SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION = (SSL_ERROR_BASE + 152), @@ -246,6 +247,19 @@ typedef enum { SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 159), SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA = (SSL_ERROR_BASE + 160), SSL_ERROR_TOO_MUCH_EARLY_DATA = (SSL_ERROR_BASE + 161), + SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA = (SSL_ERROR_BASE + 162), + SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA = (SSL_ERROR_BASE + 163), + + SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API = (SSL_ERROR_BASE + 164), + + SSL_ERROR_APPLICATION_ABORT = (SSL_ERROR_BASE + 165), + SSL_ERROR_APP_CALLBACK_ERROR = (SSL_ERROR_BASE + 166), + SSL_ERROR_NO_TIMERS_FOUND = (SSL_ERROR_BASE + 167), + SSL_ERROR_MISSING_COOKIE_EXTENSION = (SSL_ERROR_BASE + 168), + + SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE = (SSL_ERROR_BASE + 169), + SSL_ERROR_RX_MALFORMED_KEY_UPDATE = (SSL_ERROR_BASE + 170), + SSL_ERROR_TOO_MANY_KEY_UPDATES = (SSL_ERROR_BASE + 171), 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/sslexp.h b/security/nss/lib/ssl/sslexp.h new file mode 100644 index 000000000..569add861 --- /dev/null +++ b/security/nss/lib/ssl/sslexp.h @@ -0,0 +1,358 @@ +/* + * This file contains prototypes for experimental SSL functions. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __sslexp_h_ +#define __sslexp_h_ + +#include "ssl.h" +#include "sslerr.h" + +SEC_BEGIN_PROTOS + +/* The functions in this header file are not guaranteed to remain available in + * future NSS versions. Code that uses these functions needs to safeguard + * against the function not being available. */ + +#define SSL_EXPERIMENTAL_API(name, arglist, args) \ + (SSL_GetExperimentalAPI(name) \ + ? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \ + : SECFailure) +#define SSL_DEPRECATED_EXPERIMENTAL_API \ + (PR_SetError(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, 0), SECFailure) + +/* + * SSL_GetExtensionSupport() returns whether NSS supports a particular TLS + * extension. + * + * - ssl_ext_none indicates that NSS does not support the extension and + * extension hooks can be installed. + * + * - ssl_ext_native indicates that NSS supports the extension natively, but + * allows an application to override that support and install its own + * extension hooks. + * + * - ssl_ext_native_only indicates that NSS supports the extension natively + * and does not permit custom extension hooks to be installed. These + * extensions are critical to the functioning of NSS. + */ +typedef enum { + ssl_ext_none, + ssl_ext_native, + ssl_ext_native_only +} SSLExtensionSupport; + +#define SSL_GetExtensionSupport(extension, support) \ + SSL_EXPERIMENTAL_API("SSL_GetExtensionSupport", \ + (PRUint16 _extension, \ + SSLExtensionSupport * _support), \ + (extension, support)) + +/* + * Custom extension hooks. + * + * The SSL_InstallExtensionHooks() registers two callback functions for use + * with the identified extension type. + * + * Installing extension hooks disables the checks in TLS 1.3 that ensure that + * extensions are only added to the correct messages. The application is + * responsible for ensuring that extensions are only sent with the right message + * or messages. + * + * Installing an extension handler does not disable checks for whether an + * extension can be used in a message that is a response to an extension in + * another message. Extensions in ServerHello, EncryptedExtensions and the + * server Certificate messages are rejected unless the client sends an extension + * in the ClientHello. Similarly, a client Certificate message cannot contain + * extensions that don't appear in a CertificateRequest (in TLS 1.3). + * + * Setting both |writer| and |handler| to NULL removes any existing hooks for + * that extension. + * + * == SSLExtensionWriter + * + * An SSLExtensionWriter function is responsible for constructing the contents + * of an extension. This function is called during the construction of all + * handshake messages where an extension might be included. + * + * - The |fd| argument is the socket file descriptor. + * + * - The |message| argument is the TLS handshake message type. The writer will + * be called for every handshake message that NSS sends. Most extensions + * should only be sent in a subset of messages. NSS doesn’t check that + * extension writers don’t violate protocol rules regarding which message an + * extension can be sent in. + * + * - The |data| argument is a pointer to a buffer that should be written to with + * any data for the extension. + * + * - The |len| argument is an outparam indicating how many bytes were written to + * |data|. The value referenced by |len| is initialized to zero, so an + * extension that is empty does not need to write to this value. + * + * - The |maxLen| indicates the maximum number of bytes that can be written to + * |data|. + * + * - The |arg| argument is the value of the writerArg that was passed during + * installation. + * + * An SSLExtensionWriter function returns PR_TRUE if an extension should be + * written, and PR_FALSE otherwise. + * + * If there is an error, return PR_FALSE; if the error is truly fatal, the + * application can mark the connection as failed. However, recursively calling + * functions that alter the file descriptor in the callback - such as PR_Close() + * - should be avoided. + * + * Note: The ClientHello message can be sent twice in TLS 1.3. An + * SSLExtensionWriter will be called twice with the same arguments in that case; + * NSS does not distinguish between a first and second ClientHello. It is up to + * the application to track this if it needs to act differently each time. In + * most cases the correct behaviour is to provide an identical extension on each + * invocation. + * + * == SSLExtensionHandler + * + * An SSLExtensionHandler function consumes a handshake message. This function + * is called when an extension is present. + * + * - The |fd| argument is the socket file descriptor. + * + * - The |message| argument is the TLS handshake message type. This can be used + * to validate that the extension was included in the correct handshake + * message. + * + * - The |data| argument points to the contents of the extension. + * + * - The |len| argument contains the length of the extension. + * + * - The |alert| argument is an outparam that allows an application to choose + * which alert is sent in the case of a fatal error. + * + * - The |arg| argument is the value of the handlerArg that was passed during + * installation. + * + * An SSLExtensionHandler function returns SECSuccess when the extension is + * process successfully. It can return SECFailure to cause the handshake to + * fail. If the value of alert is written to, NSS will generate a fatal alert + * using the provided alert code. The value of |alert| is otherwise not used. + */ +typedef PRBool(PR_CALLBACK *SSLExtensionWriter)( + PRFileDesc *fd, SSLHandshakeType message, + PRUint8 *data, unsigned int *len, unsigned int maxLen, void *arg); + +typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)( + PRFileDesc *fd, SSLHandshakeType message, + const PRUint8 *data, unsigned int len, + SSLAlertDescription *alert, void *arg); + +#define SSL_InstallExtensionHooks(fd, extension, writer, writerArg, \ + handler, handlerArg) \ + SSL_EXPERIMENTAL_API("SSL_InstallExtensionHooks", \ + (PRFileDesc * _fd, PRUint16 _extension, \ + SSLExtensionWriter _writer, void *_writerArg, \ + SSLExtensionHandler _handler, void *_handlerArg), \ + (fd, extension, writer, writerArg, \ + handler, handlerArg)) + +/* + * Setup the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers. + * + * To use 0-RTT on a server, you must call this function. Failing to call this + * function will result in all 0-RTT being rejected. Connections will complete, + * but early data will be rejected. + * + * NSS uses a Bloom filter to track the ClientHello messages that it receives + * (specifically, it uses the PSK binder). This function initializes a pair of + * Bloom filters. The two filters are alternated over time, with new + * ClientHello messages recorded in the current filter and, if they are not + * already present, being checked against the previous filter. If the + * ClientHello is found, then early data is rejected, but the handshake is + * allowed to proceed. + * + * The false-positive probability of Bloom filters means that some valid + * handshakes will be marked as potential replays. Early data will be rejected + * for a false positive. To minimize this and to allow a trade-off of space + * against accuracy, the size of the Bloom filter can be set by this function. + * + * The first tuning parameter to consider is |window|, which determines the + * window over which ClientHello messages will be tracked. This also causes + * early data to be rejected if a ClientHello contains a ticket age parameter + * that is outside of this window (see Section 4.2.10.4 of + * draft-ietf-tls-tls13-20 for details). Set |window| to account for any + * potential sources of clock error. |window| is the entire width of the + * window, which is symmetrical. Therefore to allow 5 seconds of clock error in + * both directions, set the value to 10 seconds (i.e., 10 * PR_USEC_PER_SEC). + * + * After calling this function, early data will be rejected until |window| + * elapses. This prevents replay across crashes and restarts. Only call this + * function once to avoid inadvertently disabling 0-RTT (use PR_CallOnce() to + * avoid this problem). + * + * The primary tuning parameter is |bits| which determines the amount of memory + * allocated to each Bloom filter. NSS will allocate two Bloom filters, each + * |2^(bits - 3)| octets in size. The value of |bits| is primarily driven by + * the number of connections that are expected in any time window. Note that + * this needs to account for there being two filters both of which have + * (presumably) independent false positive rates. The following formulae can be + * used to find a value of |bits| and |k| given a chosen false positive + * probability |p| and the number of requests expected in a given window |n|: + * + * bits = log2(n) + log2(-ln(1 - sqrt(1 - p))) + 1.0575327458897952 + * k = -log2(p) + * + * ... where log2 and ln are base 2 and e logarithms respectively. For a target + * false positive rate of 1% and 1000 handshake attempts, this produces bits=14 + * and k=7. This results in two Bloom filters that are 2kB each in size. Note + * that rounding |k| and |bits| up causes the false positive probability for + * these values to be a much lower 0.123%. + * + * IMPORTANT: This anti-replay scheme has several weaknesses. See the TLS 1.3 + * specification for the details of the generic problems with this technique. + * + * In addition to the generic anti-replay weaknesses, the state that the server + * maintains is in local memory only. Servers that operate in a cluster, even + * those that use shared memory for tickets, will not share anti-replay state. + * Early data can be replayed at least once with every server instance that will + * accept tickets that are encrypted with the same key. + */ +#define SSL_SetupAntiReplay(window, k, bits) \ + SSL_EXPERIMENTAL_API("SSL_SetupAntiReplay", \ + (PRTime _window, unsigned int _k, unsigned int _bits), \ + (window, k, bits)) + +/* + * This function allows a server application to generate a session ticket that + * will embed the provided token. + * + * This function will cause a NewSessionTicket message to be sent by a server. + * This happens even if SSL_ENABLE_SESSION_TICKETS is disabled. This allows a + * server to suppress the usually automatic generation of a session ticket at + * the completion of the handshake - which do not include any token - and to + * control when session tickets are transmitted. + * + * This function will fail unless the socket has an active TLS 1.3 session. + * Earlier versions of TLS do not support the spontaneous sending of the + * NewSessionTicket message. + */ +#define SSL_SendSessionTicket(fd, appToken, appTokenLen) \ + SSL_EXPERIMENTAL_API("SSL_SendSessionTicket", \ + (PRFileDesc * _fd, const PRUint8 *_appToken, \ + unsigned int _appTokenLen), \ + (fd, appToken, appTokenLen)) + +/* + * A stateless retry handler gives an application some control over NSS handling + * of ClientHello messages. + * + * SSL_HelloRetryRequestCallback() installs a callback that allows an + * application to control how NSS sends HelloRetryRequest messages. This + * handler is only used on servers and will only be called if the server selects + * TLS 1.3. Support for older TLS versions could be added in other releases. + * + * The SSLHelloRetryRequestCallback is invoked during the processing of a + * TLS 1.3 ClientHello message. It takes the following arguments: + * + * - |firstHello| indicates if the NSS believes that this is an initial + * ClientHello. An initial ClientHello will never include a cookie extension, + * though it may contain a session ticket. + * + * - |clientToken| includes a token previously provided by the application. If + * |clientTokenLen| is 0, then |clientToken| may be NULL. + * + * - If |firstHello| is PR_FALSE, the value that was provided in the + * |retryToken| outparam of previous invocations of this callback will be + * present here. + * + * - If |firstHello| is PR_TRUE, and the handshake is resuming a session, then + * this will contain any value that was passed in the |token| parameter of + * SSL_SendNewSessionTicket() method (see below). If this is not resuming a + * session, then the token will be empty (and this value could be NULL). + * + * - |clientTokenLen| is the length of |clientToken|. + * + * - |retryToken| is an item that callback can write to. This provides NSS with + * a token. This token is encrypted and integrity protected and embedded in + * the cookie extension of a HelloRetryRequest. The value of this field is + * only used if the handler returns ssl_stateless_retry_check. NSS allocates + * space for this value. + * + * - |retryTokenLen| is an outparam for the length of the token. If this value + * is not set, or set to 0, an empty token will be sent. + * + * - |retryTokenMax| is the size of the space allocated for retryToken. An + * application cannot write more than this many bytes to retryToken. + * + * - |arg| is the same value that was passed to + * SSL_InstallStatelessRetryHandler(). + * + * The handler can validate any the value of |clientToken|, query the socket + * status (using SSL_GetPreliminaryChannelInfo() for example) and decide how to + * proceed: + * + * - Returning ssl_hello_retry_fail causes the handshake to fail. This might be + * used if the token is invalid or the application wishes to abort the + * handshake. + * + * - Returning ssl_hello_retry_accept causes the handshake to proceed. + * + * - Returning ssl_hello_retry_request causes NSS to send a HelloRetryRequest + * message and request a second ClientHello. NSS generates a cookie extension + * and embeds the value of |retryToken|. The value of |retryToken| value may + * be left empty if the application does not require any additional context to + * validate a second ClientHello attempt. This return code cannot be used to + * reject a second ClientHello (i.e., when firstHello is PR_FALSE); NSS will + * abort the handshake if this value is returned from a second call. + * + * An application that chooses to perform a stateless retry can discard the + * server socket. All necessary state to continue the TLS handshake will be + * included in the cookie extension. This makes it possible to use a new socket + * to handle the remainder of the handshake. The existing socket can be safely + * discarded. + * + * If the same socket is retained, the information in the cookie will be checked + * for consistency against the existing state of the socket. Any discrepancy + * will result in the connection being closed. + * + * Tokens should be kept as small as possible. NSS sets a limit on the size of + * tokens, which it passes in |retryTokenMax|. Depending on circumstances, + * observing a smaller limit might be desirable or even necessary. For + * instance, having HelloRetryRequest and ClientHello fit in a single packet has + * significant performance benefits. + */ +typedef enum { + ssl_hello_retry_fail, + ssl_hello_retry_accept, + ssl_hello_retry_request +} SSLHelloRetryRequestAction; + +typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)( + PRBool firstHello, const PRUint8 *clientToken, unsigned int clientTokenLen, + PRUint8 *retryToken, unsigned int *retryTokenLen, unsigned int retryTokMax, + void *arg); + +#define SSL_HelloRetryRequestCallback(fd, cb, arg) \ + SSL_EXPERIMENTAL_API("SSL_HelloRetryRequestCallback", \ + (PRFileDesc * _fd, \ + SSLHelloRetryRequestCallback _cb, void *_arg), \ + (fd, cb, arg)) + +/* Update traffic keys (TLS 1.3 only). + * + * The |requestUpdate| flag determines whether to request an update from the + * remote peer. + */ +#define SSL_KeyUpdate(fd, requestUpdate) \ + SSL_EXPERIMENTAL_API("SSL_KeyUpdate", \ + (PRFileDesc * _fd, PRBool _requestUpdate), \ + (fd, requestUpdate)) + +#define SSL_UseAltServerHelloType(fd, enable) \ + SSL_DEPRECATED_EXPERIMENTAL_API + +SEC_END_PROTOS + +#endif /* __sslexp_h_ */ diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index 64694b0df..dee9aa20f 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -19,6 +19,7 @@ #include "secport.h" #include "secerr.h" #include "sslerr.h" +#include "sslexp.h" #include "ssl3prot.h" #include "hasht.h" #include "nssilock.h" @@ -34,36 +35,11 @@ #include "sslt.h" /* for some formerly private types, now public */ typedef struct sslSocketStr sslSocket; -typedef struct ssl3CipherSpecStr ssl3CipherSpec; +typedef struct sslNamedGroupDefStr sslNamedGroupDef; +#include "sslencode.h" +#include "sslexp.h" #include "ssl3ext.h" - -/* to make some of these old enums public without namespace pollution, -** it was necessary to prepend ssl_ to the names. -** These #defines preserve compatibility with the old code here in libssl. -*/ -typedef SSLMACAlgorithm SSL3MACAlgorithm; - -#define calg_null ssl_calg_null -#define calg_rc4 ssl_calg_rc4 -#define calg_rc2 ssl_calg_rc2 -#define calg_des ssl_calg_des -#define calg_3des ssl_calg_3des -#define calg_idea ssl_calg_idea -#define calg_fortezza ssl_calg_fortezza /* deprecated, must preserve */ -#define calg_aes ssl_calg_aes -#define calg_camellia ssl_calg_camellia -#define calg_seed ssl_calg_seed -#define calg_aes_gcm ssl_calg_aes_gcm -#define calg_chacha20 ssl_calg_chacha20 - -#define mac_null ssl_mac_null -#define mac_md5 ssl_mac_md5 -#define mac_sha ssl_mac_sha -#define hmac_md5 ssl_hmac_md5 -#define hmac_sha ssl_hmac_sha -#define hmac_sha256 ssl_hmac_sha256 -#define hmac_sha384 ssl_hmac_sha384 -#define mac_aead ssl_mac_aead +#include "sslspec.h" #if defined(DEBUG) || defined(TRACE) #ifdef __cplusplus @@ -160,7 +136,7 @@ typedef enum { ticket_allow_psk_sign_auth = 16 } TLS13SessionTicketFlags; -typedef struct { +struct sslNamedGroupDefStr { /* The name is the value that is encoded on the wire in TLS. */ SSLNamedGroup name; /* The number of bits in the group. */ @@ -172,9 +148,8 @@ typedef struct { SECOidTag oidTag; /* Assume that the group is always supported. */ PRBool assumeSupported; -} sslNamedGroupDef; +}; -typedef struct sslBufferStr sslBuffer; typedef struct sslConnectInfoStr sslConnectInfo; typedef struct sslGatherStr sslGather; typedef struct sslSecurityInfoStr sslSecurityInfo; @@ -183,8 +158,6 @@ typedef struct sslSocketOpsStr sslSocketOps; typedef struct ssl3StateStr ssl3State; typedef struct ssl3CertNodeStr ssl3CertNode; -typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef; -typedef struct ssl3MACDefStr ssl3MACDef; typedef struct sslKeyPairStr sslKeyPair; typedef struct ssl3DHParamsStr ssl3DHParams; @@ -201,9 +174,6 @@ typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr, unsigned char *sid, unsigned int sidLen, CERTCertDBHandle *dbHandle); -typedef void (*sslCipherSpecChangedFunc)(void *arg, - PRBool sending, - ssl3CipherSpec *newSpec); /* Socket ops */ struct sslSocketOpsStr { @@ -229,20 +199,9 @@ struct sslSocketOpsStr { #define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000 #define ssl_SEND_FLAG_NO_BUFFER 0x20000000 #define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */ -#define ssl_SEND_FLAG_CAP_RECORD_VERSION \ - 0x04000000 /* TLS only */ #define ssl_SEND_FLAG_MASK 0x7f000000 /* -** A buffer object. -*/ -struct sslBufferStr { - unsigned char *buf; - unsigned int len; - unsigned int space; -}; - -/* ** SSL3 cipher suite policy and preference struct. */ typedef struct { @@ -282,7 +241,7 @@ typedef struct sslOptionsStr { unsigned int detectRollBack : 1; unsigned int noLocks : 1; unsigned int enableSessionTickets : 1; - unsigned int enableDeflate : 1; + unsigned int enableDeflate : 1; /* Deprecated. */ unsigned int enableRenegotiation : 2; unsigned int requireSafeNegotiation : 1; unsigned int enableFalseStart : 1; @@ -297,7 +256,7 @@ typedef struct sslOptionsStr { unsigned int enableSignedCertTimestamps : 1; unsigned int requireDHENamedGroups : 1; unsigned int enable0RttData : 1; - unsigned int enableShortHeaders : 1; + unsigned int enableTls13CompatMode : 1; } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -382,136 +341,13 @@ struct sslGatherStr { #define GS_HEADER 1 #define GS_DATA 2 -/* -** ssl3State and CipherSpec structs -*/ - -/* The SSL bulk cipher definition */ -typedef enum { - cipher_null, - cipher_rc4, - cipher_des, - cipher_3des, - cipher_aes_128, - cipher_aes_256, - cipher_camellia_128, - cipher_camellia_256, - cipher_seed, - cipher_aes_128_gcm, - cipher_aes_256_gcm, - cipher_chacha20, - cipher_missing /* reserved for no such supported cipher */ - /* This enum must match ssl3_cipherName[] in ssl3con.c. */ -} SSL3BulkCipher; - -typedef enum { type_stream, - type_block, - type_aead } CipherType; - -#define MAX_IV_LENGTH 24 - -typedef PRUint64 sslSequenceNumber; -typedef PRUint16 DTLSEpoch; - -typedef void (*DTLSTimerCb)(sslSocket *); - typedef struct { PRUint8 wrapped_master_secret[48]; PRUint16 wrapped_master_secret_len; - PRUint8 msIsWrapped; PRUint8 resumable; PRUint8 extendedMasterSecretUsed; } ssl3SidKeys; /* 52 bytes */ -typedef struct { - PK11SymKey *write_key; - PK11SymKey *write_mac_key; - PK11Context *write_mac_context; - SECItem write_key_item; - SECItem write_iv_item; - SECItem write_mac_key_item; - PRUint8 write_iv[MAX_IV_LENGTH]; -} ssl3KeyMaterial; - -typedef SECStatus (*SSLCipher)(void *context, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen); -typedef SECStatus (*SSLAEADCipher)( - ssl3KeyMaterial *keys, - PRBool doDecrypt, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen, - const unsigned char *additionalData, - int additionalDataLen); -typedef SECStatus (*SSLCompressor)(void *context, - unsigned char *out, - int *outlen, - int maxout, - const unsigned char *in, - int inlen); -typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit); - -/* The DTLS anti-replay window in number of packets. Defined here because we - * need it in the cipher spec. Note that this is a ring buffer but left and - * right represent the true window, with modular arithmetic used to map them - * onto the buffer. - */ -#define DTLS_RECVD_RECORDS_WINDOW 1024 -#define RECORD_SEQ_MAX ((1ULL << 48) - 1) -PR_STATIC_ASSERT(DTLS_RECVD_RECORDS_WINDOW % 8 == 0); - -typedef struct DTLSRecvdRecordsStr { - unsigned char data[DTLS_RECVD_RECORDS_WINDOW / 8]; - sslSequenceNumber left; - sslSequenceNumber right; -} DTLSRecvdRecords; - -/* -** These are the "specs" in the "ssl3" struct. -** Access to the pointers to these specs, and all the specs' contents -** (direct and indirect) is protected by the reader/writer lock ss->specLock. -*/ -struct ssl3CipherSpecStr { - PRCList link; - const ssl3BulkCipherDef *cipher_def; - const ssl3MACDef *mac_def; - SSLCompressionMethod compression_method; - int mac_size; - SSLCipher encode; - SSLCipher decode; - SSLAEADCipher aead; - void *encodeContext; - void *decodeContext; - SSLCompressor compressor; /* Don't name these fields compress */ - SSLCompressor decompressor; /* and uncompress because zconf.h */ - /* may define them as macros. */ - SSLDestroy destroyCompressContext; - void *compressContext; - SSLDestroy destroyDecompressContext; - void *decompressContext; - PK11SymKey *master_secret; - sslSequenceNumber write_seq_num; - sslSequenceNumber read_seq_num; - SSL3ProtocolVersion version; - ssl3KeyMaterial client; - ssl3KeyMaterial server; - SECItem msItem; - DTLSEpoch epoch; - DTLSRecvdRecords recvdRecords; - /* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This - * will be zero for everything but 0-RTT. */ - PRUint32 earlyDataRemaining; - - PRUint8 refCt; - const char *phase; -}; - typedef enum { never_cached, in_client_cache, in_server_cache, @@ -527,7 +363,7 @@ struct sslSessionIDStr { sslSessionID *next; /* chain used for client sockets, only */ Cached cached; int references; - PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */ + PRTime lastAccessTime; /* The rest of the members, except for the members of u.ssl3.locked, may * be modified only when the sid is not in any cache. @@ -545,13 +381,15 @@ struct sslSessionIDStr { SSL3ProtocolVersion version; - PRUint32 creationTime; /* seconds since Jan 1, 1970 */ - PRUint32 expirationTime; /* seconds since Jan 1, 1970 */ + PRTime creationTime; + PRTime expirationTime; SSLAuthType authType; PRUint32 authKeyBits; SSLKEAType keaType; PRUint32 keaKeyBits; + SSLNamedGroup keaGroup; + SSLSignatureScheme sigScheme; union { struct { @@ -560,7 +398,6 @@ struct sslSessionIDStr { PRUint8 sessionID[SSL3_SESSIONID_BYTES]; ssl3CipherSuite cipherSuite; - SSLCompressionMethod compression; int policy; ssl3SidKeys keys; /* mechanism used to wrap master secret */ @@ -627,13 +464,13 @@ struct sslSessionIDStr { } u; }; -typedef struct ssl3CipherSuiteDefStr { +struct ssl3CipherSuiteDefStr { ssl3CipherSuite cipher_suite; SSL3BulkCipher bulk_cipher_alg; SSL3MACAlgorithm mac_alg; SSL3KeyExchangeAlgorithm key_exchange_alg; SSLHashType prf_hash; -} ssl3CipherSuiteDef; +}; /* ** There are tables of these, all const. @@ -656,37 +493,6 @@ typedef struct { SECOidTag oid; } ssl3KEADef; -/* -** There are tables of these, all const. -*/ -struct ssl3BulkCipherDefStr { - SSL3BulkCipher cipher; - SSLCipherAlgorithm calg; - unsigned int key_size; - unsigned int secret_key_size; - CipherType type; - unsigned int iv_size; - unsigned int block_size; - unsigned int tag_size; /* for AEAD ciphers. */ - unsigned int explicit_nonce_size; /* for AEAD ciphers. */ - SECOidTag oid; - const char *short_name; - /* The maximum number of records that can be sent/received with the same - * symmetric key before the connection will be terminated. */ - PRUint64 max_records; -}; - -/* -** There are tables of these, all const. -*/ -struct ssl3MACDefStr { - SSL3MACAlgorithm mac; - CK_MECHANISM_TYPE mmech; - int pad_size; - int mac_size; - SECOidTag oid; -}; - typedef enum { ssl_0rtt_none, /* 0-RTT not present */ ssl_0rtt_sent, /* 0-RTT sent (no decision yet) */ @@ -704,6 +510,7 @@ typedef enum { typedef enum { idle_handshake, wait_client_hello, + wait_end_of_early_data, wait_client_cert, wait_client_key, wait_cert_verify, @@ -760,14 +567,15 @@ typedef enum { handshake_hash_record } SSL3HandshakeHashType; -/* This holds state for TLS 1.3 CertificateRequest handling. */ -typedef struct TLS13CertificateRequestStr { - PLArenaPool *arena; - SECItem context; - SSLSignatureScheme *signatureSchemes; - unsigned int signatureSchemeCount; - CERTDistNames ca_list; -} TLS13CertificateRequest; +// A DTLS Timer. +typedef void (*DTLSTimerCb)(sslSocket *); + +typedef struct { + const char *label; + DTLSTimerCb cb; + PRIntervalTime started; + PRUint32 timeout; +} dtlsTimer; /* ** This is the "hs" member of the "ssl3" struct. @@ -791,13 +599,12 @@ typedef struct SSL3HandshakeStateStr { const ssl3KEADef *kea_def; ssl3CipherSuite cipher_suite; const ssl3CipherSuiteDef *suite_def; - SSLCompressionMethod compression; sslBuffer msg_body; /* protected by recvBufLock */ /* partial handshake message from record layer */ unsigned int header_bytes; /* number of bytes consumed from handshake */ /* message for message type and header length */ - SSL3HandshakeType msg_type; + SSLHandshakeType msg_type; unsigned long msg_len; PRBool isResuming; /* we are resuming (not used in TLS 1.3) */ PRBool sendingSCSV; /* instead of empty RI */ @@ -834,25 +641,25 @@ typedef struct SSL3HandshakeStateStr { PRCList remoteExtensions; /* Parsed incoming extensions */ /* This group of values is used for DTLS */ - PRUint16 sendMessageSeq; /* The sending message sequence + PRUint16 sendMessageSeq; /* The sending message sequence * number */ - PRCList lastMessageFlight; /* The last message flight we + PRCList lastMessageFlight; /* The last message flight we * sent */ - PRUint16 maxMessageSent; /* The largest message we sent */ - PRUint16 recvMessageSeq; /* The receiving message sequence + PRUint16 maxMessageSent; /* The largest message we sent */ + PRUint16 recvMessageSeq; /* The receiving message sequence * number */ - sslBuffer recvdFragments; /* The fragments we have received in + sslBuffer recvdFragments; /* The fragments we have received in * a bitmask */ - PRInt32 recvdHighWater; /* The high water mark for fragments + PRInt32 recvdHighWater; /* The high water mark for fragments * received. -1 means no reassembly * in progress. */ - SECItem cookie; /* The Hello(Retry|Verify)Request cookie. */ - PRIntervalTime rtTimerStarted; /* When the timer was started */ - DTLSTimerCb rtTimerCb; /* The function to call on expiry */ - PRUint32 rtTimeoutMs; /* The length of the current timeout - * used for backoff (in ms) */ - PRUint32 rtRetries; /* The retry counter */ - SECItem srvVirtName; /* for server: name that was negotiated + SECItem cookie; /* The Hello(Retry|Verify)Request cookie. */ + dtlsTimer timers[3]; /* Holder for timers. */ + dtlsTimer *rtTimer; /* Retransmit timer. */ + dtlsTimer *ackTimer; /* Ack timer (DTLS 1.3 only). */ + dtlsTimer *hdTimer; /* Read cipher holddown timer (DLTS 1.3 only) */ + PRUint32 rtRetries; /* The retry counter */ + SECItem srvVirtName; /* for server: name that was negotiated * with a client. For client - is * always set to NULL.*/ @@ -869,22 +676,37 @@ typedef struct SSL3HandshakeStateStr { PK11SymKey *serverTrafficSecret; /* traffic keys */ PK11SymKey *earlyExporterSecret; /* for 0-RTT exporters */ PK11SymKey *exporterSecret; /* for exporters */ - /* The certificate request from the server. */ - TLS13CertificateRequest *certificateRequest; - PRCList cipherSpecs; /* The cipher specs in the sequence they - * will be applied. */ - sslZeroRttState zeroRttState; /* Are we doing a 0-RTT handshake? */ - sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */ - ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */ - PRCList bufferedEarlyData; /* Buffered TLS 1.3 early data - * on server.*/ - PRBool helloRetry; /* True if HelloRetryRequest has been sent - * or received. */ - ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def - * we use for TLS 1.3 */ - PRBool shortHeaders; /* Assigned if we are doing short headers. */ + PRCList cipherSpecs; /* The cipher specs in the sequence they + * will be applied. */ + sslZeroRttState zeroRttState; /* Are we doing a 0-RTT handshake? */ + sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */ + ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */ + PRCList bufferedEarlyData; /* Buffered TLS 1.3 early data + * on server.*/ + PRBool helloRetry; /* True if HelloRetryRequest has been sent + * or received. */ + PRBool receivedCcs; /* A server received ChangeCipherSpec + * before the handshake started. */ + PRBool clientCertRequested; /* True if CertificateRequest received. */ + ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def + * we use for TLS 1.3 */ + PRTime serverHelloTime; /* Time the ServerHello flight was sent. */ + PRUint16 ticketNonce; /* A counter we use for tickets. */ + SECItem fakeSid; /* ... (server) the SID the client used. */ + PRBool endOfFlight; /* Processed a full flight (DTLS 1.3). */ + + /* The following lists contain DTLSHandshakeRecordEntry */ + PRCList dtlsSentHandshake; /* Used to map records to handshake fragments. */ + PRCList dtlsRcvdHandshake; /* Handshake records we have received + * used to generate ACKs. */ } SSL3HandshakeState; +#define SSL_ASSERT_HASHES_EMPTY(ss) \ + do { \ + PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown); \ + PORT_Assert(ss->ssl3.hs.messages.len == 0); \ + } while (0) + /* ** This is the "ssl3" struct, as in "ss->ssl3". ** note: @@ -904,6 +726,10 @@ struct ssl3StateStr { ssl3CipherSpec *cwSpec; /* current write spec. */ ssl3CipherSpec *pwSpec; /* pending write spec. */ + /* This is true after the peer requests a key update; false after a key + * update is initiated locally. */ + PRBool peerRequestedKeyUpdate; + /* Internal callback for when we do a cipher suite change. Used for * debugging in TLS 1.3. This can only be set by non-public functions. */ sslCipherSpecChangedFunc changedCipherSpecFunc; @@ -924,9 +750,7 @@ struct ssl3StateStr { /* chain while we are trying to validate it. */ CERTDistNames *ca_list; /* used by server. trusted CAs for this socket. */ - PRBool initialized; SSL3HandshakeState hs; - ssl3CipherSpec specs[2]; /* one is current, one is pending. */ PRUint16 mtu; /* Our estimate of the MTU */ @@ -995,11 +819,12 @@ typedef struct SessionTicketStr { PRBool valid; SSL3ProtocolVersion ssl_version; ssl3CipherSuite cipher_suite; - SSLCompressionMethod compression_method; SSLAuthType authType; PRUint32 authKeyBits; SSLKEAType keaType; PRUint32 keaKeyBits; + SSLNamedGroup originalKeaGroup; + SSLSignatureScheme signatureScheme; const sslNamedGroupDef *namedCurve; /* For certificate lookup. */ /* @@ -1012,11 +837,13 @@ typedef struct SessionTicketStr { PRBool extendedMasterSecretUsed; ClientAuthenticationType client_auth_type; SECItem peer_cert; - PRUint32 timestamp; + PRTime timestamp; PRUint32 flags; SECItem srvName; /* negotiated server name */ SECItem alpnSelection; PRUint32 maxEarlyData; + PRUint32 ticketAgeBaseline; + SECItem applicationToken; } SessionTicket; /* @@ -1066,6 +893,7 @@ struct sslSecurityInfoStr { SSLKEAType keaType; PRUint32 keaKeyBits; const sslNamedGroupDef *keaGroup; + const sslNamedGroupDef *originalKeaGroup; /* The selected certificate (for servers only). */ const sslServerCert *serverCert; @@ -1151,6 +979,9 @@ struct sslSocketStr { void *pkcs11PinArg; SSLNextProtoCallback nextProtoCallback; void *nextProtoArg; + SSLHelloRetryRequestCallback hrrCallback; + void *hrrCallbackArg; + PRCList extensionHooks; PRIntervalTime rTimeout; /* timeout for NSPR I/O */ PRIntervalTime wTimeout; /* timeout for NSPR I/O */ @@ -1241,6 +1072,7 @@ extern char ssl_debug; extern char ssl_trace; extern FILE *ssl_trace_iob; extern FILE *ssl_keylog_iob; +extern PZLock *ssl_keylog_lock; extern PRUint32 ssl3_sid_timeout; extern PRUint32 ssl_ticket_lifetime; extern PRUint32 ssl_max_early_data_size; @@ -1331,14 +1163,10 @@ extern SECStatus ssl_BeginClientHandshake(sslSocket *ss); extern SECStatus ssl_BeginServerHandshake(sslSocket *ss); extern int ssl_Do1stHandshake(sslSocket *ss); -extern SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen); -extern SECStatus sslBuffer_Append(sslBuffer *b, const void *data, - unsigned int len); -extern void sslBuffer_Clear(sslBuffer *b); - extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec); -extern void ssl3_InitCipherSpec(ssl3CipherSpec *spec); +extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret, + PRBool derive); extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server); extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, const char *urlSvrName); @@ -1363,11 +1191,20 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled); extern SECStatus ssl3_ConstrainRangeByPolicy(void); -extern void ssl3_InitState(sslSocket *ss); +extern SECStatus ssl3_InitState(sslSocket *ss); +extern SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, + int maxOutputLen, const unsigned char *input, + int inputLen); extern void ssl3_RestartHandshakeHashes(sslSocket *ss); extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l); +SECStatus +ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type, + PRUint32 dtlsSeq, + const PRUint8 *b, PRUint32 length); +SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type, + const PRUint8 *b, PRUint32 length); /* Returns PR_TRUE if we are still waiting for the server to complete its * response to our client second round. Once we've received the Finished from @@ -1380,21 +1217,14 @@ extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, const PRUint8 *pIn, PRInt32 nIn, PRInt32 flags); -#ifdef NSS_SSL_ENABLE_ZLIB -/* - * The DEFLATE algorithm can result in an expansion of 0.1% + 12 bytes. For a - * maximum TLS record payload of 2**14 bytes, that's 29 bytes. - */ -#define SSL3_COMPRESSION_MAX_EXPANSION 29 -#else /* !NSS_SSL_ENABLE_ZLIB */ -#define SSL3_COMPRESSION_MAX_EXPANSION 0 -#endif +/* Clear any PRCList, optionally calling f on the value. */ +void ssl_ClearPRCList(PRCList *list, void (*f)(void *)); /* - * make sure there is room in the write buffer for padding and - * other compression and cryptographic expansions. + * Make sure there is room in the write buffer for padding and + * cryptographic expansions. */ -#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION +#define SSL3_BUFFER_FUDGE 100 #define SSL_LOCK_READER(ss) \ if (ss->recvLock) \ @@ -1547,7 +1377,7 @@ extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error); * for dealing with SSL 3.0 clients sending SSL 2.0 format hellos */ extern SECStatus ssl3_HandleV2ClientHello( - sslSocket *ss, unsigned char *buffer, int length, PRUint8 padding); + sslSocket *ss, unsigned char *buffer, unsigned int length, PRUint8 padding); SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type); @@ -1583,7 +1413,7 @@ extern PRBool ssl_HaveEphemeralKeyPair(const sslSocket *ss, const sslNamedGroupDef *groupDef); extern void ssl_FreeEphemeralKeyPairs(sslSocket *ss); -extern SECStatus ssl_AppendPaddedDHKeyShare(const sslSocket *ss, +extern SECStatus ssl_AppendPaddedDHKeyShare(sslBuffer *buf, const SECKEYPublicKey *pubKey, PRBool appendLength); extern const ssl3DHParams *ssl_GetDHEParams(const sslNamedGroupDef *groupDef); @@ -1645,6 +1475,10 @@ extern SECStatus ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b, extern SECStatus ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion, PRBool allowLargerPeerVersion); +extern SECStatus ssl_ClientSetCipherSuite(sslSocket *ss, + SSL3ProtocolVersion version, + ssl3CipherSuite suite, + PRBool initHashes); extern SECStatus ssl_GetPeerInfo(sslSocket *ss); @@ -1660,23 +1494,11 @@ extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss); extern SECStatus ssl_ImportECDHKeyShare( sslSocket *ss, SECKEYPublicKey *peerKey, PRUint8 *b, PRUint32 length, const sslNamedGroupDef *curve); -SECStatus tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss, - const SECKEYPublicKey *pubKey); extern SECStatus ssl3_ComputeCommonKeyHash(SSLHashType hashAlg, PRUint8 *hashBuf, unsigned int bufLen, SSL3Hashes *hashes); -extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName); -extern SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms); -extern SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src, - PRInt32 bytes); -extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss, - SSL3HandshakeType t, PRUint32 length); -extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, - PRInt32 lenSize); -extern SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss, - const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize); extern SECStatus ssl3_AppendSignatureAndHashAlgorithm( sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash); extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes, @@ -1684,11 +1506,12 @@ extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes, extern SECStatus ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes, PRUint8 **b, PRUint32 *length); +extern SECStatus ssl3_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *num, + PRUint32 bytes, PRUint8 **b, + PRUint32 *length); extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRUint32 bytes, PRUint8 **b, PRUint32 *length); -extern PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes, - PRUint8 *to); extern PRBool ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme); extern SECStatus ssl_CheckSignatureSchemeConsistency( sslSocket *ss, SSLSignatureScheme scheme, CERTCertificate *cert); @@ -1703,16 +1526,20 @@ extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf); extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *hash, SECItem *buf); -extern SECStatus ssl3_CacheWrappedMasterSecret( - sslSocket *ss, sslSessionID *sid, ssl3CipherSpec *spec); +extern SECStatus ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid, + PK11SymKey *secret); extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData); /* Hello Extension related routines. */ extern void ssl3_SetSIDSessionTicket(sslSessionID *sid, /*in/out*/ NewSessionTicket *session_ticket); SECStatus ssl3_EncodeSessionTicket(sslSocket *ss, - const NewSessionTicket *ticket_input, - SECItem *ticket_data); + const NewSessionTicket *ticket, + const PRUint8 *appToken, + unsigned int appTokenLen, + PK11SymKey *secret, SECItem *ticket_data); +SECStatus SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token, + unsigned int tokenLen); SECStatus ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair); SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName, @@ -1728,7 +1555,7 @@ extern void ssl_FreePRSocket(PRFileDesc *fd); /* Internal config function so SSL3 can initialize the present state of * various ciphers */ -extern int ssl3_config_match_init(sslSocket *); +extern unsigned int ssl3_config_match_init(sslSocket *); /* calls for accessing wrapping keys across processes. */ extern SECStatus @@ -1758,44 +1585,11 @@ extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit); extern SECStatus ssl_FreeSessionCacheLocks(void); -/**************** DTLS-specific functions **************/ -extern void dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg); -extern void dtls_FreeHandshakeMessages(PRCList *lst); - -extern SECStatus dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf); -extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss, - PRUint8 *b, PRUint32 length); -extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss); -extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, - const PRUint8 *pIn, PRInt32 nIn); -extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); -SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss); -extern SECStatus dtls_StartHolddownTimer(sslSocket *ss); -extern void dtls_CheckTimer(sslSocket *ss); -extern void dtls_CancelTimer(sslSocket *ss); -extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised); -extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records); -extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records, - sslSequenceNumber seq); -extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records, - sslSequenceNumber seq); -extern void dtls_RehandshakeCleanup(sslSocket *ss); -extern SSL3ProtocolVersion -dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv); -extern SSL3ProtocolVersion -dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv); -extern PRBool dtls_IsRelevant(sslSocket *ss, const SSL3Ciphertext *cText, - PRBool *sameEpoch, PRUint64 *seqNum); -extern SECStatus dtls_MaybeRetransmitHandshake(sslSocket *ss, - const SSL3Ciphertext *cText, - PRBool sameEpoch); - CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg); SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites, PRBool initHashes); SECStatus ssl3_InitHandshakeHashes(sslSocket *ss); SECStatus ssl3_ServerCallSNICallback(sslSocket *ss); -SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss); SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags); SECStatus ssl3_CompleteHandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length); @@ -1807,17 +1601,21 @@ SECStatus ssl3_SendCertificateStatus(sslSocket *ss); SECStatus ssl3_AuthCertificate(sslSocket *ss); SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b, PRUint32 length); -SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, - unsigned maxLen, PRUint32 *len); -SECStatus ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calenp, - SECItem **namesp, unsigned int *nnamesp); +SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf); +SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss, + unsigned int *calenp, + const SECItem **namesp, + unsigned int *nnamesp); SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, - PRUint32 *length, PLArenaPool *arena, - CERTDistNames *ca_list); + PRUint32 *length, CERTDistNames *ca_list); SECStatus ssl3_CompleteHandleCertificateRequest( sslSocket *ss, const SSLSignatureScheme *signatureSchemes, unsigned int signatureSchemeCount, CERTDistNames *ca_list); +SECStatus ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry, + const sslBuffer *extensionBuf, + sslBuffer *messageBuf); SECStatus ssl3_SendServerHello(sslSocket *ss); +SECStatus ssl3_SendChangeCipherSpecsInt(sslSocket *ss); SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss, ssl3CipherSpec *spec, SSL3Hashes *hashes, @@ -1832,10 +1630,9 @@ PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss, PK11SlotInfo *masterSecretSlot, CK_MECHANISM_TYPE masterWrapMech, void *pwArg); -SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid); +SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, + PK11SymKey *secret); const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite); -const ssl3BulkCipherDef * -ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def); SECStatus ssl3_SelectServerCert(sslSocket *ss); SECStatus ssl_PickSignatureScheme(sslSocket *ss, SECKEYPublicKey *pubKey, @@ -1847,11 +1644,14 @@ SECOidTag ssl3_HashTypeToOID(SSLHashType hashType); SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme); KeyType ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme); -SECStatus ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite, - PRBool initHashes); +SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes); + +/* Pull in DTLS functions */ +#include "dtlscon.h" /* Pull in TLS 1.3 functions */ #include "tls13con.h" +#include "dtls13con.h" /********************** misc calls *********************/ @@ -1861,22 +1661,27 @@ extern void ssl3_CheckCipherSuiteOrderConsistency(); extern int ssl_MapLowLevelError(int hiLevelError); -extern PRUint32 ssl_Time(void); +extern PRUint32 ssl_TimeSec(void); +#ifdef UNSAFE_FUZZER_MODE +#define ssl_TimeUsec() ((PRTime)12345678) +#else +#define ssl_TimeUsec() (PR_Now()) +#endif extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket); extern void SSL_AtomicIncrementLong(long *x); SECStatus ssl3_ApplyNSSPolicy(void); -extern HASH_HashType -ssl3_GetTls12HashType(sslSocket *ss); - extern SECStatus ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec, const char *label, unsigned int labelLen, const unsigned char *val, unsigned int valLen, unsigned char *out, unsigned int outLen); +extern void +ssl3_RecordKeyLog(sslSocket *ss, const char *label, PK11SymKey *secret); + PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag); #ifdef TRACE diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c index 88162d814..4e58c5ae7 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -2,26 +2,12 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "pk11pub.h" #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" #include "tls13hkdf.h" -static const char * -ssl_GetCompressionMethodName(SSLCompressionMethod compression) -{ - switch (compression) { - case ssl_compression_null: - return "NULL"; -#ifdef NSS_ENABLE_ZLIB - case ssl_compression_deflate: - return "DEFLATE"; -#endif - default: - return "???"; - } -} - SECStatus SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) { @@ -48,48 +34,58 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) inf.length = PR_MIN(sizeof inf, len); if (ss->opt.useSecurity && ss->enoughFirstHsDone) { + SSLCipherSuiteInfo cinfo; + SECStatus rv; + sid = ss->sec.ci.sid; inf.protocolVersion = ss->version; inf.authKeyBits = ss->sec.authKeyBits; inf.keaKeyBits = ss->sec.keaKeyBits; - if (ss->ssl3.initialized) { - SSLCipherSuiteInfo cinfo; - SECStatus rv; - - ssl_GetSpecReadLock(ss); - /* XXX The cipher suite should be in the specs and this - * function should get it from cwSpec rather than from the "hs". - * See bug 275744 comment 69 and bug 766137. - */ - inf.cipherSuite = ss->ssl3.hs.cipher_suite; - inf.compressionMethod = ss->ssl3.cwSpec->compression_method; - ssl_ReleaseSpecReadLock(ss); - inf.compressionMethodName = - ssl_GetCompressionMethodName(inf.compressionMethod); - - /* Fill in the cipher details from the cipher suite. */ - rv = SSL_GetCipherSuiteInfo(inf.cipherSuite, - &cinfo, sizeof(cinfo)); - if (rv != SECSuccess) { - return SECFailure; /* Error code already set. */ - } - inf.symCipher = cinfo.symCipher; - inf.macAlgorithm = cinfo.macAlgorithm; - /* Get these fromm |ss->sec| because that is accurate - * even with TLS 1.3 disaggregated cipher suites. */ - inf.keaType = ss->sec.keaType; - inf.keaGroup = ss->sec.keaGroup ? ss->sec.keaGroup->name : ssl_grp_none; - inf.keaKeyBits = ss->sec.keaKeyBits; - inf.authType = ss->sec.authType; - inf.authKeyBits = ss->sec.authKeyBits; - inf.signatureScheme = ss->sec.signatureScheme; + + ssl_GetSpecReadLock(ss); + /* XXX The cipher suite should be in the specs and this + * function should get it from cwSpec rather than from the "hs". + * See bug 275744 comment 69 and bug 766137. + */ + inf.cipherSuite = ss->ssl3.hs.cipher_suite; + ssl_ReleaseSpecReadLock(ss); + inf.compressionMethod = ssl_compression_null; + inf.compressionMethodName = "NULL"; + + /* Fill in the cipher details from the cipher suite. */ + rv = SSL_GetCipherSuiteInfo(inf.cipherSuite, + &cinfo, sizeof(cinfo)); + if (rv != SECSuccess) { + return SECFailure; /* Error code already set. */ + } + inf.symCipher = cinfo.symCipher; + inf.macAlgorithm = cinfo.macAlgorithm; + /* Get these fromm |ss->sec| because that is accurate + * even with TLS 1.3 disaggregated cipher suites. */ + inf.keaType = ss->sec.keaType; + inf.originalKeaGroup = ss->sec.originalKeaGroup + ? ss->sec.originalKeaGroup->name + : ssl_grp_none; + inf.keaGroup = ss->sec.keaGroup + ? ss->sec.keaGroup->name + : ssl_grp_none; + inf.keaKeyBits = ss->sec.keaKeyBits; + inf.authType = ss->sec.authType; + inf.authKeyBits = ss->sec.authKeyBits; + inf.signatureScheme = ss->sec.signatureScheme; + /* If this is a resumed session, signatureScheme isn't set in ss->sec. + * Use the signature scheme from the previous handshake. */ + if (inf.signatureScheme == ssl_sig_none && sid->sigScheme) { + inf.signatureScheme = sid->sigScheme; } + inf.resumed = ss->statelessResume || ss->ssl3.hs.isResuming; + if (sid) { unsigned int sidLen; - inf.creationTime = sid->creationTime; - inf.lastAccessTime = sid->lastAccessTime; - inf.expirationTime = sid->expirationTime; + inf.creationTime = sid->creationTime / PR_USEC_PER_SEC; + inf.lastAccessTime = sid->lastAccessTime / PR_USEC_PER_SEC; + inf.expirationTime = sid->expirationTime / PR_USEC_PER_SEC; inf.extendedMasterSecretUsed = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 || sid->u.ssl3.keys.extendedMasterSecretUsed) @@ -196,17 +192,17 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, #define K_ANY "TLS 1.3", ssl_kea_tls13_any /* record protection cipher */ -#define C_SEED "SEED", calg_seed -#define C_CAMELLIA "CAMELLIA", calg_camellia -#define C_AES "AES", calg_aes -#define C_RC4 "RC4", calg_rc4 -#define C_RC2 "RC2", calg_rc2 -#define C_DES "DES", calg_des -#define C_3DES "3DES", calg_3des -#define C_NULL "NULL", calg_null -#define C_SJ "SKIPJACK", calg_sj -#define C_AESGCM "AES-GCM", calg_aes_gcm -#define C_CHACHA20 "CHACHA20POLY1305", calg_chacha20 +#define C_SEED "SEED", ssl_calg_seed +#define C_CAMELLIA "CAMELLIA", ssl_calg_camellia +#define C_AES "AES", ssl_calg_aes +#define C_RC4 "RC4", ssl_calg_rc4 +#define C_RC2 "RC2", ssl_calg_rc2 +#define C_DES "DES", ssl_calg_des +#define C_3DES "3DES", ssl_calg_3des +#define C_NULL "NULL", ssl_calg_null +#define C_SJ "SKIPJACK", ssl_calg_sj +#define C_AESGCM "AES-GCM", ssl_calg_aes_gcm +#define C_CHACHA20 "CHACHA20POLY1305", ssl_calg_chacha20 /* "block cipher" sizes */ #define B_256 256, 256, 256 @@ -367,8 +363,7 @@ SSL_GetNegotiatedHostInfo(PRFileDesc *fd) } if (ss->sec.isServer) { - if (ss->version > SSL_LIBRARY_VERSION_3_0 && - ss->ssl3.initialized) { /* TLS */ + if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* TLS */ SECItem *crsName; ssl_GetSpecReadLock(ss); /*********************************/ crsName = &ss->ssl3.hs.srvVirtName; @@ -392,22 +387,47 @@ SSL_GetNegotiatedHostInfo(PRFileDesc *fd) return sniName; } +/* + * HKDF-Expand-Label(Derive-Secret(Secret, label, ""), + * "exporter", Hash(context_value), key_length) + */ static SECStatus tls13_Exporter(sslSocket *ss, PK11SymKey *secret, const char *label, unsigned int labelLen, const unsigned char *context, unsigned int contextLen, unsigned char *out, unsigned int outLen) { + SSL3Hashes contextHash; + PK11SymKey *innerSecret = NULL; + SECStatus rv; + + static const char *kExporterInnerLabel = "exporter"; + if (!secret) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - return tls13_HkdfExpandLabelRaw(secret, - tls13_GetHash(ss), - context, contextLen, - label, labelLen, - out, outLen); + /* Pre-hash the context. */ + rv = tls13_ComputeHash(ss, &contextHash, context, contextLen); + if (rv != SECSuccess) { + return rv; + } + + rv = tls13_DeriveSecretNullHash(ss, secret, label, labelLen, + &innerSecret); + if (rv != SECSuccess) { + return rv; + } + + rv = tls13_HkdfExpandLabelRaw(innerSecret, + tls13_GetHash(ss), + contextHash.u.raw, contextHash.len, + kExporterInnerLabel, + strlen(kExporterInnerLabel), + out, outLen); + PK11_FreeSymKey(innerSecret); + return rv; } SECStatus @@ -457,9 +477,9 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, return SECFailure; } i = 0; - PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); + PORT_Memcpy(val + i, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; - PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH); + PORT_Memcpy(val + i, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; if (hasContext) { val[i++] = contextLen >> 8; @@ -473,7 +493,7 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, * secret is available and we have sent ChangeCipherSpec. */ ssl_GetSpecReadLock(ss); - if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) { + if (!ss->ssl3.cwSpec->masterSecret) { PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); rv = SECFailure; } else { diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c index 7ad1c6bc7..228834e3d 100644 --- a/security/nss/lib/ssl/sslnonce.c +++ b/security/nss/lib/ssl/sslnonce.c @@ -256,7 +256,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, if (!urlSvrName) return NULL; - now = ssl_Time(); + now = ssl_TimeSec(); LOCK_CACHE; sidp = &cache; while ((sid = *sidp) != 0) { @@ -306,8 +306,6 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, static void CacheSID(sslSessionID *sid) { - PRUint32 expirationPeriod; - PORT_Assert(sid->cached == never_cached); SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x " @@ -335,7 +333,6 @@ CacheSID(sslSessionID *sid) return; sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES; } - expirationPeriod = ssl3_sid_timeout; PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength)); @@ -345,9 +342,9 @@ CacheSID(sslSessionID *sid) } PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0); if (!sid->creationTime) - sid->lastAccessTime = sid->creationTime = ssl_Time(); + sid->lastAccessTime = sid->creationTime = ssl_TimeUsec(); if (!sid->expirationTime) - sid->expirationTime = sid->creationTime + expirationPeriod; + sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC; /* * Put sid into the cache. Bump reference count to indicate that @@ -438,7 +435,7 @@ SSL_ClearSessionCache(void) /* returns an unsigned int containing the number of seconds in PR_Now() */ PRUint32 -ssl_Time(void) +ssl_TimeSec(void) { #ifdef UNSAFE_FUZZER_MODE return 1234; @@ -471,7 +468,7 @@ ssl_TicketTimeValid(const NewSessionTicket *ticket) endTime = ticket->received_timestamp + (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC); - return endTime > PR_Now(); + return endTime > ssl_TimeUsec(); } void diff --git a/security/nss/lib/ssl/sslreveal.c b/security/nss/lib/ssl/sslreveal.c index 4c124a1dc..cc16f574d 100644 --- a/security/nss/lib/ssl/sslreveal.c +++ b/security/nss/lib/ssl/sslreveal.c @@ -92,18 +92,16 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc *socket, /* according to public API SSL_GetChannelInfo, this doesn't need a lock */ if (sslsocket->opt.useSecurity) { - if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */ - /* now we know this socket went through ssl3_InitState() and - * ss->xtnData got initialized, which is the only member accessed by - * ssl3_ExtensionNegotiated(); - * Member xtnData appears to get accessed in functions that handle - * the handshake (hello messages and extension sending), - * therefore the handshake lock should be sufficient. - */ - ssl_GetSSL3HandshakeLock(sslsocket); - *pYes = ssl3_ExtensionNegotiated(sslsocket, extId); - ssl_ReleaseSSL3HandshakeLock(sslsocket); - } + /* now we know this socket went through ssl3_InitState() and + * ss->xtnData got initialized, which is the only member accessed by + * ssl3_ExtensionNegotiated(); + * Member xtnData appears to get accessed in functions that handle + * the handshake (hello messages and extension sending), + * therefore the handshake lock should be sufficient. + */ + ssl_GetSSL3HandshakeLock(sslsocket); + *pYes = ssl3_ExtensionNegotiated(sslsocket, extId); + ssl_ReleaseSSL3HandshakeLock(sslsocket); } return SECSuccess; diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index 8bec3d327..3f7060f22 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Various SSL functions. * @@ -200,7 +201,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) ssl_Release1stHandshakeLock(ss); ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); - ssl3_ResetExtensionData(&ss->xtnData); + ssl3_ResetExtensionData(&ss->xtnData, ss); if (!ss->TCPconnected) ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr)); @@ -342,11 +343,6 @@ SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) return SECFailure; } - if (!ss->ssl3.initialized) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - /* Require a forward-secret key exchange. */ *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss || ss->ssl3.hs.kea_def->kea == kea_dhe_rsa || @@ -435,58 +431,6 @@ SSL_ForceHandshakeWithTimeout(PRFileDesc *fd, /************************************************************************/ /* -** Grow a buffer to hold newLen bytes of data. -** Called for both recv buffers and xmit buffers. -** Caller must hold xmitBufLock or recvBufLock, as appropriate. -*/ -SECStatus -sslBuffer_Grow(sslBuffer *b, unsigned int newLen) -{ - newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048); - if (newLen > b->space) { - unsigned char *newBuf; - if (b->buf) { - newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen); - } else { - newBuf = (unsigned char *)PORT_Alloc(newLen); - } - if (!newBuf) { - return SECFailure; - } - SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d", - SSL_GETPID(), b->space, newLen)); - b->buf = newBuf; - b->space = newLen; - } - return SECSuccess; -} - -SECStatus -sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len) -{ - unsigned int newLen = b->len + len; - SECStatus rv; - - rv = sslBuffer_Grow(b, newLen); - if (rv != SECSuccess) - return rv; - PORT_Memcpy(b->buf + b->len, data, len); - b->len += len; - return SECSuccess; -} - -void -sslBuffer_Clear(sslBuffer *b) -{ - if (b->buf) { - PORT_Free(b->buf); - b->buf = NULL; - b->len = 0; - b->space = 0; - } -} - -/* ** Save away write data that is trying to be written before the security ** handshake has been completed. When the handshake is completed, we will ** flush this data out. @@ -774,8 +718,7 @@ ssl_SecureClose(sslSocket *ss) if (!(ss->shutdownHow & ssl_SHUTDOWN_SEND) && ss->firstHsDone && - !ss->recvdCloseNotify && - ss->ssl3.initialized) { + !ss->recvdCloseNotify) { /* We don't want the final alert to be Nagle delayed. */ if (!ss->delayDisabled) { @@ -805,8 +748,7 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow) if ((sslHow & ssl_SHUTDOWN_SEND) != 0 && !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && ss->firstHsDone && - !ss->recvdCloseNotify && - ss->ssl3.initialized) { + !ss->recvdCloseNotify) { (void)SSL3_SendAlert(ss, alert_warning, close_notify); } @@ -820,6 +762,55 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow) /************************************************************************/ +static SECStatus +tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir) +{ + PRBool keyUpdate; + ssl3CipherSpec *spec; + sslSequenceNumber seqNum; + sslSequenceNumber margin; + SECStatus rv; + + /* Bug 1413368: enable for DTLS */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 || IS_DTLS(ss)) { + return SECSuccess; + } + + /* If both sides update at the same number, then this will cause two updates + * to happen at once. The problem is that the KeyUpdate itself consumes a + * sequence number, and that will trigger the reading side to request an + * update. + * + * If we have the writing side update first, the writer will be the one that + * drives the update. An update by the writer doesn't need a response, so + * it is more efficient overall. The margins here are pretty arbitrary, but + * having the write margin larger reduces the number of times that a + * KeyUpdate is sent by a reader. */ + ssl_GetSpecReadLock(ss); + if (dir == CipherSpecRead) { + spec = ss->ssl3.crSpec; + margin = spec->cipherDef->max_records / 8; + } else { + spec = ss->ssl3.cwSpec; + margin = spec->cipherDef->max_records / 4; + } + seqNum = spec->seqNum; + keyUpdate = seqNum > spec->cipherDef->max_records - margin; + ssl_ReleaseSpecReadLock(ss); + if (!keyUpdate) { + return SECSuccess; + } + + SSL_TRC(5, ("%d: SSL[%d]: automatic key update at %llx for %s cipher spec", + SSL_GETPID(), ss->fd, seqNum, + (dir == CipherSpecRead) ? "read" : "write")); + ssl_GetSSL3HandshakeLock(ss); + rv = tls13_SendKeyUpdate(ss, (dir == CipherSpecRead) ? update_requested : update_not_requested, + dir == CipherSpecWrite /* buffer */); + ssl_ReleaseSSL3HandshakeLock(ss); + return rv; +} + int ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) { @@ -859,8 +850,17 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); + } else { + if (tls13_CheckKeyUpdate(ss, CipherSpecRead) != SECSuccess) { + rv = PR_FAILURE; + } } if (rv < 0) { + if (PORT_GetError() == PR_WOULD_BLOCK_ERROR && + !PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) { + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + return tls13_Read0RttData(ss, buf, len); + } return rv; } @@ -942,11 +942,19 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) } ssl_Release1stHandshakeLock(ss); } + if (rv < 0) { ss->writerThread = NULL; goto done; } + if (ss->firstHsDone) { + if (tls13_CheckKeyUpdate(ss, CipherSpecWrite) != SECSuccess) { + rv = PR_FAILURE; + goto done; + } + } + if (zeroRtt) { /* There's a limit to the number of early data octets we can send. * @@ -1241,14 +1249,7 @@ SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error) } ssl_Get1stHandshakeLock(ss); - - if (!ss->ssl3.initialized) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - } else { - rv = ssl3_AuthCertificateComplete(ss, error); - } - + rv = ssl3_AuthCertificateComplete(ss, error); ssl_Release1stHandshakeLock(ss); return rv; diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index 3ef11f7a7..279f3c015 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -85,11 +85,12 @@ /* ** Format of a cache entry in the shared memory. */ +PR_STATIC_ASSERT(sizeof(PRTime) == 8); struct sidCacheEntryStr { /* 16 */ PRIPv6Addr addr; /* client's IP address */ - /* 4 */ PRUint32 creationTime; - /* 4 */ PRUint32 lastAccessTime; - /* 4 */ PRUint32 expirationTime; + /* 8 */ PRTime creationTime; + /* 8 */ PRTime lastAccessTime; + /* 8 */ PRTime expirationTime; /* 2 */ PRUint16 version; /* 1 */ PRUint8 valid; /* 1 */ PRUint8 sessionIDLength; @@ -98,25 +99,25 @@ struct sidCacheEntryStr { /* 2 */ PRUint16 authKeyBits; /* 2 */ PRUint16 keaType; /* 2 */ PRUint16 keaKeyBits; - /* 72 - common header total */ + /* 4 */ PRUint32 signatureScheme; + /* 4 */ PRUint32 keaGroup; + /* 92 - common header total */ union { struct { /* 2 */ ssl3CipherSuite cipherSuite; - /* 2 */ PRUint16 compression; /* SSLCompressionMethod */ - - /* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */ + /* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */ /* 4 */ PRUint32 masterWrapMech; /* 4 */ PRInt32 certIndex; /* 4 */ PRInt32 srvNameIndex; /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */ /* 2 */ PRUint16 namedCurve; -/*104 */} ssl3; +/*100 */} ssl3; /* force sizeof(sidCacheEntry) to be a multiple of cache line size */ struct { - /*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */ + /*116 */ PRUint8 filler[116]; /* 92+116==208, a multiple of 16 */ } forceSize; } u; }; @@ -282,7 +283,7 @@ LockSidCacheLock(sidCacheLock *lock, PRUint32 now) if (rv != SECSuccess) return 0; if (!now) - now = ssl_Time(); + now = ssl_TimeSec(); lock->timeStamp = now; lock->pid = myPid; return now; @@ -298,7 +299,7 @@ UnlockSidCacheLock(sidCacheLock *lock) return rv; } -/* returns the value of ssl_Time on success, zero on failure. */ +/* returns the value of ssl_TimeSec on success, zero on failure. */ static PRUint32 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now) { @@ -432,9 +433,10 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) to->authKeyBits = from->authKeyBits; to->keaType = from->keaType; to->keaKeyBits = from->keaKeyBits; + to->keaGroup = from->keaGroup; + to->signatureScheme = from->sigScheme; to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; - to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression; to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->sessionIDLength = from->u.ssl3.sessionIDLength; @@ -452,9 +454,10 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x " "cipherSuite=%d", - myPid, to->creationTime, to->addr.pr_s6_addr32[0], - to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2], - to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite)); + myPid, to->creationTime / PR_USEC_PER_SEC, + to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1], + to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3], + to->u.ssl3.cipherSuite)); } /* @@ -476,7 +479,6 @@ ConvertToSID(sidCacheEntry *from, to->u.ssl3.sessionIDLength = from->sessionIDLength; to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; - to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression; to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; if (from->u.ssl3.srvNameIndex != -1 && psnce) { @@ -541,6 +543,8 @@ ConvertToSID(sidCacheEntry *from, to->authKeyBits = from->authKeyBits; to->keaType = from->keaType; to->keaKeyBits = from->keaKeyBits; + to->keaGroup = from->keaGroup; + to->sigScheme = from->signatureScheme; return to; @@ -748,17 +752,19 @@ ServerSessionIDCache(sslSessionID *sid) PORT_Assert(sid->creationTime != 0); if (!sid->creationTime) - sid->lastAccessTime = sid->creationTime = ssl_Time(); + sid->lastAccessTime = sid->creationTime = ssl_TimeUsec(); /* override caller's expiration time, which uses client timeout * duration, not server timeout duration. */ - sid->expirationTime = sid->creationTime + cache->ssl3Timeout; + sid->expirationTime = + sid->creationTime + cache->ssl3Timeout * PR_USEC_PER_SEC; SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " "cipherSuite=%d", myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], - sid->creationTime, sid->u.ssl3.cipherSuite)); + sid->creationTime / PR_USEC_PER_SEC, + sid->u.ssl3.cipherSuite)); PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength)); @@ -820,7 +826,8 @@ ServerSessionIDUncache(sslSessionID *sid) myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3], - sid->creationTime, sid->u.ssl3.cipherSuite)); + sid->creationTime / PR_USEC_PER_SEC, + sid->u.ssl3.cipherSuite)); PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength); now = LockSet(cache, set, 0); @@ -1086,7 +1093,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData); /* initialize the locks */ - init_time = ssl_Time(); + init_time = ssl_TimeSec(); pLock = cache->sidCacheLocks; for (locks_to_initialize = cache->numSIDCacheLocks + 3; locks_initialized < locks_to_initialize; @@ -1134,6 +1141,10 @@ SSL_SetMaxServerCacheLocks(PRUint32 maxLocks) return SECSuccess; } +PR_STATIC_ASSERT(sizeof(sidCacheEntry) % 16 == 0); +PR_STATIC_ASSERT(sizeof(certCacheEntry) == 4096); +PR_STATIC_ASSERT(sizeof(srvNameCacheEntry) == 1072); + static SECStatus ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache, PRUint32 ssl3_timeout, @@ -1145,10 +1156,6 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache, { SECStatus rv; - PORT_Assert(sizeof(sidCacheEntry) == 192); - PORT_Assert(sizeof(certCacheEntry) == 4096); - PORT_Assert(sizeof(srvNameCacheEntry) == 1072); - rv = ssl_Init(); if (rv != SECSuccess) { return rv; @@ -1519,7 +1526,7 @@ LockPoller(void *arg) if (sharedCache->stopPolling) break; - now = ssl_Time(); + now = ssl_TimeSec(); then = now - expiration; for (pLock = cache->sidCacheLocks, locks_polled = 0; locks_to_poll > locks_polled && !sharedCache->stopPolling; diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 99828c85b..4893cb9f9 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -11,6 +11,7 @@ #include "cert.h" #include "keyhi.h" #include "ssl.h" +#include "sslexp.h" #include "sslimpl.h" #include "sslproto.h" #include "nspr.h" @@ -79,11 +80,7 @@ static sslOptions ssl_defaults = { PR_FALSE, /* enableSignedCertTimestamps */ PR_FALSE, /* requireDHENamedGroups */ PR_FALSE, /* enable0RttData */ -#ifdef NSS_ENABLE_TLS13_SHORT_HEADERS - PR_TRUE /* enableShortHeaders */ -#else - PR_FALSE /* enableShortHeaders */ -#endif + PR_FALSE /* enableTls13CompatMode */ }; /* @@ -110,7 +107,6 @@ sslSessionIDLookupFunc ssl_sid_lookup; sslSessionIDCacheFunc ssl_sid_cache; sslSessionIDUncacheFunc ssl_sid_uncache; -static PRBool ssl_inited = PR_FALSE; static PRDescIdentity ssl_layer_id; PRBool locksEverDisabled; /* implicitly PR_FALSE */ @@ -122,6 +118,7 @@ FILE *ssl_trace_iob; #ifdef NSS_ALLOW_SSLKEYLOGFILE FILE *ssl_keylog_iob; +PZLock *ssl_keylog_lock; #endif char lockStatus[] = "Locks are ENABLED. "; @@ -300,6 +297,7 @@ ssl_DupSocket(sslSocket *os) if (ss->opt.useSecurity) { PRCList *cursor; + for (cursor = PR_NEXT_LINK(&os->serverCerts); cursor != &os->serverCerts; cursor = PR_NEXT_LINK(cursor)) { @@ -309,7 +307,6 @@ ssl_DupSocket(sslSocket *os) PR_APPEND_LINK(&sc->link, &ss->serverCerts); } - PR_INIT_CLIST(&ss->ephemeralKeyPairs); for (cursor = PR_NEXT_LINK(&os->ephemeralKeyPairs); cursor != &os->ephemeralKeyPairs; cursor = PR_NEXT_LINK(cursor)) { @@ -320,6 +317,18 @@ ssl_DupSocket(sslSocket *os) PR_APPEND_LINK(&skp->link, &ss->ephemeralKeyPairs); } + for (cursor = PR_NEXT_LINK(&os->extensionHooks); + cursor != &os->extensionHooks; + cursor = PR_NEXT_LINK(cursor)) { + sslCustomExtensionHooks *oh = (sslCustomExtensionHooks *)cursor; + sslCustomExtensionHooks *sh = PORT_ZNew(sslCustomExtensionHooks); + if (!sh) { + goto loser; + } + *sh = *oh; + PR_APPEND_LINK(&sh->link, &ss->extensionHooks); + } + /* * XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL. * XXX We should detect this, and not just march on with NULL pointers. @@ -354,6 +363,7 @@ ssl_DupSocket(sslSocket *os) goto loser; } } + return ss; loser: @@ -422,9 +432,16 @@ ssl_DestroySocketContents(sslSocket *ss) PR_REMOVE_LINK(cursor); ssl_FreeServerCert((sslServerCert *)cursor); } + + /* Remove extension handlers. */ + ssl_ClearPRCList(&ss->extensionHooks, NULL); + ssl_FreeEphemeralKeyPairs(ss); SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE); ssl3_FreeSniNameArray(&ss->xtnData); + + ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL); + ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL); } /* @@ -501,7 +518,7 @@ PrepareSocket(sslSocket *ss) } SECStatus -SSL_Enable(PRFileDesc *fd, int which, PRBool on) +SSL_Enable(PRFileDesc *fd, int which, PRIntn on) { return SSL_OptionSet(fd, which, on); } @@ -513,9 +530,9 @@ static PRBool ssl_VersionIsSupportedByPolicy( * ssl.h in the section "SSL version range setting API". */ static void -ssl_EnableTLS(SSLVersionRange *vrange, PRBool on) +ssl_EnableTLS(SSLVersionRange *vrange, PRIntn enable) { - if (on) { + if (enable) { /* don't turn it on if tls1.0 disallowed by by policy */ if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_0)) { @@ -523,14 +540,14 @@ ssl_EnableTLS(SSLVersionRange *vrange, PRBool on) } } if (SSL_ALL_VERSIONS_DISABLED(vrange)) { - if (on) { + if (enable) { vrange->min = SSL_LIBRARY_VERSION_TLS_1_0; vrange->max = SSL_LIBRARY_VERSION_TLS_1_0; } /* else don't change anything */ return; } - if (on) { + if (enable) { /* Expand the range of enabled version to include TLS 1.0 */ vrange->min = PR_MIN(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0); vrange->max = PR_MAX(vrange->max, SSL_LIBRARY_VERSION_TLS_1_0); @@ -550,9 +567,9 @@ ssl_EnableTLS(SSLVersionRange *vrange, PRBool on) * ssl.h in the section "SSL version range setting API". */ static void -ssl_EnableSSL3(SSLVersionRange *vrange, PRBool on) +ssl_EnableSSL3(SSLVersionRange *vrange, PRIntn enable) { - if (on) { + if (enable) { /* don't turn it on if ssl3 disallowed by by policy */ if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, SSL_LIBRARY_VERSION_3_0)) { @@ -560,14 +577,14 @@ ssl_EnableSSL3(SSLVersionRange *vrange, PRBool on) } } if (SSL_ALL_VERSIONS_DISABLED(vrange)) { - if (on) { + if (enable) { vrange->min = SSL_LIBRARY_VERSION_3_0; vrange->max = SSL_LIBRARY_VERSION_3_0; } /* else don't change anything */ return; } - if (on) { + if (enable) { /* Expand the range of enabled versions to include SSL 3.0. We know * SSL 3.0 or some version of TLS is already enabled at this point, so * we don't need to change vrange->max. @@ -586,7 +603,7 @@ ssl_EnableSSL3(SSLVersionRange *vrange, PRBool on) } SECStatus -SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) +SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) { sslSocket *ss = ssl_FindSocket(fd); SECStatus rv = SECSuccess; @@ -605,63 +622,63 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) case SSL_SOCKS: ss->opt.useSocks = PR_FALSE; rv = PrepareSocket(ss); - if (on) { + if (val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SSL_SECURITY: - ss->opt.useSecurity = on; + ss->opt.useSecurity = val; rv = PrepareSocket(ss); break; case SSL_REQUEST_CERTIFICATE: - ss->opt.requestCertificate = on; + ss->opt.requestCertificate = val; break; case SSL_REQUIRE_CERTIFICATE: - ss->opt.requireCertificate = on; + ss->opt.requireCertificate = val; break; case SSL_HANDSHAKE_AS_CLIENT: - if (ss->opt.handshakeAsServer && on) { + if (ss->opt.handshakeAsServer && val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->opt.handshakeAsClient = on; + ss->opt.handshakeAsClient = val; break; case SSL_HANDSHAKE_AS_SERVER: - if (ss->opt.handshakeAsClient && on) { + if (ss->opt.handshakeAsClient && val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->opt.handshakeAsServer = on; + ss->opt.handshakeAsServer = val; break; case SSL_ENABLE_TLS: if (IS_DTLS(ss)) { - if (on) { + if (val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; /* not allowed */ } break; } - ssl_EnableTLS(&ss->vrange, on); + ssl_EnableTLS(&ss->vrange, val); break; case SSL_ENABLE_SSL3: if (IS_DTLS(ss)) { - if (on) { + if (val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; /* not allowed */ } break; } - ssl_EnableSSL3(&ss->vrange, on); + ssl_EnableSSL3(&ss->vrange, val); break; case SSL_ENABLE_SSL2: @@ -670,26 +687,26 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) * However, if an old application requests to disable SSL v2, * we shouldn't fail. */ - if (on) { + if (val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SSL_NO_CACHE: - ss->opt.noCache = on; + ss->opt.noCache = val; break; case SSL_ENABLE_FDX: - if (on && ss->opt.noLocks) { + if (val && ss->opt.noLocks) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } - ss->opt.fdx = on; + ss->opt.fdx = val; break; case SSL_ROLLBACK_DETECTION: - ss->opt.detectRollBack = on; + ss->opt.detectRollBack = val; break; case SSL_NO_STEP_DOWN: @@ -699,14 +716,14 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) break; case SSL_NO_LOCKS: - if (on && ss->opt.fdx) { + if (val && ss->opt.fdx) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } - if (on && ssl_force_locks) - on = PR_FALSE; /* silent override */ - ss->opt.noLocks = on; - if (on) { + if (val && ssl_force_locks) + val = PR_FALSE; /* silent override */ + ss->opt.noLocks = val; + if (val) { locksEverDisabled = PR_TRUE; strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED."); } else if (!holdingLocks) { @@ -718,71 +735,75 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) break; case SSL_ENABLE_SESSION_TICKETS: - ss->opt.enableSessionTickets = on; + ss->opt.enableSessionTickets = val; break; case SSL_ENABLE_DEFLATE: - ss->opt.enableDeflate = on; + ss->opt.enableDeflate = val; break; case SSL_ENABLE_RENEGOTIATION: - if (IS_DTLS(ss) && on != SSL_RENEGOTIATE_NEVER) { + if (IS_DTLS(ss) && val != SSL_RENEGOTIATE_NEVER) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->opt.enableRenegotiation = on; + ss->opt.enableRenegotiation = val; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - ss->opt.requireSafeNegotiation = on; + ss->opt.requireSafeNegotiation = val; break; case SSL_ENABLE_FALSE_START: - ss->opt.enableFalseStart = on; + ss->opt.enableFalseStart = val; break; case SSL_CBC_RANDOM_IV: - ss->opt.cbcRandomIV = on; + ss->opt.cbcRandomIV = val; break; case SSL_ENABLE_OCSP_STAPLING: - ss->opt.enableOCSPStapling = on; + ss->opt.enableOCSPStapling = val; break; case SSL_ENABLE_NPN: break; case SSL_ENABLE_ALPN: - ss->opt.enableALPN = on; + ss->opt.enableALPN = val; break; case SSL_REUSE_SERVER_ECDHE_KEY: - ss->opt.reuseServerECDHEKey = on; + ss->opt.reuseServerECDHEKey = val; break; case SSL_ENABLE_FALLBACK_SCSV: - ss->opt.enableFallbackSCSV = on; + ss->opt.enableFallbackSCSV = val; break; case SSL_ENABLE_SERVER_DHE: - ss->opt.enableServerDhe = on; + ss->opt.enableServerDhe = val; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - ss->opt.enableExtendedMS = on; + ss->opt.enableExtendedMS = val; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - ss->opt.enableSignedCertTimestamps = on; + ss->opt.enableSignedCertTimestamps = val; break; case SSL_REQUIRE_DH_NAMED_GROUPS: - ss->opt.requireDHENamedGroups = on; + ss->opt.requireDHENamedGroups = val; break; case SSL_ENABLE_0RTT_DATA: - ss->opt.enable0RttData = on; + ss->opt.enable0RttData = val; + break; + + case SSL_ENABLE_TLS13_COMPAT_MODE: + ss->opt.enableTls13CompatMode = val; break; default: @@ -804,19 +825,19 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) } SECStatus -SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) +SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal) { sslSocket *ss = ssl_FindSocket(fd); SECStatus rv = SECSuccess; - PRBool on = PR_FALSE; + PRIntn val = PR_FALSE; - if (!pOn) { + if (!pVal) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd)); - *pOn = PR_FALSE; + *pVal = PR_FALSE; return SECFailure; } @@ -825,98 +846,101 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) switch (which) { case SSL_SOCKS: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_SECURITY: - on = ss->opt.useSecurity; + val = ss->opt.useSecurity; break; case SSL_REQUEST_CERTIFICATE: - on = ss->opt.requestCertificate; + val = ss->opt.requestCertificate; break; case SSL_REQUIRE_CERTIFICATE: - on = ss->opt.requireCertificate; + val = ss->opt.requireCertificate; break; case SSL_HANDSHAKE_AS_CLIENT: - on = ss->opt.handshakeAsClient; + val = ss->opt.handshakeAsClient; break; case SSL_HANDSHAKE_AS_SERVER: - on = ss->opt.handshakeAsServer; + val = ss->opt.handshakeAsServer; break; case SSL_ENABLE_TLS: - on = ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_0; + val = ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_0; break; case SSL_ENABLE_SSL3: - on = ss->vrange.min == SSL_LIBRARY_VERSION_3_0; + val = ss->vrange.min == SSL_LIBRARY_VERSION_3_0; break; case SSL_ENABLE_SSL2: case SSL_V2_COMPATIBLE_HELLO: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_NO_CACHE: - on = ss->opt.noCache; + val = ss->opt.noCache; break; case SSL_ENABLE_FDX: - on = ss->opt.fdx; + val = ss->opt.fdx; break; case SSL_ROLLBACK_DETECTION: - on = ss->opt.detectRollBack; + val = ss->opt.detectRollBack; break; case SSL_NO_STEP_DOWN: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_BYPASS_PKCS11: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_NO_LOCKS: - on = ss->opt.noLocks; + val = ss->opt.noLocks; break; case SSL_ENABLE_SESSION_TICKETS: - on = ss->opt.enableSessionTickets; + val = ss->opt.enableSessionTickets; break; case SSL_ENABLE_DEFLATE: - on = ss->opt.enableDeflate; + val = ss->opt.enableDeflate; break; case SSL_ENABLE_RENEGOTIATION: - on = ss->opt.enableRenegotiation; + val = ss->opt.enableRenegotiation; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - on = ss->opt.requireSafeNegotiation; + val = ss->opt.requireSafeNegotiation; break; case SSL_ENABLE_FALSE_START: - on = ss->opt.enableFalseStart; + val = ss->opt.enableFalseStart; break; case SSL_CBC_RANDOM_IV: - on = ss->opt.cbcRandomIV; + val = ss->opt.cbcRandomIV; break; case SSL_ENABLE_OCSP_STAPLING: - on = ss->opt.enableOCSPStapling; + val = ss->opt.enableOCSPStapling; break; case SSL_ENABLE_NPN: - on = ss->opt.enableNPN; + val = ss->opt.enableNPN; break; case SSL_ENABLE_ALPN: - on = ss->opt.enableALPN; + val = ss->opt.enableALPN; break; case SSL_REUSE_SERVER_ECDHE_KEY: - on = ss->opt.reuseServerECDHEKey; + val = ss->opt.reuseServerECDHEKey; break; case SSL_ENABLE_FALLBACK_SCSV: - on = ss->opt.enableFallbackSCSV; + val = ss->opt.enableFallbackSCSV; break; case SSL_ENABLE_SERVER_DHE: - on = ss->opt.enableServerDhe; + val = ss->opt.enableServerDhe; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - on = ss->opt.enableExtendedMS; + val = ss->opt.enableExtendedMS; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - on = ss->opt.enableSignedCertTimestamps; + val = ss->opt.enableSignedCertTimestamps; break; case SSL_REQUIRE_DH_NAMED_GROUPS: - on = ss->opt.requireDHENamedGroups; + val = ss->opt.requireDHENamedGroups; break; case SSL_ENABLE_0RTT_DATA: - on = ss->opt.enable0RttData; + val = ss->opt.enable0RttData; + break; + case SSL_ENABLE_TLS13_COMPAT_MODE: + val = ss->opt.enableTls13CompatMode; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -926,17 +950,17 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); - *pOn = on; + *pVal = val; return rv; } SECStatus -SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) +SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal) { SECStatus rv = SECSuccess; - PRBool on = PR_FALSE; + PRIntn val = PR_FALSE; - if (!pOn) { + if (!pVal) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } @@ -945,114 +969,117 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) switch (which) { case SSL_SOCKS: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_SECURITY: - on = ssl_defaults.useSecurity; + val = ssl_defaults.useSecurity; break; case SSL_REQUEST_CERTIFICATE: - on = ssl_defaults.requestCertificate; + val = ssl_defaults.requestCertificate; break; case SSL_REQUIRE_CERTIFICATE: - on = ssl_defaults.requireCertificate; + val = ssl_defaults.requireCertificate; break; case SSL_HANDSHAKE_AS_CLIENT: - on = ssl_defaults.handshakeAsClient; + val = ssl_defaults.handshakeAsClient; break; case SSL_HANDSHAKE_AS_SERVER: - on = ssl_defaults.handshakeAsServer; + val = ssl_defaults.handshakeAsServer; break; case SSL_ENABLE_TLS: - on = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0; + val = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0; break; case SSL_ENABLE_SSL3: - on = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0; + val = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0; break; case SSL_ENABLE_SSL2: case SSL_V2_COMPATIBLE_HELLO: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_NO_CACHE: - on = ssl_defaults.noCache; + val = ssl_defaults.noCache; break; case SSL_ENABLE_FDX: - on = ssl_defaults.fdx; + val = ssl_defaults.fdx; break; case SSL_ROLLBACK_DETECTION: - on = ssl_defaults.detectRollBack; + val = ssl_defaults.detectRollBack; break; case SSL_NO_STEP_DOWN: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_BYPASS_PKCS11: - on = PR_FALSE; + val = PR_FALSE; break; case SSL_NO_LOCKS: - on = ssl_defaults.noLocks; + val = ssl_defaults.noLocks; break; case SSL_ENABLE_SESSION_TICKETS: - on = ssl_defaults.enableSessionTickets; + val = ssl_defaults.enableSessionTickets; break; case SSL_ENABLE_DEFLATE: - on = ssl_defaults.enableDeflate; + val = ssl_defaults.enableDeflate; break; case SSL_ENABLE_RENEGOTIATION: - on = ssl_defaults.enableRenegotiation; + val = ssl_defaults.enableRenegotiation; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - on = ssl_defaults.requireSafeNegotiation; + val = ssl_defaults.requireSafeNegotiation; break; case SSL_ENABLE_FALSE_START: - on = ssl_defaults.enableFalseStart; + val = ssl_defaults.enableFalseStart; break; case SSL_CBC_RANDOM_IV: - on = ssl_defaults.cbcRandomIV; + val = ssl_defaults.cbcRandomIV; break; case SSL_ENABLE_OCSP_STAPLING: - on = ssl_defaults.enableOCSPStapling; + val = ssl_defaults.enableOCSPStapling; break; case SSL_ENABLE_NPN: - on = ssl_defaults.enableNPN; + val = ssl_defaults.enableNPN; break; case SSL_ENABLE_ALPN: - on = ssl_defaults.enableALPN; + val = ssl_defaults.enableALPN; break; case SSL_REUSE_SERVER_ECDHE_KEY: - on = ssl_defaults.reuseServerECDHEKey; + val = ssl_defaults.reuseServerECDHEKey; break; case SSL_ENABLE_FALLBACK_SCSV: - on = ssl_defaults.enableFallbackSCSV; + val = ssl_defaults.enableFallbackSCSV; break; case SSL_ENABLE_SERVER_DHE: - on = ssl_defaults.enableServerDhe; + val = ssl_defaults.enableServerDhe; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - on = ssl_defaults.enableExtendedMS; + val = ssl_defaults.enableExtendedMS; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - on = ssl_defaults.enableSignedCertTimestamps; + val = ssl_defaults.enableSignedCertTimestamps; break; case SSL_ENABLE_0RTT_DATA: - on = ssl_defaults.enable0RttData; + val = ssl_defaults.enable0RttData; + break; + case SSL_ENABLE_TLS13_COMPAT_MODE: + val = ssl_defaults.enableTls13CompatMode; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } - *pOn = on; + *pVal = val; return rv; } /* XXX Use Global Lock to protect this stuff. */ SECStatus -SSL_EnableDefault(int which, PRBool on) +SSL_EnableDefault(int which, PRIntn val) { - return SSL_OptionSetDefault(which, on); + return SSL_OptionSetDefault(which, val); } SECStatus -SSL_OptionSetDefault(PRInt32 which, PRBool on) +SSL_OptionSetDefault(PRInt32 which, PRIntn val) { SECStatus status = ssl_Init(); @@ -1065,46 +1092,46 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) switch (which) { case SSL_SOCKS: ssl_defaults.useSocks = PR_FALSE; - if (on) { + if (val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } break; case SSL_SECURITY: - ssl_defaults.useSecurity = on; + ssl_defaults.useSecurity = val; break; case SSL_REQUEST_CERTIFICATE: - ssl_defaults.requestCertificate = on; + ssl_defaults.requestCertificate = val; break; case SSL_REQUIRE_CERTIFICATE: - ssl_defaults.requireCertificate = on; + ssl_defaults.requireCertificate = val; break; case SSL_HANDSHAKE_AS_CLIENT: - if (ssl_defaults.handshakeAsServer && on) { + if (ssl_defaults.handshakeAsServer && val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - ssl_defaults.handshakeAsClient = on; + ssl_defaults.handshakeAsClient = val; break; case SSL_HANDSHAKE_AS_SERVER: - if (ssl_defaults.handshakeAsClient && on) { + if (ssl_defaults.handshakeAsClient && val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - ssl_defaults.handshakeAsServer = on; + ssl_defaults.handshakeAsServer = val; break; case SSL_ENABLE_TLS: - ssl_EnableTLS(&versions_defaults_stream, on); + ssl_EnableTLS(&versions_defaults_stream, val); break; case SSL_ENABLE_SSL3: - ssl_EnableSSL3(&versions_defaults_stream, on); + ssl_EnableSSL3(&versions_defaults_stream, val); break; case SSL_ENABLE_SSL2: @@ -1113,26 +1140,26 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) * However, if an old application requests to disable SSL v2, * we shouldn't fail. */ - if (on) { + if (val) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } break; case SSL_NO_CACHE: - ssl_defaults.noCache = on; + ssl_defaults.noCache = val; break; case SSL_ENABLE_FDX: - if (on && ssl_defaults.noLocks) { + if (val && ssl_defaults.noLocks) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - ssl_defaults.fdx = on; + ssl_defaults.fdx = val; break; case SSL_ROLLBACK_DETECTION: - ssl_defaults.detectRollBack = on; + ssl_defaults.detectRollBack = val; break; case SSL_NO_STEP_DOWN: @@ -1142,76 +1169,80 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) break; case SSL_NO_LOCKS: - if (on && ssl_defaults.fdx) { + if (val && ssl_defaults.fdx) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - if (on && ssl_force_locks) - on = PR_FALSE; /* silent override */ - ssl_defaults.noLocks = on; - if (on) { + if (val && ssl_force_locks) + val = PR_FALSE; /* silent override */ + ssl_defaults.noLocks = val; + if (val) { locksEverDisabled = PR_TRUE; strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED."); } break; case SSL_ENABLE_SESSION_TICKETS: - ssl_defaults.enableSessionTickets = on; + ssl_defaults.enableSessionTickets = val; break; case SSL_ENABLE_DEFLATE: - ssl_defaults.enableDeflate = on; + ssl_defaults.enableDeflate = val; break; case SSL_ENABLE_RENEGOTIATION: - ssl_defaults.enableRenegotiation = on; + ssl_defaults.enableRenegotiation = val; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - ssl_defaults.requireSafeNegotiation = on; + ssl_defaults.requireSafeNegotiation = val; break; case SSL_ENABLE_FALSE_START: - ssl_defaults.enableFalseStart = on; + ssl_defaults.enableFalseStart = val; break; case SSL_CBC_RANDOM_IV: - ssl_defaults.cbcRandomIV = on; + ssl_defaults.cbcRandomIV = val; break; case SSL_ENABLE_OCSP_STAPLING: - ssl_defaults.enableOCSPStapling = on; + ssl_defaults.enableOCSPStapling = val; break; case SSL_ENABLE_NPN: break; case SSL_ENABLE_ALPN: - ssl_defaults.enableALPN = on; + ssl_defaults.enableALPN = val; break; case SSL_REUSE_SERVER_ECDHE_KEY: - ssl_defaults.reuseServerECDHEKey = on; + ssl_defaults.reuseServerECDHEKey = val; break; case SSL_ENABLE_FALLBACK_SCSV: - ssl_defaults.enableFallbackSCSV = on; + ssl_defaults.enableFallbackSCSV = val; break; case SSL_ENABLE_SERVER_DHE: - ssl_defaults.enableServerDhe = on; + ssl_defaults.enableServerDhe = val; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - ssl_defaults.enableExtendedMS = on; + ssl_defaults.enableExtendedMS = val; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - ssl_defaults.enableSignedCertTimestamps = on; + ssl_defaults.enableSignedCertTimestamps = val; break; case SSL_ENABLE_0RTT_DATA: - ssl_defaults.enable0RttData = on; + ssl_defaults.enable0RttData = val; + break; + + case SSL_ENABLE_TLS13_COMPAT_MODE: + ssl_defaults.enableTls13CompatMode = val; break; default: @@ -2124,6 +2155,25 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) return NULL; PR_APPEND_LINK(&skp->link, &ss->ephemeralKeyPairs); } + + while (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) { + cursor = PR_LIST_TAIL(&ss->extensionHooks); + PR_REMOVE_LINK(cursor); + PORT_Free(cursor); + } + for (cursor = PR_NEXT_LINK(&sm->extensionHooks); + cursor != &sm->extensionHooks; + cursor = PR_NEXT_LINK(cursor)) { + SECStatus rv; + sslCustomExtensionHooks *hook = (sslCustomExtensionHooks *)cursor; + rv = SSL_InstallExtensionHooks(ss->fd, hook->type, + hook->writer, hook->writerArg, + hook->handler, hook->handlerArg); + if (rv != SECSuccess) { + return NULL; + } + } + PORT_Memcpy((void *)ss->namedGroupPreferences, sm->namedGroupPreferences, sizeof(ss->namedGroupPreferences)); @@ -2214,7 +2264,7 @@ ssl3_GetEffectiveVersionPolicy(SSLProtocolVariant variant, return SECSuccess; } -/* +/* * Assumes that rangeParam values are within the supported boundaries, * but should contain all potentially allowed versions, even if they contain * conflicting versions. @@ -3124,7 +3174,7 @@ ssl_WriteV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 vectors, } blocking = ssl_FdIsBlocking(fd); -#define K16 sizeof(buf) +#define K16 ((int)sizeof(buf)) #define KILL_VECTORS \ while (vectors && !iov->iov_len) { \ ++iov; \ @@ -3411,7 +3461,6 @@ ssl_InitIOLayer(void) { ssl_layer_id = PR_GetUniqueIdentity("SSL"); ssl_SetupIOMethods(); - ssl_inited = PR_TRUE; return PR_SUCCESS; } @@ -3421,15 +3470,13 @@ ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, PRDescIdentity id) PRFileDesc *layer = NULL; PRStatus status; - if (!ssl_inited) { - status = PR_CallOnce(&initIoLayerOnce, &ssl_InitIOLayer); - if (status != PR_SUCCESS) - goto loser; + status = PR_CallOnce(&initIoLayerOnce, &ssl_InitIOLayer); + if (status != PR_SUCCESS) { + goto loser; } - - if (ns == NULL) + if (ns == NULL) { goto loser; - + } layer = PR_CreateIOLayerStub(ssl_layer_id, &combined_methods); if (layer == NULL) goto loser; @@ -3542,6 +3589,12 @@ ssl_SetDefaultsFromEnvironment(void) ssl_keylog_iob); } SSL_TRACE(("SSL: logging SSL/TLS secrets to %s", ev)); + ssl_keylog_lock = PR_NewLock(); + if (!ssl_keylog_lock) { + SSL_TRACE(("SSL: failed to create key log lock")); + fclose(ssl_keylog_iob); + ssl_keylog_iob = NULL; + } } } #endif @@ -3746,7 +3799,6 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) SECStatus rv; sslSocket *ss; int i; - ssl_SetDefaultsFromEnvironment(); if (ssl_force_locks) @@ -3777,6 +3829,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) PR_INIT_CLIST(&ss->serverCerts); PR_INIT_CLIST(&ss->ephemeralKeyPairs); + PR_INIT_CLIST(&ss->extensionHooks); ss->dbHandle = CERT_GetDefaultCertDB(); @@ -3804,7 +3857,11 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight); PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs); PR_INIT_CLIST(&ss->ssl3.hs.bufferedEarlyData); - ssl3_InitExtensionData(&ss->xtnData); + ssl3_InitExtensionData(&ss->xtnData, ss); + PR_INIT_CLIST(&ss->ssl3.hs.dtlsSentHandshake); + PR_INIT_CLIST(&ss->ssl3.hs.dtlsRcvdHandshake); + dtls_InitTimers(ss); + if (makeLocks) { rv = ssl_MakeLocks(ss); if (rv != SECSuccess) @@ -3816,6 +3873,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) rv = ssl3_InitGather(&ss->gs); if (rv != SECSuccess) goto loser; + rv = ssl3_InitState(ss); + if (rv != SECSuccess) { + goto loser; + } return ss; loser: @@ -3840,3 +3901,69 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey, *pcanbypass = PR_FALSE; return SECSuccess; } + +/* Functions that are truly experimental use EXP, functions that are no longer + * experimental use PUB. + * + * When initially defining a new API, add that API here using the EXP() macro + * and name the function with a SSLExp_ prefix. Define the experimental API as + * a macro in sslexp.h using the SSL_EXPERIMENTAL_API() macro defined there. + * + * Once an API is stable and proven, move the macro definition in sslexp.h to a + * proper function declaration in ssl.h. Keeping the function in this list + * ensures that code built against the release that contained the experimental + * API will continue to work; use PUB() to reference the public function. + */ +#define EXP(n) \ + { \ + "SSL_" #n, SSLExp_##n \ + } +#define PUB(n) \ + { \ + "SSL_" #n, SSL_##n \ + } +struct { + const char *const name; + void *function; +} ssl_experimental_functions[] = { +#ifndef SSL_DISABLE_EXPERIMENTAL_API + EXP(GetExtensionSupport), + EXP(HelloRetryRequestCallback), + EXP(InstallExtensionHooks), + EXP(KeyUpdate), + EXP(SendSessionTicket), + EXP(SetupAntiReplay), +#endif + { "", NULL } +}; +#undef EXP +#undef PUB + +void * +SSL_GetExperimentalAPI(const char *name) +{ + unsigned int i; + for (i = 0; i < PR_ARRAY_SIZE(ssl_experimental_functions); ++i) { + if (strcmp(name, ssl_experimental_functions[i].name) == 0) { + return ssl_experimental_functions[i].function; + } + } + PORT_SetError(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API); + return NULL; +} + +void +ssl_ClearPRCList(PRCList *list, void (*f)(void *)) +{ + PRCList *cursor; + + while (!PR_CLIST_IS_EMPTY(list)) { + cursor = PR_LIST_TAIL(list); + + PR_REMOVE_LINK(cursor); + if (f) { + f(cursor); + } + PORT_Free(cursor); + } +} diff --git a/security/nss/lib/ssl/sslspec.c b/security/nss/lib/ssl/sslspec.c new file mode 100644 index 000000000..26c3eb546 --- /dev/null +++ b/security/nss/lib/ssl/sslspec.c @@ -0,0 +1,273 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Handling of cipher specs. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ssl.h" +#include "sslproto.h" +#include "pk11func.h" +#include "secitem.h" + +#include "sslimpl.h" + +/* Record protection algorithms, indexed by SSL3BulkCipher. + * + * The |max_records| field (|mr| below) is set to a number that is higher than + * recommended in some literature (esp. TLS 1.3) because we currently abort the + * connection when this limit is reached and we want to ensure that we only + * rarely hit this limit. See bug 1268745 for details. + */ +#define MR_MAX RECORD_SEQ_MAX /* 2^48-1 */ +#define MR_128 (0x5aULL << 28) /* For AES and similar. */ +#define MR_LOW (1ULL << 20) /* For weak ciphers. */ +/* clang-format off */ +static const ssl3BulkCipherDef ssl_bulk_cipher_defs[] = { + /* |--------- Lengths ---------| */ + /* cipher calg : s : */ + /* : e b n */ + /* oid short_name mr : c l o */ + /* k r o t n */ + /* e e i c a c */ + /* y t type v k g e */ + {cipher_null, ssl_calg_null, 0, 0, type_stream, 0, 0, 0, 0, + SEC_OID_NULL_CIPHER, "NULL", MR_MAX}, + {cipher_rc4, ssl_calg_rc4, 16,16, type_stream, 0, 0, 0, 0, + SEC_OID_RC4, "RC4", MR_LOW}, + {cipher_des, ssl_calg_des, 8, 8, type_block, 8, 8, 0, 0, + SEC_OID_DES_CBC, "DES-CBC", MR_LOW}, + {cipher_3des, ssl_calg_3des, 24,24, type_block, 8, 8, 0, 0, + SEC_OID_DES_EDE3_CBC, "3DES-EDE-CBC", MR_LOW}, + {cipher_aes_128, ssl_calg_aes, 16,16, type_block, 16,16, 0, 0, + SEC_OID_AES_128_CBC, "AES-128", MR_128}, + {cipher_aes_256, ssl_calg_aes, 32,32, type_block, 16,16, 0, 0, + SEC_OID_AES_256_CBC, "AES-256", MR_128}, + {cipher_camellia_128, ssl_calg_camellia, 16,16, type_block, 16,16, 0, 0, + SEC_OID_CAMELLIA_128_CBC, "Camellia-128", MR_128}, + {cipher_camellia_256, ssl_calg_camellia, 32,32, type_block, 16,16, 0, 0, + SEC_OID_CAMELLIA_256_CBC, "Camellia-256", MR_128}, + {cipher_seed, ssl_calg_seed, 16,16, type_block, 16,16, 0, 0, + SEC_OID_SEED_CBC, "SEED-CBC", MR_128}, + {cipher_aes_128_gcm, ssl_calg_aes_gcm, 16,16, type_aead, 4, 0,16, 8, + SEC_OID_AES_128_GCM, "AES-128-GCM", MR_128}, + {cipher_aes_256_gcm, ssl_calg_aes_gcm, 32,32, type_aead, 4, 0,16, 8, + SEC_OID_AES_256_GCM, "AES-256-GCM", MR_128}, + {cipher_chacha20, ssl_calg_chacha20, 32,32, type_aead, 12, 0,16, 0, + SEC_OID_CHACHA20_POLY1305, "ChaCha20-Poly1305", MR_MAX}, + {cipher_missing, ssl_calg_null, 0, 0, type_stream, 0, 0, 0, 0, + SEC_OID_UNKNOWN, "missing", 0U}, +}; +/* clang-format on */ + +const ssl3BulkCipherDef * +ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *suiteDef) +{ + SSL3BulkCipher bulkCipher = suiteDef->bulk_cipher_alg; + PORT_Assert(bulkCipher < PR_ARRAY_SIZE(ssl_bulk_cipher_defs)); + PORT_Assert(ssl_bulk_cipher_defs[bulkCipher].cipher == bulkCipher); + return &ssl_bulk_cipher_defs[bulkCipher]; +} + +/* indexed by SSL3MACAlgorithm */ +static const ssl3MACDef ssl_mac_defs[] = { + /* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */ + /* mac mmech pad_size mac_size */ + { ssl_mac_null, CKM_INVALID_MECHANISM, 0, 0, 0 }, + { ssl_mac_md5, CKM_SSL3_MD5_MAC, 48, MD5_LENGTH, SEC_OID_HMAC_MD5 }, + { ssl_mac_sha, CKM_SSL3_SHA1_MAC, 40, SHA1_LENGTH, SEC_OID_HMAC_SHA1 }, + { ssl_hmac_md5, CKM_MD5_HMAC, 0, MD5_LENGTH, SEC_OID_HMAC_MD5 }, + { ssl_hmac_sha, CKM_SHA_1_HMAC, 0, SHA1_LENGTH, SEC_OID_HMAC_SHA1 }, + { ssl_hmac_sha256, CKM_SHA256_HMAC, 0, SHA256_LENGTH, SEC_OID_HMAC_SHA256 }, + { ssl_mac_aead, CKM_INVALID_MECHANISM, 0, 0, 0 }, + { ssl_hmac_sha384, CKM_SHA384_HMAC, 0, SHA384_LENGTH, SEC_OID_HMAC_SHA384 } +}; + +const ssl3MACDef * +ssl_GetMacDefByAlg(SSL3MACAlgorithm mac) +{ + /* Cast here for clang: https://bugs.llvm.org/show_bug.cgi?id=16154 */ + PORT_Assert((size_t)mac < PR_ARRAY_SIZE(ssl_mac_defs)); + PORT_Assert(ssl_mac_defs[mac].mac == mac); + return &ssl_mac_defs[mac]; +} + +const ssl3MACDef * +ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef) +{ + SSL3MACAlgorithm mac = suiteDef->mac_alg; + if (ss->version > SSL_LIBRARY_VERSION_3_0) { + switch (mac) { + case ssl_mac_md5: + mac = ssl_hmac_md5; + break; + case ssl_mac_sha: + mac = ssl_hmac_sha; + break; + default: + break; + } + } + return ssl_GetMacDefByAlg(mac); +} + +ssl3CipherSpec * +ssl_FindCipherSpecByEpoch(sslSocket *ss, CipherSpecDirection direction, + DTLSEpoch epoch) +{ + PRCList *cur_p; + for (cur_p = PR_LIST_HEAD(&ss->ssl3.hs.cipherSpecs); + cur_p != &ss->ssl3.hs.cipherSpecs; + cur_p = PR_NEXT_LINK(cur_p)) { + ssl3CipherSpec *spec = (ssl3CipherSpec *)cur_p; + + if (spec->epoch != epoch) { + continue; + } + if (direction != spec->direction) { + continue; + } + return spec; + } + return NULL; +} + +ssl3CipherSpec * +ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction) +{ + ssl3CipherSpec *spec = PORT_ZNew(ssl3CipherSpec); + if (!spec) { + return NULL; + } + spec->refCt = 1; + spec->version = ss->version; + spec->direction = direction; + SSL_TRC(10, ("%d: SSL[%d]: new %s spec %d ct=%d", + SSL_GETPID(), ss->fd, SPEC_DIR(spec), spec, + spec->refCt)); + return spec; +} + +void +ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) +{ + PR_APPEND_LINK(&spec->link, &ss->ssl3.hs.cipherSpecs); +} + +/* Called from ssl3_InitState. */ +/* Caller must hold the SpecWriteLock. */ +SECStatus +ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir) +{ + ssl3CipherSpec *spec; + + PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); + + spec = ssl_CreateCipherSpec(ss, dir); + if (!spec) { + return SECFailure; + } + + /* Set default versions. This value will be used to generate and send + * alerts if a version is not negotiated. These values are overridden when + * sending a ClientHello and when a version is negotiated. */ + spec->version = SSL_LIBRARY_VERSION_TLS_1_0; + spec->recordVersion = IS_DTLS(ss) + ? SSL_LIBRARY_VERSION_DTLS_1_0_WIRE + : SSL_LIBRARY_VERSION_TLS_1_0; + spec->cipherDef = &ssl_bulk_cipher_defs[cipher_null]; + PORT_Assert(spec->cipherDef->cipher == cipher_null); + spec->macDef = &ssl_mac_defs[ssl_mac_null]; + PORT_Assert(spec->macDef->mac == ssl_mac_null); + spec->cipher = Null_Cipher; + + spec->phase = "cleartext"; + dtls_InitRecvdRecords(&spec->recvdRecords); + + ssl_SaveCipherSpec(ss, spec); + if (dir == CipherSpecRead) { + ss->ssl3.crSpec = spec; + } else { + ss->ssl3.cwSpec = spec; + } + return SECSuccess; +} + +void +ssl_CipherSpecAddRef(ssl3CipherSpec *spec) +{ + ++spec->refCt; + SSL_TRC(10, ("%d: SSL[-]: Increment ref ct for %s spec %d. new ct = %d", + SSL_GETPID(), SPEC_DIR(spec), spec, spec->refCt)); +} + +static void +ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial) +{ + PK11_FreeSymKey(keyMaterial->key); + PK11_FreeSymKey(keyMaterial->macKey); + if (keyMaterial->macContext != NULL) { + PK11_DestroyContext(keyMaterial->macContext, PR_TRUE); + } +} + +static void +ssl_FreeCipherSpec(ssl3CipherSpec *spec) +{ + SSL_TRC(10, ("%d: SSL[-]: Freeing %s spec %d. epoch=%d", + SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch)); + + PR_REMOVE_LINK(&spec->link); + + /* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ + if (spec->cipherContext) { + PK11_DestroyContext(spec->cipherContext, PR_TRUE); + } + PK11_FreeSymKey(spec->masterSecret); + ssl_DestroyKeyMaterial(&spec->keyMaterial); + + PORT_ZFree(spec, sizeof(*spec)); +} + +/* This function is never called on a spec which is on the + * cipherSpecs list. */ +void +ssl_CipherSpecRelease(ssl3CipherSpec *spec) +{ + if (!spec) { + return; + } + + PORT_Assert(spec->refCt > 0); + --spec->refCt; + SSL_TRC(10, ("%d: SSL[-]: decrement refct for %s spec %d. epoch=%d new ct = %d", + SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch, spec->refCt)); + if (!spec->refCt) { + ssl_FreeCipherSpec(spec); + } +} + +void +ssl_DestroyCipherSpecs(PRCList *list) +{ + while (!PR_CLIST_IS_EMPTY(list)) { + ssl3CipherSpec *spec = (ssl3CipherSpec *)PR_LIST_TAIL(list); + ssl_FreeCipherSpec(spec); + } +} + +void +ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection dir, + DTLSEpoch epoch) +{ + ssl3CipherSpec *spec; + SSL_TRC(10, ("%d: SSL[%d]: releasing %s cipher spec for epoch %d", + SSL_GETPID(), ss->fd, + (dir == CipherSpecRead) ? "read" : "write", epoch)); + + spec = ssl_FindCipherSpecByEpoch(ss, dir, epoch); + if (spec) { + ssl_CipherSpecRelease(spec); + } +} diff --git a/security/nss/lib/ssl/sslspec.h b/security/nss/lib/ssl/sslspec.h new file mode 100644 index 000000000..729ac1006 --- /dev/null +++ b/security/nss/lib/ssl/sslspec.h @@ -0,0 +1,194 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __sslspec_h_ +#define __sslspec_h_ + +#include "sslexp.h" +#include "prclist.h" + +typedef enum { + TrafficKeyClearText = 0, + TrafficKeyEarlyApplicationData = 1, + TrafficKeyHandshake = 2, + TrafficKeyApplicationData = 3 +} TrafficKeyType; + +typedef enum { + CipherSpecRead, + CipherSpecWrite, +} CipherSpecDirection; + +#define SPEC_DIR(spec) \ + ((spec->direction == CipherSpecRead) ? "read" : "write") + +typedef struct ssl3CipherSpecStr ssl3CipherSpec; +typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef; +typedef struct ssl3MACDefStr ssl3MACDef; +typedef struct ssl3CipherSuiteDefStr ssl3CipherSuiteDef; +typedef PRUint64 sslSequenceNumber; +typedef PRUint16 DTLSEpoch; + +/* The SSL bulk cipher definition */ +typedef enum { + cipher_null, + cipher_rc4, + cipher_des, + cipher_3des, + cipher_aes_128, + cipher_aes_256, + cipher_camellia_128, + cipher_camellia_256, + cipher_seed, + cipher_aes_128_gcm, + cipher_aes_256_gcm, + cipher_chacha20, + cipher_missing /* reserved for no such supported cipher */ + /* This enum must match ssl3_cipherName[] in ssl3con.c. */ +} SSL3BulkCipher; + +typedef enum { + type_stream, + type_block, + type_aead +} CipherType; + +/* +** There are tables of these, all const. +*/ +struct ssl3BulkCipherDefStr { + SSL3BulkCipher cipher; + SSLCipherAlgorithm calg; + unsigned int key_size; + unsigned int secret_key_size; + CipherType type; + unsigned int iv_size; + unsigned int block_size; + unsigned int tag_size; /* for AEAD ciphers. */ + unsigned int explicit_nonce_size; /* for AEAD ciphers. */ + SECOidTag oid; + const char *short_name; + /* The maximum number of records that can be sent/received with the same + * symmetric key before the connection will be terminated. */ + PRUint64 max_records; +}; + +/* to make some of these old enums public without namespace pollution, +** it was necessary to prepend ssl_ to the names. +** These #defines preserve compatibility with the old code here in libssl. +*/ +typedef SSLMACAlgorithm SSL3MACAlgorithm; + +/* + * There are tables of these, all const. + */ +struct ssl3MACDefStr { + SSL3MACAlgorithm mac; + CK_MECHANISM_TYPE mmech; + int pad_size; + int mac_size; + SECOidTag oid; +}; + +#define MAX_IV_LENGTH 24 + +typedef struct { + PK11SymKey *key; + PK11SymKey *macKey; + PK11Context *macContext; + PRUint8 iv[MAX_IV_LENGTH]; +} ssl3KeyMaterial; + +typedef SECStatus (*SSLCipher)(void *context, + unsigned char *out, + int *outlen, + int maxout, + const unsigned char *in, + int inlen); +typedef SECStatus (*SSLAEADCipher)( + ssl3KeyMaterial *keys, + PRBool doDecrypt, + unsigned char *out, + int *outlen, + int maxout, + const unsigned char *in, + int inlen, + const unsigned char *additionalData, + int additionalDataLen); + +/* The DTLS anti-replay window in number of packets. Defined here because we + * need it in the cipher spec. Note that this is a ring buffer but left and + * right represent the true window, with modular arithmetic used to map them + * onto the buffer. + */ +#define DTLS_RECVD_RECORDS_WINDOW 1024 +#define RECORD_SEQ_MASK ((1ULL << 48) - 1) +#define RECORD_SEQ_MAX RECORD_SEQ_MASK +PR_STATIC_ASSERT(DTLS_RECVD_RECORDS_WINDOW % 8 == 0); + +typedef struct DTLSRecvdRecordsStr { + unsigned char data[DTLS_RECVD_RECORDS_WINDOW / 8]; + sslSequenceNumber left; + sslSequenceNumber right; +} DTLSRecvdRecords; + +/* + * These are the "specs" used for reading and writing records. Access to the + * pointers to these specs, and all the specs' contents (direct and indirect) is + * protected by the reader/writer lock ss->specLock. + */ +struct ssl3CipherSpecStr { + PRCList link; + PRUint8 refCt; + + CipherSpecDirection direction; + SSL3ProtocolVersion version; + SSL3ProtocolVersion recordVersion; + + const ssl3BulkCipherDef *cipherDef; + const ssl3MACDef *macDef; + + SSLCipher cipher; + SSLAEADCipher aead; + void *cipherContext; + + PK11SymKey *masterSecret; + ssl3KeyMaterial keyMaterial; + + DTLSEpoch epoch; + const char *phase; + sslSequenceNumber seqNum; + 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; +}; + +typedef void (*sslCipherSpecChangedFunc)(void *arg, + PRBool sending, + ssl3CipherSpec *newSpec); + +const ssl3BulkCipherDef *ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def); +const ssl3MACDef *ssl_GetMacDefByAlg(SSL3MACAlgorithm mac); +const ssl3MACDef *ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef); + +ssl3CipherSpec *ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction); +void ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec); +void ssl_CipherSpecAddRef(ssl3CipherSpec *spec); +void ssl_CipherSpecRelease(ssl3CipherSpec *spec); +void ssl_DestroyCipherSpecs(PRCList *list); +SECStatus ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir); + +ssl3CipherSpec *ssl_FindCipherSpecByEpoch(sslSocket *ss, + CipherSpecDirection direction, + DTLSEpoch epoch); +void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection direction, + DTLSEpoch epoch); + +#endif /* __sslspec_h_ */ diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h index bd9a2ae88..ce8f6e281 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/lib/ssl/sslt.h @@ -13,6 +13,28 @@ #include "secitem.h" #include "certt.h" +typedef enum { + ssl_hs_hello_request = 0, + ssl_hs_client_hello = 1, + ssl_hs_server_hello = 2, + ssl_hs_hello_verify_request = 3, + ssl_hs_new_session_ticket = 4, + ssl_hs_end_of_early_data = 5, + ssl_hs_hello_retry_request = 6, + ssl_hs_encrypted_extensions = 8, + ssl_hs_certificate = 11, + ssl_hs_server_key_exchange = 12, + ssl_hs_certificate_request = 13, + ssl_hs_server_hello_done = 14, + ssl_hs_certificate_verify = 15, + ssl_hs_client_key_exchange = 16, + ssl_hs_finished = 20, + ssl_hs_certificate_status = 22, + ssl_hs_key_update = 24, + ssl_hs_next_proto = 67, + ssl_hs_message_hash = 254, /* Not a real message. */ +} SSLHandshakeType; + typedef struct SSL3StatisticsStr { /* statistics from ssl3_SendClientHello (sch) */ long sch_sid_cache_hits; @@ -275,6 +297,14 @@ typedef struct SSLChannelInfoStr { SSLAuthType authType; SSLSignatureScheme signatureScheme; + /* The following fields were added in NSS 3.34. */ + /* When the session was resumed this holds the key exchange group of the + * original handshake. */ + SSLNamedGroup originalKeaGroup; + /* This field is PR_TRUE when the session is resumed and PR_FALSE + * otherwise. */ + PRBool resumed; + /* When adding new fields to this structure, please document the * NSS version in which they were added. */ } SSLChannelInfo; @@ -395,16 +425,19 @@ typedef enum { ssl_padding_xtn = 21, ssl_extended_master_secret_xtn = 23, ssl_session_ticket_xtn = 35, - ssl_tls13_key_share_xtn = 40, + /* 40 was used in draft versions of TLS 1.3; it is now reserved. */ ssl_tls13_pre_shared_key_xtn = 41, ssl_tls13_early_data_xtn = 42, ssl_tls13_supported_versions_xtn = 43, ssl_tls13_cookie_xtn = 44, ssl_tls13_psk_key_exchange_modes_xtn = 45, - ssl_tls13_ticket_early_data_info_xtn = 46, - ssl_next_proto_nego_xtn = 13172, + ssl_tls13_ticket_early_data_info_xtn = 46, /* Deprecated. */ + ssl_tls13_certificate_authorities_xtn = 47, + ssl_signature_algorithms_cert_xtn = 50, + ssl_tls13_key_share_xtn = 51, + ssl_next_proto_nego_xtn = 13172, /* Deprecated. */ ssl_renegotiation_info_xtn = 0xff01, - ssl_tls13_short_header_xtn = 0xff03 + ssl_tls13_short_header_xtn = 0xff03 /* Deprecated. */ } SSLExtensionType; /* This is the old name for the supported_groups extensions. */ diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c index 560493848..1fecaf3f8 100644 --- a/security/nss/lib/ssl/tls13con.c +++ b/security/nss/lib/ssl/tls13con.c @@ -17,23 +17,14 @@ #include "sslimpl.h" #include "sslproto.h" #include "sslerr.h" +#include "ssl3exthandle.h" #include "tls13hkdf.h" #include "tls13con.h" +#include "tls13err.h" #include "tls13exthandle.h" +#include "tls13hashstate.h" -typedef enum { - TrafficKeyClearText = 0, - TrafficKeyEarlyApplicationData = 1, - TrafficKeyHandshake = 2, - TrafficKeyApplicationData = 3 -} TrafficKeyType; - -typedef enum { - CipherSpecRead, - CipherSpecWrite, -} CipherSpecDirection; - -static SECStatus tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, +static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, CipherSpecDirection install, PRBool deleteSecret); static SECStatus tls13_AESGCM( @@ -53,8 +44,9 @@ static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss); static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group); static SECStatus tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare); -static SECStatus tls13_SendHelloRetryRequest(sslSocket *ss, - const sslNamedGroupDef *selectedGroup); +static SECStatus tls13_SendHelloRetryRequest( + sslSocket *ss, const sslNamedGroupDef *selectedGroup, + const PRUint8 *token, unsigned int tokenLen); static SECStatus tls13_HandleServerKeyShare(sslSocket *ss); static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, @@ -62,40 +54,46 @@ static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, static SECStatus tls13_SendCertificate(sslSocket *ss); static SECStatus tls13_HandleCertificate( sslSocket *ss, PRUint8 *b, PRUint32 length); +static SECStatus tls13_ReinjectHandshakeTranscript(sslSocket *ss); static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length); static SECStatus tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey); static SECStatus tls13_HandleCertificateVerify( - sslSocket *ss, PRUint8 *b, PRUint32 length, - SSL3Hashes *hashes); + sslSocket *ss, PRUint8 *b, PRUint32 length); static SECStatus tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid); static SECStatus +tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key, + const char *prefix, + const char *suffix, + const char *keylogLabel, + PK11SymKey **dest); +static SECStatus tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, - const char *prefix, - const char *suffix, + const char *label, + unsigned int labelLen, const SSL3Hashes *hashes, PK11SymKey **dest); static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss); +static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, + PRUint32 length); static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey); -static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, - unsigned long prefixLength, +static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefix, SSL3Hashes *hashes); -static SECStatus tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, +static SECStatus tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message, PK11SymKey *secret, PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes); static SECStatus tls13_ClientHandleFinished(sslSocket *ss, - PRUint8 *b, PRUint32 length, - const SSL3Hashes *hashes); + PRUint8 *b, PRUint32 length); static SECStatus tls13_ServerHandleFinished(sslSocket *ss, - PRUint8 *b, PRUint32 length, - const SSL3Hashes *hashes); + PRUint8 *b, PRUint32 length); +static SECStatus tls13_SendNewSessionTicket(sslSocket *ss, + const PRUint8 *appToken, + unsigned int appTokenLen); static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length); -static SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss, - SSL3Hashes *hashes); static SECStatus tls13_ComputeEarlySecrets(sslSocket *ss); static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss); static SECStatus tls13_ComputeApplicationSecrets(sslSocket *ss); @@ -107,26 +105,28 @@ static SECStatus tls13_ComputeFinished( static SECStatus tls13_SendClientSecondRound(sslSocket *ss); static SECStatus tls13_FinishHandshake(sslSocket *ss); -const char kHkdfLabelClient[] = "client"; -const char kHkdfLabelServer[] = "server"; -const char kHkdfLabelPskBinderKey[] = "resumption psk binder key"; -const char kHkdfLabelEarlyTrafficSecret[] = "early traffic secret"; -const char kHkdfLabelEarlyExporterSecret[] = "early exporter master secret"; -const char kHkdfLabelHandshakeTrafficSecret[] = "handshake traffic secret"; -const char kHkdfLabelApplicationTrafficSecret[] = "application traffic secret"; +const char kHkdfLabelClient[] = "c"; +const char kHkdfLabelServer[] = "s"; +const char kHkdfLabelDerivedSecret[] = "derived"; +const char kHkdfLabelPskBinderKey[] = "res binder"; +const char kHkdfLabelEarlyTrafficSecret[] = "e traffic"; +const char kHkdfLabelEarlyExporterSecret[] = "e exp master"; +const char kHkdfLabelHandshakeTrafficSecret[] = "hs traffic"; +const char kHkdfLabelApplicationTrafficSecret[] = "ap traffic"; const char kHkdfLabelFinishedSecret[] = "finished"; -const char kHkdfLabelResumptionMasterSecret[] = "resumption master secret"; -const char kHkdfLabelExporterMasterSecret[] = "exporter master secret"; +const char kHkdfLabelResumptionMasterSecret[] = "res master"; +const char kHkdfLabelExporterMasterSecret[] = "exp master"; +const char kHkdfLabelResumption[] = "resumption"; const char kHkdfPurposeKey[] = "key"; const char kHkdfPurposeIv[] = "iv"; -#define TRAFFIC_SECRET(ss, dir, name) ((ss->sec.isServer ^ \ - (dir == CipherSpecWrite)) \ - ? ss->ssl3.hs.client##name \ - : ss->ssl3.hs.server##name) - -const SSL3ProtocolVersion kTlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_0; -const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_1; +const char keylogLabelClientEarlyTrafficSecret[] = "CLIENT_EARLY_TRAFFIC_SECRET"; +const char keylogLabelClientHsTrafficSecret[] = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; +const char keylogLabelServerHsTrafficSecret[] = "SERVER_HANDSHAKE_TRAFFIC_SECRET"; +const char keylogLabelClientTrafficSecret[] = "CLIENT_TRAFFIC_SECRET_0"; +const char keylogLabelServerTrafficSecret[] = "SERVER_TRAFFIC_SECRET_0"; +const char keylogLabelEarlyExporterSecret[] = "EARLY_EXPORTER_SECRET"; +const char keylogLabelExporterSecret[] = "EXPORTER_SECRET"; /* Belt and suspenders in case we ever add a TLS 1.4. */ PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <= @@ -165,6 +165,7 @@ tls13_HandshakeState(SSL3WaitState st) switch (st) { STATE_CASE(idle_handshake); STATE_CASE(wait_client_hello); + STATE_CASE(wait_end_of_early_data); STATE_CASE(wait_client_cert); STATE_CASE(wait_client_key); STATE_CASE(wait_cert_verify); @@ -336,6 +337,23 @@ tls13_GetHmacMechanism(sslSocket *ss) } SECStatus +tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes, + const PRUint8 *buf, unsigned int len) +{ + SECStatus rv; + + rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)), + hashes->u.raw, buf, len); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + return SECFailure; + } + hashes->len = tls13_GetHashSize(ss); + + return SECSuccess; +} + +SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef) { SECStatus rv; @@ -450,7 +468,8 @@ tls13_SetupClientHello(sslSocket *ss) return SECFailure; } - rv = ssl3_SetCipherSuite(ss, ss->sec.ci.sid->u.ssl3.cipherSuite, PR_FALSE); + ss->ssl3.hs.cipher_suite = ss->sec.ci.sid->u.ssl3.cipherSuite; + rv = ssl3_SetupCipherSuite(ss, PR_FALSE); if (rv != SECSuccess) { FATAL_ERROR(ss, PORT_GetError(), internal_error); return SECFailure; @@ -558,9 +577,241 @@ loser: return SECFailure; } +static PRBool +tls13_UseServerSecret(sslSocket *ss, CipherSpecDirection direction) +{ + return ss->sec.isServer == (direction == CipherSpecWrite); +} + +static PK11SymKey ** +tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction) +{ + if (tls13_UseServerSecret(ss, direction)) { + return &ss->ssl3.hs.serverTrafficSecret; + } + return &ss->ssl3.hs.clientTrafficSecret; +} + +SECStatus +tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction) +{ + PK11SymKey **secret; + PK11SymKey *updatedSecret; + PRUint16 epoch; + SECStatus rv; + + secret = tls13_TrafficSecretRef(ss, direction); + rv = tls13_HkdfExpandLabel(*secret, tls13_GetHash(ss), + NULL, 0, + kHkdfLabelApplicationTrafficSecret, + strlen(kHkdfLabelApplicationTrafficSecret), + tls13_GetHmacMechanism(ss), + tls13_GetHashSize(ss), + &updatedSecret); + if (rv != SECSuccess) { + return SECFailure; + } + + PK11_FreeSymKey(*secret); + *secret = updatedSecret; + + ssl_GetSpecReadLock(ss); + if (direction == CipherSpecRead) { + epoch = ss->ssl3.crSpec->epoch; + } else { + epoch = ss->ssl3.cwSpec->epoch; + } + ssl_ReleaseSpecReadLock(ss); + + if (epoch == PR_UINT16_MAX) { + /* Good chance that this is an overflow from too many updates. */ + FATAL_ERROR(ss, SSL_ERROR_TOO_MANY_KEY_UPDATES, internal_error); + return SECFailure; + } + ++epoch; + + rv = tls13_SetCipherSpec(ss, epoch, direction, PR_FALSE); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + return SECFailure; + } + + return SECSuccess; +} + +SECStatus +tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer) +{ + SECStatus rv; + + SSL_TRC(3, ("%d: TLS13[%d]: %s send key update, response %s", + SSL_GETPID(), ss->fd, SSL_ROLE(ss), + (request == update_requested) ? "requested" + : "not requested")); + + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + if (!ss->firstHsDone) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_LIBRARY_FAILURE, + idle_handshake); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Not supported. */ + if (IS_DTLS(ss)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + ssl_GetXmitBufLock(ss); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_key_update, 1); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + goto loser; + } + rv = ssl3_AppendHandshakeNumber(ss, request, 1); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + goto loser; + } + + /* If we have been asked to buffer, then do so. This allows us to coalesce + * a KeyUpdate with a pending write. */ + rv = ssl3_FlushHandshake(ss, buffer ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0); + if (rv != SECSuccess) { + goto loser; /* error code set by ssl3_FlushHandshake */ + } + ssl_ReleaseXmitBufLock(ss); + + rv = tls13_UpdateTrafficKeys(ss, CipherSpecWrite); + if (rv != SECSuccess) { + goto loser; /* error code set by tls13_UpdateTrafficKeys */ + } + + return SECSuccess; + +loser: + ssl_ReleaseXmitBufLock(ss); + return SECFailure; +} + +SECStatus +SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate) +{ + SECStatus rv; + sslSocket *ss = ssl_FindSocket(fd); + if (!ss) { + return SECFailure; + } + + if (!ss->firstHsDone) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS, + idle_handshake); + if (rv != SECSuccess) { + return SECFailure; + } + + ssl_GetSSL3HandshakeLock(ss); + rv = tls13_SendKeyUpdate(ss, requestUpdate ? update_requested : update_not_requested, + PR_FALSE /* don't buffer */); + + /* Remember that we are the ones that initiated this KeyUpdate. */ + if (rv == SECSuccess) { + ss->ssl3.peerRequestedKeyUpdate = PR_FALSE; + } + ssl_ReleaseSSL3HandshakeLock(ss); + return rv; +} + +/* + * enum { + * update_not_requested(0), update_requested(1), (255) + * } KeyUpdateRequest; + * + * struct { + * KeyUpdateRequest request_update; + * } KeyUpdate; + */ +static SECStatus +tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length) +{ + SECStatus rv; + PRUint32 update; + + SSL_TRC(3, ("%d: TLS13[%d]: %s handle key update", + SSL_GETPID(), ss->fd, SSL_ROLE(ss))); + + PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + PORT_Assert(ss->firstHsDone); + if (!ss->firstHsDone) { + FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, unexpected_message); + return SECFailure; + } + + rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, + idle_handshake); + if (rv != SECSuccess) { + /* We should never be idle_handshake prior to firstHsDone. */ + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + return SECFailure; + } + + rv = ssl3_ConsumeHandshakeNumber(ss, &update, 1, &b, &length); + if (rv != SECSuccess) { + return SECFailure; /* Error code set already. */ + } + if (length != 0) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_UPDATE, decode_error); + return SECFailure; + } + if (!(update == update_requested || + update == update_not_requested)) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_UPDATE, decode_error); + return SECFailure; + } + + rv = tls13_UpdateTrafficKeys(ss, CipherSpecRead); + if (rv != SECSuccess) { + return SECFailure; /* Error code set by tls13_UpdateTrafficKeys. */ + } + + if (update == update_requested) { + PRBool sendUpdate; + if (ss->ssl3.peerRequestedKeyUpdate) { + /* 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; + ssl_ReleaseSpecReadLock(ss); + } else { + sendUpdate = PR_TRUE; + } + if (sendUpdate) { + /* Respond immediately (don't buffer). */ + rv = tls13_SendKeyUpdate(ss, update_not_requested, PR_FALSE); + if (rv != SECSuccess) { + return SECFailure; /* Error already set. */ + } + } + ss->ssl3.peerRequestedKeyUpdate = PR_TRUE; + } + + return SECSuccess; +} + SECStatus -tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, - PRUint32 length, SSL3Hashes *hashesPtr) +tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length) { if (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) { SSL_TRC(3, ("%d: TLS13[%d]: %s successfully decrypted handshake after" @@ -571,36 +822,34 @@ tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, /* TODO(ekr@rtfm.com): Would it be better to check all the states here? */ switch (ss->ssl3.hs.msg_type) { - case certificate: + case ssl_hs_certificate: return tls13_HandleCertificate(ss, b, length); - case certificate_request: + case ssl_hs_certificate_request: return tls13_HandleCertificateRequest(ss, b, length); - case certificate_verify: - if (!hashesPtr) { - FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY, unexpected_message); - return SECFailure; - } - return tls13_HandleCertificateVerify(ss, b, length, hashesPtr); + case ssl_hs_certificate_verify: + return tls13_HandleCertificateVerify(ss, b, length); - case encrypted_extensions: + case ssl_hs_encrypted_extensions: return tls13_HandleEncryptedExtensions(ss, b, length); - case new_session_ticket: + case ssl_hs_new_session_ticket: return tls13_HandleNewSessionTicket(ss, b, length); - case finished: - if (!hashesPtr) { - FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, unexpected_message); - return SECFailure; - } + case ssl_hs_finished: if (ss->sec.isServer) { - return tls13_ServerHandleFinished(ss, b, length, hashesPtr); + return tls13_ServerHandleFinished(ss, b, length); } else { - return tls13_ClientHandleFinished(ss, b, length, hashesPtr); + return tls13_ClientHandleFinished(ss, b, length); } + case ssl_hs_end_of_early_data: + return tls13_HandleEndOfEarlyData(ss, b, length); + + case ssl_hs_key_update: + return tls13_HandleKeyUpdate(ss, b, length); + default: FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message); return SECFailure; @@ -619,10 +868,6 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid) SSL_TRC(3, ("%d: TLS13[%d]: recovering static secret (%s)", SSL_GETPID(), ss->fd, SSL_ROLE(ss))); - if (!sid->u.ssl3.keys.msIsWrapped) { - PORT_Assert(0); /* I think this can't happen. */ - return SECFailure; - } /* Now find the hash used as the PRF for the previous handshake. */ hashType = tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite); @@ -673,53 +918,55 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid) /* Key Derivation Functions. * - * Below is the key schedule from [draft-ietf-tls-tls13]. - * - * * The relevant functions from this file are indicated by tls13_Foo(). * 0 * | * v - * PSK -> HKDF-Extract + * PSK -> HKDF-Extract = Early Secret * | - * v - * Early Secret ---> Derive-Secret(., "client early traffic secret", - * | ClientHello) - * | = client_early_traffic_secret - * v - * (EC)DHE -> HKDF-Extract + * +-----> Derive-Secret(., "ext binder" | "res binder", "") + * | = binder_key + * | + * +-----> Derive-Secret(., "c e traffic", + * | ClientHello) + * | = client_early_traffic_secret * | + * +-----> Derive-Secret(., "e exp master", + * | ClientHello) + * | = early_exporter_secret * v - * Handshake Secret + * Derive-Secret(., "derived", "") * | - * +---------> Derive-Secret(., "client handshake traffic secret", - * | ClientHello...ServerHello) - * | = client_handshake_traffic_secret + * v + *(EC)DHE -> HKDF-Extract = Handshake Secret * | - * +---------> Derive-Secret(., "server handshake traffic secret", - * | ClientHello...ServerHello) - * | = server_handshake_traffic_secret + * +-----> Derive-Secret(., "c hs traffic", + * | ClientHello...ServerHello) + * | = client_handshake_traffic_secret * | + * +-----> Derive-Secret(., "s hs traffic", + * | ClientHello...ServerHello) + * | = server_handshake_traffic_secret * v - * 0 -> HKDF-Extract + * Derive-Secret(., "derived", "") * | * v - * Master Secret + * 0 -> HKDF-Extract = Master Secret * | - * +---------> Derive-Secret(., "client application traffic secret", - * | ClientHello...Server Finished) - * | = client_traffic_secret_0 + * +-----> Derive-Secret(., "c ap traffic", + * | ClientHello...Server Finished) + * | = client_traffic_secret_0 * | - * +---------> Derive-Secret(., "server application traffic secret", - * | ClientHello...Server Finished) - * | = server_traffic_secret_0 + * +-----> Derive-Secret(., "s ap traffic", + * | ClientHello...Server Finished) + * | = server_traffic_secret_0 * | - * +---------> Derive-Secret(., "exporter master secret", - * | ClientHello...Client Finished) - * | = exporter_secret + * +-----> Derive-Secret(., "exp master", + * | ClientHello...Server Finished) + * | = exporter_secret * | - * +---------> Derive-Secret(., "resumption master secret", - * ClientHello...Client Finished) - * = resumption_secret + * +-----> Derive-Secret(., "res master", + * ClientHello...Client Finished) + * = resumption_master_secret * */ @@ -742,35 +989,43 @@ tls13_ComputeEarlySecrets(sslSocket *ss) PORT_Assert(ss->statelessResume == (ss->ssl3.hs.resumptionMasterSecret != NULL)); if (ss->statelessResume) { - PRUint8 buf[1] = { 0 }; - SSL3Hashes hashes; - PK11_FreeSymKey(ss->ssl3.hs.resumptionMasterSecret); ss->ssl3.hs.resumptionMasterSecret = NULL; - rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)), - hashes.u.raw, buf, 0); + rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelPskBinderKey, + strlen(kHkdfLabelPskBinderKey), + &ss->ssl3.hs.pskBinderKey); if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return SECFailure; } - hashes.len = tls13_GetHashSize(ss); + } + PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret); - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - NULL, kHkdfLabelPskBinderKey, &hashes, - &ss->ssl3.hs.pskBinderKey); - if (rv != SECSuccess) { - return SECFailure; - } + return SECSuccess; +} + +/* This derives the early traffic and early exporter secrets. */ +static SECStatus +tls13_DeriveEarlySecrets(sslSocket *ss) +{ + SECStatus rv; + + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelClient, + kHkdfLabelEarlyTrafficSecret, + keylogLabelClientEarlyTrafficSecret, + &ss->ssl3.hs.clientEarlyTrafficSecret); + if (rv != SECSuccess) { + return SECFailure; + } - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, NULL, kHkdfLabelEarlyExporterSecret, - &hashes, &ss->ssl3.hs.earlyExporterSecret); - if (rv != SECSuccess) { - return SECFailure; - } - } else { - PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret); + keylogLabelEarlyExporterSecret, + &ss->ssl3.hs.earlyExporterSecret); + if (rv != SECSuccess) { + return SECFailure; } return SECSuccess; @@ -780,6 +1035,7 @@ static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss) { SECStatus rv; + PK11SymKey *derivedSecret = NULL; PK11SymKey *newSecret = NULL; SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)", @@ -788,8 +1044,21 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss) /* First update |currentSecret| to add |dheSecret|, if any. */ PORT_Assert(ss->ssl3.hs.currentSecret); PORT_Assert(ss->ssl3.hs.dheSecret); - rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret, ss->ssl3.hs.dheSecret, + + /* Expand before we extract. */ + rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelDerivedSecret, + strlen(kHkdfLabelDerivedSecret), + &derivedSecret); + if (rv != SECSuccess) { + LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); + return rv; + } + + rv = tls13_HkdfExtract(derivedSecret, ss->ssl3.hs.dheSecret, tls13_GetHash(ss), &newSecret); + PK11_FreeSymKey(derivedSecret); + if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return rv; @@ -800,18 +1069,20 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss) ss->ssl3.hs.currentSecret = newSecret; /* Now compute |*HsTrafficSecret| */ - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelClient, - kHkdfLabelHandshakeTrafficSecret, NULL, - &ss->ssl3.hs.clientHsTrafficSecret); + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelClient, + kHkdfLabelHandshakeTrafficSecret, + keylogLabelClientHsTrafficSecret, + &ss->ssl3.hs.clientHsTrafficSecret); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return rv; } - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelServer, - kHkdfLabelHandshakeTrafficSecret, NULL, - &ss->ssl3.hs.serverHsTrafficSecret); + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelServer, + kHkdfLabelHandshakeTrafficSecret, + keylogLabelServerHsTrafficSecret, + &ss->ssl3.hs.serverHsTrafficSecret); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return rv; @@ -822,11 +1093,19 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss) /* Crank HKDF forward to make master secret, which we * stuff in current secret. */ - rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret, + rv = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelDerivedSecret, + strlen(kHkdfLabelDerivedSecret), + &derivedSecret); + if (rv != SECSuccess) { + LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); + return rv; + } + rv = tls13_HkdfExtract(derivedSecret, NULL, tls13_GetHash(ss), &newSecret); - + PK11_FreeSymKey(derivedSecret); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; @@ -842,26 +1121,27 @@ tls13_ComputeApplicationSecrets(sslSocket *ss) { SECStatus rv; - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelClient, - kHkdfLabelApplicationTrafficSecret, - NULL, - &ss->ssl3.hs.clientTrafficSecret); + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelClient, + kHkdfLabelApplicationTrafficSecret, + keylogLabelClientTrafficSecret, + &ss->ssl3.hs.clientTrafficSecret); if (rv != SECSuccess) { return SECFailure; } - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelServer, - kHkdfLabelApplicationTrafficSecret, - NULL, - &ss->ssl3.hs.serverTrafficSecret); + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelServer, + kHkdfLabelApplicationTrafficSecret, + keylogLabelServerTrafficSecret, + &ss->ssl3.hs.serverTrafficSecret); if (rv != SECSuccess) { return SECFailure; } - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - NULL, kHkdfLabelExporterMasterSecret, - NULL, &ss->ssl3.hs.exporterSecret); + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + NULL, kHkdfLabelExporterMasterSecret, + keylogLabelExporterSecret, + &ss->ssl3.hs.exporterSecret); if (rv != SECSuccess) { return SECFailure; } @@ -873,30 +1153,20 @@ static SECStatus tls13_ComputeFinalSecrets(sslSocket *ss) { SECStatus rv; - PK11SymKey *resumptionMasterSecret = NULL; - PORT_Assert(!ss->ssl3.crSpec->master_secret); - PORT_Assert(!ss->ssl3.cwSpec->master_secret); + PORT_Assert(!ss->ssl3.crSpec->masterSecret); + PORT_Assert(!ss->ssl3.cwSpec->masterSecret); - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - NULL, kHkdfLabelResumptionMasterSecret, - NULL, &resumptionMasterSecret); + rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + NULL, kHkdfLabelResumptionMasterSecret, + NULL, + &ss->ssl3.hs.resumptionMasterSecret); PK11_FreeSymKey(ss->ssl3.hs.currentSecret); ss->ssl3.hs.currentSecret = NULL; if (rv != SECSuccess) { return SECFailure; } - /* This is pretty gross. TLS 1.3 uses a number of master secrets: - * The master secret to generate the keys and then the resumption - * master secret for future connections. To make this work without - * refactoring too much of the SSLv3 code, we store the RMS in - * |crSpec->master_secret| and |cwSpec->master_secret|. - */ - ss->ssl3.crSpec->master_secret = resumptionMasterSecret; - ss->ssl3.cwSpec->master_secret = - PK11_ReferenceSymKey(ss->ssl3.crSpec->master_secret); - return SECSuccess; } @@ -909,6 +1179,8 @@ tls13_RestoreCipherInfo(sslSocket *ss, sslSessionID *sid) */ ss->sec.authType = sid->authType; ss->sec.authKeyBits = sid->authKeyBits; + ss->sec.originalKeaGroup = ssl_LookupNamedGroup(sid->keaGroup); + ss->sec.signatureScheme = sid->sigScheme; } /* Check whether resumption-PSK is allowed. */ @@ -961,6 +1233,10 @@ tls13_CanNegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid) &sid->u.ssl3.alpnSelection) != 0) return PR_FALSE; + if (tls13_IsReplay(ss, sid)) { + return PR_FALSE; + } + return PR_TRUE; } @@ -1046,7 +1322,9 @@ tls13_FindKeyShareEntry(sslSocket *ss, const sslNamedGroupDef *group) } static SECStatus -tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare) +tls13_NegotiateKeyExchange(sslSocket *ss, + const sslNamedGroupDef **requestedGroup, + TLS13KeyShareEntry **clientShare) { unsigned int index; TLS13KeyShareEntry *entry = NULL; @@ -1126,13 +1404,16 @@ tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare) SSL_TRC(3, ("%d: TLS13[%d]: group = %d", SSL_GETPID(), ss->fd, preferredGroup->name)); - if (!entry) { - return tls13_SendHelloRetryRequest(ss, preferredGroup); + /* Either provide a share, or provide a group that should be requested in a + * HelloRetryRequest, but not both. */ + if (entry) { + PORT_Assert(preferredGroup == entry->group); + *clientShare = entry; + *requestedGroup = NULL; + } else { + *clientShare = NULL; + *requestedGroup = preferredGroup; } - - PORT_Assert(preferredGroup == entry->group); - *clientShare = entry; - return SECSuccess; } @@ -1190,8 +1471,8 @@ tls13_SelectServerCert(sslSocket *ss) rv = ssl_PickSignatureScheme(ss, cert->serverKeyPair->pubKey, cert->serverKeyPair->privKey, - ss->xtnData.clientSigSchemes, - ss->xtnData.numClientSigScheme, + ss->xtnData.sigSchemes, + ss->xtnData.numSigSchemes, PR_FALSE); if (rv == SECSuccess) { /* Found one. */ @@ -1208,6 +1489,62 @@ tls13_SelectServerCert(sslSocket *ss) return SECFailure; } +/* Note: |requestedGroup| is non-NULL when we send a key_share extension. */ +static SECStatus +tls13_MaybeSendHelloRetry(sslSocket *ss, const sslNamedGroupDef *requestedGroup, + PRBool *hrrSent) +{ + SSLHelloRetryRequestAction action = ssl_hello_retry_accept; + PRUint8 token[256] = { 0 }; + unsigned int tokenLen = 0; + SECStatus rv; + + if (ss->hrrCallback) { + action = ss->hrrCallback(!ss->ssl3.hs.helloRetry, + ss->xtnData.applicationToken.data, + ss->xtnData.applicationToken.len, + token, &tokenLen, sizeof(token), + ss->hrrCallbackArg); + } + + /* These use SSL3_SendAlert directly to avoid an assertion in + * tls13_FatalError(), which is ordinarily OK. */ + if (action == ssl_hello_retry_request && ss->ssl3.hs.helloRetry) { + (void)SSL3_SendAlert(ss, alert_fatal, internal_error); + PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR); + return SECFailure; + } + + if (action != ssl_hello_retry_request && tokenLen) { + (void)SSL3_SendAlert(ss, alert_fatal, internal_error); + PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR); + return SECFailure; + } + + if (tokenLen > sizeof(token)) { + (void)SSL3_SendAlert(ss, alert_fatal, internal_error); + PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR); + return SECFailure; + } + + if (action == ssl_hello_retry_fail) { + FATAL_ERROR(ss, SSL_ERROR_APPLICATION_ABORT, handshake_failure); + return SECFailure; + } + + if (!requestedGroup && action != ssl_hello_retry_request) { + return SECSuccess; + } + + rv = tls13_SendHelloRetryRequest(ss, requestedGroup, token, tokenLen); + if (rv != SECSuccess) { + return SECFailure; /* Code already set. */ + } + + *hrrSent = PR_TRUE; + return SECSuccess; +} + static SECStatus tls13_NegotiateAuthentication(sslSocket *ss) { @@ -1237,13 +1574,19 @@ tls13_NegotiateAuthentication(sslSocket *ss) SECStatus tls13_HandleClientHelloPart2(sslSocket *ss, const SECItem *suites, - sslSessionID *sid) + sslSessionID *sid, + const PRUint8 *msg, + unsigned int len) { SECStatus rv; SSL3Statistics *ssl3stats = SSL_GetStatistics(); + const sslNamedGroupDef *requestedGroup = NULL; TLS13KeyShareEntry *clientShare = NULL; - int j; - ssl3CipherSuite previousCipherSuite; + ssl3CipherSuite previousCipherSuite = 0; + const sslNamedGroupDef *previousGroup = NULL; + PRBool hrr = PR_FALSE; + + ss->ssl3.hs.endOfFlight = PR_TRUE; if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) { ss->ssl3.hs.zeroRttState = ssl_0rtt_sent; @@ -1251,24 +1594,59 @@ tls13_HandleClientHelloPart2(sslSocket *ss, #ifndef PARANOID /* Look for a matching cipher suite. */ - j = ssl3_config_match_init(ss); - if (j <= 0) { /* no ciphers are working/supported by PK11 */ + if (ssl3_config_match_init(ss) == 0) { /* no ciphers are working/supported by PK11 */ FATAL_ERROR(ss, PORT_GetError(), internal_error); goto loser; } #endif - previousCipherSuite = ss->ssl3.hs.cipher_suite; + /* Negotiate cipher suite. */ rv = ssl3_NegotiateCipherSuite(ss, suites, PR_FALSE); if (rv != SECSuccess) { FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure); goto loser; } + /* If we are going around again, then we should make sure that the cipher * suite selection doesn't change. That's a sign of client shennanigans. */ - if (ss->ssl3.hs.helloRetry && - ss->ssl3.hs.cipher_suite != previousCipherSuite) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, handshake_failure); + if (ss->ssl3.hs.helloRetry) { + + /* Update sequence numbers before checking the cookie so that any alerts + * we generate are sent with the right sequence numbers. */ + if (IS_DTLS(ss)) { + /* Count the first ClientHello and the HelloRetryRequest. */ + ss->ssl3.hs.sendMessageSeq = 1; + ss->ssl3.hs.recvMessageSeq = 1; + 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; + ssl_ReleaseSpecWriteLock(ss); + } + + if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_cookie_xtn) || + !ss->xtnData.cookie.len) { + FATAL_ERROR(ss, SSL_ERROR_MISSING_COOKIE_EXTENSION, + missing_extension); + goto loser; + } + PRINT_BUF(50, (ss, "Client sent cookie", + ss->xtnData.cookie.data, ss->xtnData.cookie.len)); + + rv = tls13_RecoverHashState(ss, ss->xtnData.cookie.data, + ss->xtnData.cookie.len, + &previousCipherSuite, + &previousGroup); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter); + goto loser; + } + } + + /* Now merge the ClientHello into the hash state. */ + rv = ssl_HashHandshakeMessage(ss, ssl_hs_client_hello, msg, len); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } @@ -1296,13 +1674,50 @@ tls13_HandleClientHelloPart2(sslSocket *ss, } /* Select key exchange. */ - rv = tls13_NegotiateKeyExchange(ss, &clientShare); + rv = tls13_NegotiateKeyExchange(ss, &requestedGroup, &clientShare); if (rv != SECSuccess) { goto loser; } + /* We should get either one of these, but not both. */ + PORT_Assert((requestedGroup && !clientShare) || + (!requestedGroup && clientShare)); - /* If we didn't find a client key share, we have to retry. */ - if (!clientShare) { + /* After HelloRetryRequest, check consistency of cipher and group. */ + if (ss->ssl3.hs.helloRetry) { + PORT_Assert(previousCipherSuite); + if (ss->ssl3.hs.cipher_suite != previousCipherSuite) { + FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, + illegal_parameter); + goto loser; + } + if (!clientShare) { + FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, + illegal_parameter); + goto loser; + } + + /* If we requested a new key share, check that the client provided just + * one of the right type. */ + if (previousGroup) { + if (PR_PREV_LINK(&ss->xtnData.remoteKeyShares) != + PR_NEXT_LINK(&ss->xtnData.remoteKeyShares)) { + FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, + illegal_parameter); + goto loser; + } + if (clientShare->group != previousGroup) { + FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, + illegal_parameter); + goto loser; + } + } + } + + rv = tls13_MaybeSendHelloRetry(ss, requestedGroup, &hrr); + if (rv != SECSuccess) { + goto loser; + } + if (hrr) { if (sid) { /* Free the sid. */ ss->sec.uncache(sid); ssl_FreeSID(sid); @@ -1373,14 +1788,17 @@ tls13_HandleClientHelloPart2(sslSocket *ss, if (ss->statelessResume) { SSL3Hashes hashes; - rv = tls13_ComputePskBinderHash(ss, ss->xtnData.pskBinderPrefixLen, - &hashes); + PORT_Assert(ss->ssl3.hs.messages.len > ss->xtnData.pskBindersLen); + rv = tls13_ComputePskBinderHash( + ss, + ss->ssl3.hs.messages.len - ss->xtnData.pskBindersLen, + &hashes); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } - rv = tls13_VerifyFinished(ss, client_hello, + rv = tls13_VerifyFinished(ss, ssl_hs_client_hello, ss->ssl3.hs.pskBinderKey, ss->xtnData.pskBinder.data, ss->xtnData.pskBinder.len, @@ -1429,11 +1847,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss, sid = NULL; if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelClient, - kHkdfLabelEarlyTrafficSecret, - NULL, /* Current running hash. */ - &ss->ssl3.hs.clientEarlyTrafficSecret); + rv = tls13_DeriveEarlySecrets(ss); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return SECFailure; @@ -1458,70 +1872,143 @@ loser: return SECFailure; } -static SECStatus -tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup) +SECStatus +SSLExp_HelloRetryRequestCallback(PRFileDesc *fd, + SSLHelloRetryRequestCallback cb, void *arg) { - SECStatus rv; - - SSL_TRC(3, ("%d: TLS13[%d]: send hello retry request handshake", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - - /* We asked already, but made no progress. */ - if (ss->ssl3.hs.helloRetry) { - FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter); - return SECFailure; + sslSocket *ss = ssl_FindSocket(fd); + if (!ss) { + return SECFailure; /* Code already set. */ } - ssl_GetXmitBufLock(ss); - rv = ssl3_AppendHandshakeHeader(ss, hello_retry_request, - 2 + /* version */ - 2 + /* extension length */ - 2 + /* group extension id */ - 2 + /* group extension length */ - 2 /* group */); + ss->hrrCallback = cb; + ss->hrrCallbackArg = arg; + return SECSuccess; +} + +/* + * struct { + * ProtocolVersion server_version; + * CipherSuite cipher_suite; + * Extension extensions<2..2^16-1>; + * } HelloRetryRequest; + * + * Note: this function takes an empty buffer and returns + * a non-empty one on success, in which case the caller must + * eventually clean up. + */ +SECStatus +tls13_ConstructHelloRetryRequest(sslSocket *ss, + ssl3CipherSuite cipherSuite, + const sslNamedGroupDef *selectedGroup, + PRUint8 *cookie, unsigned int cookieLen, + sslBuffer *buffer) +{ + SECStatus rv; + sslBuffer extensionsBuf = SSL_BUFFER_EMPTY; + PORT_Assert(buffer->len == 0); + + /* Note: cookie is pointing to a stack variable, so is only valid + * now. */ + ss->xtnData.selectedGroup = selectedGroup; + ss->xtnData.cookie.data = cookie; + ss->xtnData.cookie.len = cookieLen; + rv = ssl_ConstructExtensions(ss, &extensionsBuf, + ssl_hs_hello_retry_request); if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } + /* These extensions can't be empty. */ + PORT_Assert(SSL_BUFFER_LEN(&extensionsBuf) > 0); - rv = ssl3_AppendHandshakeNumber( - ss, tls13_EncodeDraftVersion(ss->version), 2); + /* Clean up cookie so we're not pointing at random memory. */ + ss->xtnData.cookie.data = NULL; + ss->xtnData.cookie.len = 0; + + rv = ssl_ConstructServerHello(ss, PR_TRUE, &extensionsBuf, buffer); if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } + sslBuffer_Clear(&extensionsBuf); + return SECSuccess; + +loser: + sslBuffer_Clear(&extensionsBuf); + sslBuffer_Clear(buffer); + return SECFailure; +} + +static SECStatus +tls13_SendHelloRetryRequest(sslSocket *ss, + const sslNamedGroupDef *requestedGroup, + const PRUint8 *appToken, unsigned int appTokenLen) +{ + SECStatus rv; + unsigned int cookieLen; + PRUint8 cookie[1024]; + sslBuffer messageBuf = SSL_BUFFER_EMPTY; - /* Length of extensions. */ - rv = ssl3_AppendHandshakeNumber(ss, 2 + 2 + 2, 2); + SSL_TRC(3, ("%d: TLS13[%d]: send hello retry request handshake", + SSL_GETPID(), ss->fd)); + + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + /* Compute the cookie we are going to need. */ + rv = tls13_MakeHrrCookie(ss, requestedGroup, + appToken, appTokenLen, + cookie, &cookieLen, sizeof(cookie)); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - goto loser; + return SECFailure; } - /* Key share extension - currently the only reason we send this. */ - rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); + /* Now build the body of the message. */ + rv = tls13_ConstructHelloRetryRequest(ss, ss->ssl3.hs.cipher_suite, + requestedGroup, + cookie, cookieLen, &messageBuf); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - goto loser; + return SECFailure; } - /* Key share extension length. */ - rv = ssl3_AppendHandshakeNumber(ss, 2, 2); + + /* And send it. */ + ssl_GetXmitBufLock(ss); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello, + SSL_BUFFER_LEN(&messageBuf)); if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } - rv = ssl3_AppendHandshakeNumber(ss, selectedGroup->name, 2); + rv = ssl3_AppendBufferToHandshake(ss, &messageBuf); if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } + sslBuffer_Clear(&messageBuf); /* Done with messageBuf */ - rv = ssl3_FlushHandshake(ss, 0); - if (rv != SECSuccess) { - goto loser; /* error code set by ssl3_FlushHandshake */ + if (ss->ssl3.hs.fakeSid.len) { + PRInt32 sent; + + PORT_Assert(!IS_DTLS(ss)); + rv = ssl3_SendChangeCipherSpecsInt(ss); + if (rv != SECSuccess) { + goto loser; + } + /* ssl3_SendChangeCipherSpecsInt() only flushes to the output buffer, so we + * have to force a send. */ + sent = ssl_SendSavedWriteData(ss); + if (sent < 0 && PORT_GetError() != PR_WOULD_BLOCK_ERROR) { + PORT_SetError(SSL_ERROR_SOCKET_WRITE_FAILURE); + goto loser; + } + } else { + rv = ssl3_FlushHandshake(ss, 0); + if (rv != SECSuccess) { + goto loser; /* error code set by ssl3_FlushHandshake */ + } } + + /* 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)); ssl_ReleaseXmitBufLock(ss); ss->ssl3.hs.helloRetry = PR_TRUE; @@ -1535,6 +2022,7 @@ tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup return SECSuccess; loser: + sslBuffer_Clear(&messageBuf); ssl_ReleaseXmitBufLock(ss); return SECFailure; } @@ -1606,67 +2094,96 @@ static SECStatus tls13_SendCertificateRequest(sslSocket *ss) { SECStatus rv; - unsigned int calen; - SECItem *names; - unsigned int nnames; - SECItem *name; - int i; - PRUint8 sigSchemes[MAX_SIGNATURE_SCHEMES * 2]; - unsigned int sigSchemesLength = 0; - int length; + sslBuffer extensionBuf = SSL_BUFFER_EMPTY; SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request", SSL_GETPID(), ss->fd)); - rv = ssl3_EncodeSigAlgs(ss, sigSchemes, sizeof(sigSchemes), - &sigSchemesLength); + rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request); if (rv != SECSuccess) { - return rv; + return SECFailure; /* Code already set. */ } + /* We should always have at least one of these. */ + PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0); - rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request, + 1 + 0 + /* empty request context */ + 2 + /* extension length */ + SSL_BUFFER_LEN(&extensionBuf)); if (rv != SECSuccess) { - return rv; + goto loser; /* err set by AppendHandshake. */ } - length = 1 + 0 /* length byte for empty request context */ + - 2 + sigSchemesLength + 2 + calen + 2; - rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } + /* Context. */ rv = ssl3_AppendHandshakeNumber(ss, 0, 1); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ + goto loser; /* err set by AppendHandshake. */ } - rv = ssl3_AppendHandshakeVariable(ss, sigSchemes, sigSchemesLength, 2); + /* Extensions. */ + rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ + goto loser; /* err set by AppendHandshake. */ } - rv = ssl3_AppendHandshakeNumber(ss, calen, 2); + + sslBuffer_Clear(&extensionBuf); + return SECSuccess; + +loser: + sslBuffer_Clear(&extensionBuf); + return SECFailure; +} + +/* [draft-ietf-tls-tls13; S 4.4.1] says: + * + * Transcript-Hash(ClientHello1, HelloRetryRequest, ... MN) = + * Hash(message_hash || // Handshake type + * 00 00 Hash.length || // Handshake message length + * Hash(ClientHello1) || // Hash of ClientHello1 + * HelloRetryRequest ... MN) + */ +static SECStatus +tls13_ReinjectHandshakeTranscript(sslSocket *ss) +{ + SSL3Hashes hashes; + SECStatus rv; + + // First compute the hash. + rv = tls13_ComputeHash(ss, &hashes, + ss->ssl3.hs.messages.buf, + ss->ssl3.hs.messages.len); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } - for (i = 0, name = names; i < nnames; i++, name++) { - rv = ssl3_AppendHandshakeVariable(ss, name->data, name->len, 2); - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } + return SECFailure; } - rv = ssl3_AppendHandshakeNumber(ss, 0, 2); + + // Now re-init the handshake. + ssl3_RestartHandshakeHashes(ss); + + // And reinject the message. + rv = ssl_HashHandshakeMessage(ss, ssl_hs_message_hash, + hashes.u.raw, hashes.len); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ + return SECFailure; } return SECSuccess; } +static unsigned int +ssl_ListCount(PRCList *list) +{ + unsigned int c = 0; + PRCList *cur; + for (cur = PR_NEXT_LINK(list); cur != list; cur = PR_NEXT_LINK(cur)) { + ++c; + } + return c; +} + SECStatus -tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) +tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg, + PRUint32 savedLength) { SECStatus rv; - PRUint32 tmp; - SSL3ProtocolVersion version; SSL_TRC(3, ("%d: TLS13[%d]: handle hello retry request", SSL_GETPID(), ss->fd)); @@ -1679,84 +2196,77 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) unexpected_message); return SECFailure; } - - /* Client only. */ - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST, - wait_server_hello); - if (rv != SECSuccess) { - return SECFailure; - } - - /* Fool me once, shame on you; fool me twice... */ - if (ss->ssl3.hs.helloRetry) { - FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_HELLO_RETRY_REQUEST, - unexpected_message); - return SECFailure; - } + PORT_Assert(ss->ssl3.hs.ws == wait_server_hello); if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) { ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored; /* Restore the null cipher spec for writing. */ ssl_GetSpecWriteLock(ss); - tls13_CipherSpecRelease(ss->ssl3.cwSpec); - ss->ssl3.cwSpec = ss->ssl3.crSpec; - PORT_Assert(ss->ssl3.cwSpec->cipher_def->cipher == cipher_null); + ssl_CipherSpecRelease(ss->ssl3.cwSpec); + ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecWrite, + TrafficKeyClearText); + PORT_Assert(ss->ssl3.cwSpec); ssl_ReleaseSpecWriteLock(ss); } else { PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none); } - /* Version. */ - rv = ssl_ClientReadVersion(ss, &b, &length, &version); - if (rv != SECSuccess) { - return SECFailure; /* alert already sent */ - } - if (version > ss->vrange.max || version < SSL_LIBRARY_VERSION_TLS_1_3) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST, - protocol_version); - return SECFailure; - } - - /* Extensions. */ - rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, &b, &length); - if (rv != SECSuccess) { - return SECFailure; /* error code already set */ - } - /* Extensions must be non-empty and use the remainder of the message. - * This means that a HelloRetryRequest cannot be a no-op: we must have an - * extension, it must be one that we understand and recognize as being valid - * for HelloRetryRequest, and all the extensions we permit cause us to - * modify our ClientHello in some way. */ - if (!tmp || tmp != length) { + /* 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 + * extensions, supported_versions plus one other. That other must be one + * that we understand and recognize as being valid for HelloRetryRequest, + * and all the extensions we permit cause us to modify our second + * ClientHello in some meaningful way. */ + if (ssl_ListCount(&ss->ssl3.hs.remoteExtensions) <= 1) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST, decode_error); return SECFailure; } - rv = ssl3_HandleExtensions(ss, &b, &length, hello_retry_request); + rv = ssl3_HandleParsedExtensions(ss, ssl_hs_hello_retry_request); + ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); if (rv != SECSuccess) { return SECFailure; /* Error code set below */ } ss->ssl3.hs.helloRetry = PR_TRUE; + rv = tls13_ReinjectHandshakeTranscript(ss); + if (rv != SECSuccess) { + return rv; + } + + rv = ssl_HashHandshakeMessage(ss, ssl_hs_server_hello, + savedMsg, savedLength); + if (rv != SECSuccess) { + return SECFailure; + } ssl_GetXmitBufLock(ss); + if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss) && + ss->ssl3.hs.zeroRttState == ssl_0rtt_none) { + rv = ssl3_SendChangeCipherSpecsInt(ss); + if (rv != SECSuccess) { + goto loser; + } + } rv = ssl3_SendClientHello(ss, client_hello_retry); - ssl_ReleaseXmitBufLock(ss); if (rv != SECSuccess) { - return SECFailure; + goto loser; } + ssl_ReleaseXmitBufLock(ss); return SECSuccess; + +loser: + ssl_ReleaseXmitBufLock(ss); + return SECFailure; } static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; - TLS13CertificateRequest *certRequest = NULL; SECItem context = { siBuffer, NULL, 0 }; - PLArenaPool *arena; SECItem extensionsData = { siBuffer, NULL, 0 }; SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence", @@ -1775,71 +2285,51 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) PORT_Assert(ss->ssl3.clientCertChain == NULL); PORT_Assert(ss->ssl3.clientCertificate == NULL); PORT_Assert(ss->ssl3.clientPrivateKey == NULL); - PORT_Assert(ss->ssl3.hs.certificateRequest == NULL); + PORT_Assert(!ss->ssl3.hs.clientCertRequested); - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (!arena) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length); + if (rv != SECSuccess) { return SECFailure; } - rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length); - if (rv != SECSuccess) - goto loser; - /* We don't support post-handshake client auth, the certificate request - * context must always be null. */ + * context must always be empty. */ if (context.len > 0) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter); - goto loser; - } - - certRequest = PORT_ArenaZNew(arena, TLS13CertificateRequest); - if (!certRequest) - goto loser; - certRequest->arena = arena; - certRequest->ca_list.arena = arena; - - rv = ssl_ParseSignatureSchemes(ss, arena, - &certRequest->signatureSchemes, - &certRequest->signatureSchemeCount, - &b, &length); - if (rv != SECSuccess || certRequest->signatureSchemeCount == 0) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, - decode_error); - goto loser; + return SECFailure; } - rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, - &certRequest->ca_list); - if (rv != SECSuccess) - goto loser; /* alert already sent */ - - /* Verify that the extensions are sane. */ rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length); if (rv != SECSuccess) { - goto loser; + return SECFailure; + } + + if (length) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, decode_error); + return SECFailure; } - /* Process all the extensions (note: currently a no-op). */ + /* Process all the extensions. */ rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len, - certificate_request); + ssl_hs_certificate_request); if (rv != SECSuccess) { - goto loser; + return SECFailure; } - rv = SECITEM_CopyItem(arena, &certRequest->context, &context); - if (rv != SECSuccess) - goto loser; + if (!ss->xtnData.numSigSchemes) { + FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION, + missing_extension); + return SECFailure; + } - TLS13_SET_HS_STATE(ss, wait_server_cert); - ss->ssl3.hs.certificateRequest = certRequest; + rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &context); + if (rv != SECSuccess) { + return SECFailure; + } + ss->ssl3.hs.clientCertRequested = PR_TRUE; + TLS13_SET_HS_STATE(ss, wait_server_cert); return SECSuccess; - -loser: - PORT_FreeArena(arena, PR_FALSE); - return SECFailure; } static SECStatus @@ -1859,12 +2349,10 @@ tls13_SendEncryptedServerSequence(sslSocket *ss) return SECFailure; } - ss->ssl3.hs.shortHeaders = ssl3_ExtensionNegotiated( - ss, ssl_tls13_short_header_xtn); - if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { - rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_early_data_xtn, - tls13_ServerSendEarlyDataXtn); + rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, + ssl_tls13_early_data_xtn, + ssl_SendEmptyExtension); if (rv != SECSuccess) { return SECFailure; /* Error code set already. */ } @@ -1917,11 +2405,29 @@ tls13_SendServerHelloSequence(sslSocket *ss) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, + ssl_tls13_supported_versions_xtn, + tls13_ServerSendSupportedVersionsXtn); + if (rv != SECSuccess) { + return SECFailure; + } + rv = ssl3_SendServerHello(ss); if (rv != SECSuccess) { return rv; /* err code is set. */ } + if (ss->ssl3.hs.fakeSid.len) { + PORT_Assert(!IS_DTLS(ss)); + SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE); + if (!ss->ssl3.hs.helloRetry) { + rv = ssl3_SendChangeCipherSpecsInt(ss); + if (rv != SECSuccess) { + return rv; + } + } + } + rv = tls13_SendEncryptedServerSequence(ss); if (rv != SECSuccess) { err = PORT_GetError(); @@ -1953,14 +2459,18 @@ tls13_SendServerHelloSequence(sslSocket *ss) return SECFailure; } + if (IS_DTLS(ss)) { + /* We need this for reading ACKs. */ + ssl_CipherSpecAddRef(ss->ssl3.crSpec); + } if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { - rv = tls13_SetCipherSpec(ss, - TrafficKeyEarlyApplicationData, + rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData, CipherSpecRead, PR_TRUE); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } + TLS13_SET_HS_STATE(ss, wait_end_of_early_data); } else { PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none || ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored); @@ -1972,11 +2482,12 @@ tls13_SendServerHelloSequence(sslSocket *ss) LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } + TLS13_SET_HS_STATE(ss, + ss->opt.requestCertificate ? wait_client_cert + : wait_finished); } - TLS13_SET_HS_STATE(ss, - ss->opt.requestCertificate ? wait_client_cert - : wait_finished); + ss->ssl3.hs.serverHelloTime = ssl_TimeUsec(); return SECSuccess; } @@ -2023,7 +2534,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss) SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes); } else { /* !PSK */ - if (ssl3_ClientExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) { + if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) { SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_misses); } if (sid->cached == in_client_cache) { @@ -2068,8 +2579,12 @@ tls13_HandleServerHelloPart2(sslSocket *ss) return SECFailure; /* error code is set. */ } - ss->ssl3.hs.shortHeaders = ssl3_ExtensionNegotiated( - ss, ssl_tls13_short_header_xtn); + if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) { + /* When we send 0-RTT, we saved the null spec in case we needed it to + * send another ClientHello in response to a HelloRetryRequest. Now + * that we won't be receiving a HelloRetryRequest, release the spec. */ + ssl_CipherSpecReleaseByEpoch(ss, CipherSpecWrite, TrafficKeyClearText); + } rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, CipherSpecRead, PR_FALSE); @@ -2171,8 +2686,7 @@ tls13_SendCertificate(sslSocket *ss) int certChainLen = 0; int i; SECItem context = { siBuffer, NULL, 0 }; - PRInt32 extensionsLen = 0; - PRUint32 maxBytes = 65535; + sslBuffer extensionBuf = SSL_BUFFER_EMPTY; SSL_TRC(3, ("%d: TLS1.3[%d]: send certificate handshake", SSL_GETPID(), ss->fd)); @@ -2195,26 +2709,28 @@ tls13_SendCertificate(sslSocket *ss) ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate); } - /* Get the extensions length. This only applies to the leaf cert, - * because we don't yet send extensions for non-leaf certs. */ - extensionsLen = ssl3_CallHelloExtensionSenders( - ss, PR_FALSE, maxBytes, &ss->xtnData.certificateSenders[0]); - if (!ss->sec.isServer) { - PORT_Assert(ss->ssl3.hs.certificateRequest); - context = ss->ssl3.hs.certificateRequest->context; + PORT_Assert(ss->ssl3.hs.clientCertRequested); + context = ss->xtnData.certReqContext; } if (certChain) { for (i = 0; i < certChain->len; i++) { - certChainLen += - 3 + certChain->certs[i].len + /* cert length + cert */ - 2 + (!i ? extensionsLen : 0); /* extensions length + extensions */ + /* Each cert is 3 octet length, cert, and extensions */ + certChainLen += 3 + certChain->certs[i].len + 2; + } + + /* Build the extensions. This only applies to the leaf cert, because we + * don't yet send extensions for non-leaf certs. */ + rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate); + if (rv != SECSuccess) { + return SECFailure; /* code already set */ } + /* extensionBuf.len is only added once, for the leaf cert. */ + certChainLen += SSL_BUFFER_LEN(&extensionBuf); } - rv = ssl3_AppendHandshakeHeader(ss, certificate, - 1 + context.len + - 3 + certChainLen); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate, + 1 + context.len + 3 + certChainLen); if (rv != SECSuccess) { return SECFailure; /* err set by AppendHandshake. */ } @@ -2222,50 +2738,44 @@ tls13_SendCertificate(sslSocket *ss) rv = ssl3_AppendHandshakeVariable(ss, context.data, context.len, 1); if (rv != SECSuccess) { - return SECFailure; /* err set by AppendHandshake. */ + goto loser; /* err set by AppendHandshake. */ } rv = ssl3_AppendHandshakeNumber(ss, certChainLen, 3); if (rv != SECSuccess) { - return SECFailure; /* err set by AppendHandshake. */ + goto loser; /* err set by AppendHandshake. */ } if (certChain) { for (i = 0; i < certChain->len; i++) { - PRInt32 sentLen; - rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data, certChain->certs[i].len, 3); if (rv != SECSuccess) { - return SECFailure; /* err set by AppendHandshake. */ + goto loser; /* err set by AppendHandshake. */ } if (i) { /* Not end-entity. */ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); if (rv != SECSuccess) { - return SECFailure; /* err set by AppendHandshake. */ + goto loser; /* err set by AppendHandshake. */ } continue; } /* End-entity, send extensions. */ - rv = ssl3_AppendHandshakeNumber(ss, extensionsLen, 2); + rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2); if (rv != SECSuccess) { - return SECFailure; /* err set by AppendHandshake. */ - } - - sentLen = ssl3_CallHelloExtensionSenders( - ss, PR_TRUE, extensionsLen, - &ss->xtnData.certificateSenders[0]); - PORT_Assert(sentLen == extensionsLen); - if (sentLen != extensionsLen) { - LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; + goto loser; /* err set by AppendHandshake. */ } } } + sslBuffer_Clear(&extensionBuf); return SECSuccess; + +loser: + sslBuffer_Clear(&extensionBuf); + return SECFailure; } static SECStatus @@ -2293,7 +2803,7 @@ tls13_HandleCertificateEntry(sslSocket *ss, SECItem *data, PRBool first, if (first && !ss->sec.isServer) { rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len, - certificate); + ssl_hs_certificate); if (rv != SECSuccess) { return SECFailure; } @@ -2351,6 +2861,11 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length) if (rv != SECSuccess) return SECFailure; + /* We can ignore any other cleartext from the client. */ + if (ss->sec.isServer && IS_DTLS(ss)) { + ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText); + dtls_ReceivedFirstMessageInFlight(ss); + } /* Process the context string */ rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length); if (rv != SECSuccess) @@ -2445,32 +2960,6 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length) return ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */ } -void -tls13_CipherSpecAddRef(ssl3CipherSpec *spec) -{ - ++spec->refCt; - SSL_TRC(10, ("%d: TLS13[-]: Increment ref ct for spec %d. new ct = %d", - SSL_GETPID(), spec, spec->refCt)); -} - -/* This function is never called on a spec which is on the - * cipherSpecs list. */ -void -tls13_CipherSpecRelease(ssl3CipherSpec *spec) -{ - PORT_Assert(spec->refCt > 0); - --spec->refCt; - SSL_TRC(10, ("%d: TLS13[-]: decrement refct for spec %d. phase=%s new ct = %d", - SSL_GETPID(), spec, spec->phase, spec->refCt)); - if (!spec->refCt) { - SSL_TRC(10, ("%d: TLS13[-]: Freeing spec %d. phase=%s", - SSL_GETPID(), spec, spec->phase)); - PR_REMOVE_LINK(&spec->link); - ssl3_DestroyCipherSpec(spec, PR_TRUE); - PORT_Free(spec); - } -} - /* Add context to the hash functions as described in [draft-ietf-tls-tls13; Section 4.9.1] */ SECStatus @@ -2539,15 +3028,56 @@ loser: * HKDF-Expand-Label(Secret, Label, * Hash(Messages) + Hash(resumption_context), L)) */ -static SECStatus +SECStatus tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, - const char *prefix, - const char *suffix, + const char *label, + unsigned int labelLen, const SSL3Hashes *hashes, PK11SymKey **dest) { SECStatus rv; - SSL3Hashes hashesTmp; + + rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss), + hashes->u.raw, hashes->len, + label, labelLen, + tls13_GetHkdfMechanism(ss), + tls13_GetHashSize(ss), dest); + if (rv != SECSuccess) { + LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return SECSuccess; +} + +/* Convenience wrapper for the empty hash. */ +SECStatus +tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key, + const char *label, + unsigned int labelLen, + PK11SymKey **dest) +{ + SSL3Hashes hashes; + SECStatus rv; + PRUint8 buf[] = { 0 }; + + rv = tls13_ComputeHash(ss, &hashes, buf, 0); + if (rv != SECSuccess) { + return SECFailure; + } + + return tls13_DeriveSecret(ss, key, label, labelLen, &hashes, dest); +} + +/* Convenience wrapper that lets us supply a separate prefix and suffix. */ +static SECStatus +tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key, + const char *prefix, + const char *suffix, + const char *keylogLabel, + PK11SymKey **dest) +{ + SECStatus rv; + SSL3Hashes hashes; char buf[100]; const char *label; @@ -2566,25 +3096,22 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, SSL_TRC(3, ("%d: TLS13[%d]: deriving secret '%s'", SSL_GETPID(), ss->fd, label)); - if (!hashes) { - rv = tls13_ComputeHandshakeHashes(ss, &hashesTmp); - if (rv != SECSuccess) { - PORT_Assert(0); /* Should never fail */ - ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - hashes = &hashesTmp; + rv = tls13_ComputeHandshakeHashes(ss, &hashes); + if (rv != SECSuccess) { + PORT_Assert(0); /* Should never fail */ + ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } - rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss), - hashes->u.raw, hashes->len, - label, strlen(label), - tls13_GetHkdfMechanism(ss), - tls13_GetHashSize(ss), dest); + rv = tls13_DeriveSecret(ss, key, label, strlen(label), + &hashes, dest); if (rv != SECSuccess) { - LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } + + if (keylogLabel) { + ssl3_RecordKeyLog(ss, keylogLabel, *dest); + } return SECSuccess; } @@ -2592,49 +3119,41 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, static SECStatus tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, TrafficKeyType type, - CipherSpecDirection direction, PRBool deleteSecret) { - size_t keySize = spec->cipher_def->key_size; - size_t ivSize = spec->cipher_def->iv_size + - spec->cipher_def->explicit_nonce_size; /* This isn't always going to - * work, but it does for - * AES-GCM */ - CK_MECHANISM_TYPE bulkAlgorithm = ssl3_Alg2Mech(spec->cipher_def->calg); + size_t keySize = spec->cipherDef->key_size; + size_t ivSize = spec->cipherDef->iv_size + + spec->cipherDef->explicit_nonce_size; /* This isn't always going to + * work, but it does for + * AES-GCM */ + CK_MECHANISM_TYPE bulkAlgorithm = ssl3_Alg2Mech(spec->cipherDef->calg); PK11SymKey **prkp = NULL; PK11SymKey *prk = NULL; - PRBool clientKey; - ssl3KeyMaterial *target; - const char *phase; + PRBool clientSecret; SECStatus rv; /* These labels are just used for debugging. */ static const char kHkdfPhaseEarlyApplicationDataKeys[] = "early application data"; static const char kHkdfPhaseHandshakeKeys[] = "handshake data"; static const char kHkdfPhaseApplicationDataKeys[] = "application data"; - if (ss->sec.isServer ^ (direction == CipherSpecWrite)) { - clientKey = PR_TRUE; - target = &spec->client; - } else { - clientKey = PR_FALSE; - target = &spec->server; - } - PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + clientSecret = !tls13_UseServerSecret(ss, spec->direction); switch (type) { case TrafficKeyEarlyApplicationData: - PORT_Assert(clientKey); - phase = kHkdfPhaseEarlyApplicationDataKeys; + PORT_Assert(clientSecret); prkp = &ss->ssl3.hs.clientEarlyTrafficSecret; + spec->phase = kHkdfPhaseEarlyApplicationDataKeys; break; case TrafficKeyHandshake: - phase = kHkdfPhaseHandshakeKeys; - prkp = clientKey ? &ss->ssl3.hs.clientHsTrafficSecret : &ss->ssl3.hs.serverHsTrafficSecret; + prkp = clientSecret ? &ss->ssl3.hs.clientHsTrafficSecret + : &ss->ssl3.hs.serverHsTrafficSecret; + spec->phase = kHkdfPhaseHandshakeKeys; break; case TrafficKeyApplicationData: - phase = kHkdfPhaseApplicationDataKeys; - prkp = clientKey ? &ss->ssl3.hs.clientTrafficSecret : &ss->ssl3.hs.serverTrafficSecret; + prkp = clientSecret ? &ss->ssl3.hs.clientTrafficSecret + : &ss->ssl3.hs.serverTrafficSecret; + spec->phase = kHkdfPhaseApplicationDataKeys; break; default: LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); @@ -2644,17 +3163,15 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, PORT_Assert(prkp != NULL); prk = *prkp; - SSL_TRC(3, ("%d: TLS13[%d]: deriving %s traffic keys phase='%s'", - SSL_GETPID(), ss->fd, - (direction == CipherSpecWrite) ? "write" : "read", phase)); - PORT_Assert(phase); - spec->phase = phase; + SSL_TRC(3, ("%d: TLS13[%d]: deriving %s traffic keys epoch=%d (%s)", + SSL_GETPID(), ss->fd, SPEC_DIR(spec), + spec->epoch, spec->phase)); rv = tls13_HkdfExpandLabel(prk, tls13_GetHash(ss), NULL, 0, kHkdfPurposeKey, strlen(kHkdfPurposeKey), bulkAlgorithm, keySize, - &target->write_key); + &spec->keyMaterial.key); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); @@ -2664,7 +3181,7 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss), NULL, 0, kHkdfPurposeIv, strlen(kHkdfPurposeIv), - target->write_iv, ivSize); + spec->keyMaterial.iv, ivSize); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); @@ -2681,38 +3198,111 @@ loser: return SECFailure; } +void +tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec) +{ + /* Set the record version to pretend to be (D)TLS 1.2. */ + if (IS_DTLS(ss)) { + spec->recordVersion = SSL_LIBRARY_VERSION_DTLS_1_2_WIRE; + } else { + spec->recordVersion = SSL_LIBRARY_VERSION_TLS_1_2; + } + SSL_TRC(10, ("%d: TLS13[%d]: set spec=%d record version to 0x%04x", + SSL_GETPID(), ss->fd, spec, spec->recordVersion)); +} + static SECStatus -tls13_SetupPendingCipherSpec(sslSocket *ss) +tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) { - ssl3CipherSpec *pSpec; ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite; - const ssl3BulkCipherDef *bulk = ssl_GetBulkCipherDef( - ssl_LookupCipherSuiteDef(suite)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert(spec->epoch); - ssl_GetSpecWriteLock(ss); /*******************************/ - - pSpec = ss->ssl3.pwSpec; /* Version isn't set when we send 0-RTT data. */ - pSpec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version); + spec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version); + + ssl_SaveCipherSpec(ss, spec); + /* We want to keep read cipher specs around longer because + * there are cases where we might get either epoch N or + * epoch N+1. */ + if (IS_DTLS(ss) && spec->direction == CipherSpecRead) { + ssl_CipherSpecAddRef(spec); + } SSL_TRC(3, ("%d: TLS13[%d]: Set Pending Cipher Suite to 0x%04x", SSL_GETPID(), ss->fd, suite)); - pSpec->cipher_def = bulk; - ssl_ReleaseSpecWriteLock(ss); /*******************************/ + spec->cipherDef = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite)); + switch (spec->cipherDef->calg) { + case ssl_calg_aes_gcm: + spec->aead = tls13_AESGCM; + break; + case ssl_calg_chacha20: + spec->aead = tls13_ChaCha20Poly1305; + break; + default: + PORT_Assert(0); + return SECFailure; + } + + if (spec->epoch == TrafficKeyEarlyApplicationData) { + spec->earlyDataRemaining = + ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size; + } + + tls13_SetSpecRecordVersion(ss, spec); + return SECSuccess; +} + +/* + * Called before sending alerts to set up the right key on the client. + * We might encounter errors during the handshake where the current + * key is ClearText or EarlyApplicationData. This + * function switches to the Handshake key if possible. + */ +SECStatus +tls13_SetAlertCipherSpec(sslSocket *ss) +{ + SECStatus rv; + + if (ss->sec.isServer) { + return SECSuccess; + } + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + if (TLS13_IN_HS_STATE(ss, wait_server_hello)) { + return SECSuccess; + } + if ((ss->ssl3.cwSpec->epoch != TrafficKeyClearText) && + (ss->ssl3.cwSpec->epoch != TrafficKeyEarlyApplicationData)) { + return SECSuccess; + } + + rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, + CipherSpecWrite, PR_FALSE); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } return SECSuccess; } -/* Install a new cipher spec for this direction. */ +/* Install a new cipher spec for this direction. + * + * During the handshake, the values for |epoch| take values from the + * TrafficKeyType enum. Afterwards, key update increments them. + */ static SECStatus -tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, +tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, CipherSpecDirection direction, PRBool deleteSecret) { + TrafficKeyType type; SECStatus rv; ssl3CipherSpec *spec = NULL; - ssl3CipherSpec **specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec; + ssl3CipherSpec **specp; + /* Flush out old handshake data. */ ssl_GetXmitBufLock(ss); rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); @@ -2722,81 +3312,52 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, } /* Create the new spec. */ - spec = PORT_ZNew(ssl3CipherSpec); + spec = ssl_CreateCipherSpec(ss, direction); if (!spec) { - PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } - spec->refCt = 1; - PR_APPEND_LINK(&spec->link, &ss->ssl3.hs.cipherSpecs); - ss->ssl3.pwSpec = ss->ssl3.prSpec = spec; - - rv = tls13_SetupPendingCipherSpec(ss); - if (rv != SECSuccess) - return SECFailure; - - switch (spec->cipher_def->calg) { - case calg_aes_gcm: - spec->aead = tls13_AESGCM; - break; - case calg_chacha20: - spec->aead = tls13_ChaCha20Poly1305; - break; - default: - PORT_Assert(0); - return SECFailure; - break; + spec->epoch = epoch; + spec->seqNum = 0; + if (IS_DTLS(ss)) { + dtls_InitRecvdRecords(&spec->recvdRecords); } - rv = tls13_DeriveTrafficKeys(ss, spec, type, direction, - deleteSecret); + /* This depends on spec having a valid direction and epoch. */ + rv = tls13_SetupPendingCipherSpec(ss, spec); if (rv != SECSuccess) { - return SECFailure; - } - - /* We use the epoch for cipher suite identification, so increment - * it in both TLS and DTLS. */ - if ((*specp)->epoch == PR_UINT16_MAX) { - return SECFailure; - } - spec->epoch = (PRUint16)type; - - if (!IS_DTLS(ss)) { - spec->read_seq_num = spec->write_seq_num = 0; - } else { - /* The sequence number has the high 16 bits as the epoch. */ - spec->read_seq_num = spec->write_seq_num = - (sslSequenceNumber)spec->epoch << 48; - - dtls_InitRecvdRecords(&spec->recvdRecords); + goto loser; } - if (type == TrafficKeyEarlyApplicationData) { - spec->earlyDataRemaining = - ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size; + type = (TrafficKeyType)PR_MIN(TrafficKeyApplicationData, epoch); + rv = tls13_DeriveTrafficKeys(ss, spec, type, deleteSecret); + if (rv != SECSuccess) { + goto loser; } /* Now that we've set almost everything up, finally cut over. */ + specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec; ssl_GetSpecWriteLock(ss); - tls13_CipherSpecRelease(*specp); /* May delete old cipher. */ - *specp = spec; /* Overwrite. */ + ssl_CipherSpecRelease(*specp); /* May delete old cipher. */ + *specp = spec; /* Overwrite. */ ssl_ReleaseSpecWriteLock(ss); - SSL_TRC(3, ("%d: TLS13[%d]: %s installed key for phase='%s'.%d dir=%s", - SSL_GETPID(), ss->fd, SSL_ROLE(ss), - spec->phase, spec->epoch, - direction == CipherSpecRead ? "read" : "write")); + SSL_TRC(3, ("%d: TLS13[%d]: %s installed key for epoch=%d (%s) dir=%s", + SSL_GETPID(), ss->fd, SSL_ROLE(ss), spec->epoch, + spec->phase, SPEC_DIR(spec))); if (ss->ssl3.changedCipherSpecFunc) { ss->ssl3.changedCipherSpecFunc(ss->ssl3.changedCipherSpecArg, direction == CipherSpecWrite, spec); } return SECSuccess; + +loser: + ssl_CipherSpecRelease(spec); + return SECFailure; } -static SECStatus -tls13_ComputeHandshakeHashes(sslSocket *ss, - SSL3Hashes *hashes) +SECStatus +tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes) { SECStatus rv; PK11Context *ctx = NULL; @@ -2816,7 +3377,7 @@ tls13_ComputeHandshakeHashes(sslSocket *ss, goto loser; } - PRINT_BUF(10, (NULL, "Handshake hash computed over saved messages", + PRINT_BUF(10, (ss, "Handshake hash computed over saved messages", ss->ssl3.hs.messages.buf, ss->ssl3.hs.messages.len)); @@ -2841,6 +3402,8 @@ tls13_ComputeHandshakeHashes(sslSocket *ss, ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE); goto loser; } + + PRINT_BUF(10, (ss, "Handshake hash", hashes->u.raw, hashes->len)); PORT_Assert(hashes->len == tls13_GetHashSize(ss)); PK11_DestroyContext(ctx, PR_TRUE); @@ -2890,19 +3453,6 @@ tls13_DestroyEarlyData(PRCList *list) } } -void -tls13_DestroyCipherSpecs(PRCList *list) -{ - PRCList *cur_p; - - while (!PR_CLIST_IS_EMPTY(list)) { - cur_p = PR_LIST_TAIL(list); - PR_REMOVE_LINK(cur_p); - ssl3_DestroyCipherSpec((ssl3CipherSpec *)cur_p, PR_FALSE); - PORT_Free(cur_p); - } -} - /* draft-ietf-tls-tls13 Section 5.2.2 specifies the following * nonce algorithm: * @@ -2932,7 +3482,7 @@ tls13_WriteNonce(ssl3KeyMaterial *keys, size_t i; PORT_Assert(nonceLen == 12); - memcpy(nonce, keys->write_iv, 12); + memcpy(nonce, keys->iv, 12); /* XOR the last 8 bytes of the IV with the sequence number. */ PORT_Assert(seqNumLen == 8); @@ -2962,10 +3512,10 @@ tls13_AEAD(ssl3KeyMaterial *keys, PRBool doDecrypt, }; if (doDecrypt) { - rv = PK11_Decrypt(keys->write_key, mechanism, ¶m, + rv = PK11_Decrypt(keys->key, mechanism, ¶m, out, &uOutLen, maxout, in, inlen); } else { - rv = PK11_Encrypt(keys->write_key, mechanism, ¶m, + rv = PK11_Encrypt(keys->key, mechanism, ¶m, out, &uOutLen, maxout, in, inlen); } *outlen = (int)uOutLen; @@ -3062,7 +3612,7 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length) ss->xtnData.nextProto.data = NULL; ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT; } - rv = ssl3_HandleExtensions(ss, &b, &length, encrypted_extensions); + rv = ssl3_HandleExtensions(ss, &b, &length, ssl_hs_encrypted_extensions); if (rv != SECSuccess) { return SECFailure; /* Error code set below */ } @@ -3114,10 +3664,8 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length) static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss) { + sslBuffer extensions = SSL_BUFFER_EMPTY; SECStatus rv; - PRInt32 extensions_len = 0; - PRInt32 sent_len = 0; - PRUint32 maxBytes = 65535; SSL_TRC(3, ("%d: TLS13[%d]: send encrypted extensions handshake", SSL_GETPID(), ss->fd)); @@ -3125,31 +3673,28 @@ tls13_SendEncryptedExtensions(sslSocket *ss) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - extensions_len = ssl3_CallHelloExtensionSenders( - ss, PR_FALSE, maxBytes, &ss->xtnData.encryptedExtensionsSenders[0]); - - rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions, - extensions_len + 2); + rv = ssl_ConstructExtensions(ss, &extensions, ssl_hs_encrypted_extensions); if (rv != SECSuccess) { - LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); + + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_encrypted_extensions, + SSL_BUFFER_LEN(&extensions) + 2); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; + goto loser; } - sent_len = ssl3_CallHelloExtensionSenders( - ss, PR_TRUE, extensions_len, - &ss->xtnData.encryptedExtensionsSenders[0]); - PORT_Assert(sent_len == extensions_len); - if (sent_len != extensions_len) { + rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensions, 2); + if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); - PORT_Assert(sent_len == 0); - return SECFailure; + goto loser; } - + sslBuffer_Clear(&extensions); return SECSuccess; + +loser: + sslBuffer_Clear(&extensions); + return SECFailure; } SECStatus @@ -3210,7 +3755,7 @@ tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey) len = buf.len + 2 + 2; - rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len); if (rv != SECSuccess) { goto done; /* error code set by AppendHandshake */ } @@ -3238,14 +3783,14 @@ done: * Caller must hold Handshake and RecvBuf locks. */ SECStatus -tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, - SSL3Hashes *hashes) +tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECItem signed_hash = { siBuffer, NULL, 0 }; SECStatus rv; SSLSignatureScheme sigScheme; SSLHashType hashAlg; SSL3Hashes tbsHash; + SSL3Hashes hashes; SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake", SSL_GETPID(), ss->fd)); @@ -3257,7 +3802,17 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, if (rv != SECSuccess) { return SECFailure; } - PORT_Assert(hashes); + + rv = tls13_ComputeHandshakeHashes(ss, &hashes); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl_HashHandshakeMessage(ss, ssl_hs_certificate_verify, b, length); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); if (rv != SECSuccess) { @@ -3272,7 +3827,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, } hashAlg = ssl_SignatureSchemeToHashType(sigScheme); - rv = tls13_AddContextToHashes(ss, hashes, hashAlg, PR_FALSE, &tbsHash); + rv = tls13_AddContextToHashes(ss, &hashes, hashAlg, PR_FALSE, &tbsHash); if (rv != SECSuccess) { FATAL_ERROR(ss, SSL_ERROR_DIGEST_FAILURE, internal_error); return SECFailure; @@ -3301,13 +3856,11 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, } /* Request a client certificate now if one was requested. */ - if (ss->ssl3.hs.certificateRequest) { - TLS13CertificateRequest *req = ss->ssl3.hs.certificateRequest; - + if (ss->ssl3.hs.clientCertRequested) { PORT_Assert(!ss->sec.isServer); - rv = ssl3_CompleteHandleCertificateRequest(ss, req->signatureSchemes, - req->signatureSchemeCount, - &req->ca_list); + rv = ssl3_CompleteHandleCertificateRequest( + ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes, + &ss->xtnData.certReqAuthorities); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return rv; @@ -3320,7 +3873,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, } static SECStatus -tls13_ComputePskBinderHash(sslSocket *ss, unsigned long prefixLength, +tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength, SSL3Hashes *hashes) { SECStatus rv; @@ -3332,38 +3885,75 @@ tls13_ComputePskBinderHash(sslSocket *ss, unsigned long prefixLength, PRINT_BUF(10, (NULL, "Handshake hash computed over ClientHello prefix", ss->ssl3.hs.messages.buf, prefixLength)); rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)), - hashes->u.raw, - ss->ssl3.hs.messages.buf, prefixLength); + hashes->u.raw, ss->ssl3.hs.messages.buf, prefixLength); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - goto loser; + return SECFailure; } - hashes->len = tls13_GetHashSize(ss); - PRINT_BUF(10, (NULL, "PSK Binder hash", - hashes->u.raw, hashes->len)); + hashes->len = tls13_GetHashSize(ss); + PRINT_BUF(10, (NULL, "PSK Binder hash", hashes->u.raw, hashes->len)); return SECSuccess; - -loser: - return SECFailure; } -/* Compute the PSK Binder This is kind of sneaky.*/ + +/* Compute and inject the PSK Binder for sending. + * + * When sending a ClientHello, we construct all the extensions with a dummy + * value for the binder. To construct the binder, we commit the entire message + * up to the point where the binders start. Then we calculate the hash using + * the saved message (in ss->ssl3.hs.messages). This is written over the dummy + * binder, after which we write the remainder of the binder extension. */ SECStatus -tls13_ComputePskBinder(sslSocket *ss, PRBool sending, - unsigned int prefixLength, - PRUint8 *output, unsigned int *outputLen, - unsigned int maxOutputLen) +tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions) { SSL3Hashes hashes; SECStatus rv; + unsigned int size = tls13_GetHashSize(ss); + unsigned int prefixLen = extensions->len - size - 3; + unsigned int finishedLen; - rv = tls13_ComputePskBinderHash(ss, prefixLength, &hashes); - if (rv != SECSuccess) + PORT_Assert(extensions->len >= size + 3); + + rv = ssl3_AppendHandshakeNumber(ss, extensions->len, 2); + if (rv != SECSuccess) { return SECFailure; + } - return tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes, - sending, output, outputLen, maxOutputLen); + /* Only write the extension up to the point before the binders. Assume that + * the pre_shared_key extension is at the end of the buffer. Don't write + * the binder, or the lengths that precede it (a 2 octet length for the list + * of all binders, plus a 1 octet length for the binder length). */ + rv = ssl3_AppendHandshake(ss, extensions->buf, prefixLen); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Calculate the binder based on what has been written out. */ + rv = tls13_ComputePskBinderHash(ss, ss->ssl3.hs.messages.len, &hashes); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Write the binder into the extensions buffer, over the zeros we reserved + * previously. This avoids an allocation and means that we don't need a + * separate write for the extra bits that precede the binder. */ + rv = tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes, PR_TRUE, + extensions->buf + extensions->len - size, + &finishedLen, size); + if (rv != SECSuccess) { + return SECFailure; + } + PORT_Assert(finishedLen == size); + + /* Write out the remainder of the extension. */ + rv = ssl3_AppendHandshake(ss, extensions->buf + prefixLen, + extensions->len - prefixLen); + if (rv != SECSuccess) { + return SECFailure; + } + + return SECSuccess; } static SECStatus @@ -3462,7 +4052,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey) return SECFailure; } - rv = ssl3_AppendHandshakeHeader(ss, finished, finishedLen); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, finishedLen); if (rv != SECSuccess) { return SECFailure; /* Error code already set. */ } @@ -3477,7 +4067,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey) } static SECStatus -tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, +tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message, PK11SymKey *secret, PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes) @@ -3500,7 +4090,7 @@ tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, if (length != finishedLen) { #ifndef UNSAFE_FUZZER_MODE - FATAL_ERROR(ss, message == finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + FATAL_ERROR(ss, message == ssl_hs_finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); return SECFailure; #endif } @@ -3517,8 +4107,37 @@ tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, } static SECStatus -tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, - const SSL3Hashes *hashes) +tls13_CommonHandleFinished(sslSocket *ss, PK11SymKey *key, + PRUint8 *b, PRUint32 length) +{ + SECStatus rv; + SSL3Hashes hashes; + + rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, + wait_finished); + if (rv != SECSuccess) { + return SECFailure; + } + ss->ssl3.hs.endOfFlight = PR_TRUE; + + rv = tls13_ComputeHandshakeHashes(ss, &hashes); + if (rv != SECSuccess) { + LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + rv = ssl_HashHandshakeMessage(ss, ssl_hs_finished, b, length); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + return tls13_VerifyFinished(ss, ssl_hs_finished, + key, b, length, &hashes); +} + +static SECStatus +tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; @@ -3528,27 +4147,19 @@ tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL_TRC(3, ("%d: TLS13[%d]: client handle finished handshake", SSL_GETPID(), ss->fd)); - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, - wait_finished); + rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.serverHsTrafficSecret, + b, length); if (rv != SECSuccess) { return SECFailure; } - rv = tls13_VerifyFinished(ss, finished, - ss->ssl3.hs.serverHsTrafficSecret, - b, length, hashes); - if (rv != SECSuccess) - return SECFailure; - return tls13_SendClientSecondRound(ss); } static SECStatus -tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, - const SSL3Hashes *hashes) +tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; - PK11SymKey *secret; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -3556,61 +4167,68 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake", SSL_GETPID(), ss->fd)); - rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, wait_finished); + rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.clientHsTrafficSecret, + b, length); if (rv != SECSuccess) { return SECFailure; } - if (TLS13_IN_HS_STATE(ss, wait_finished)) { - secret = ss->ssl3.hs.clientHsTrafficSecret; - } else { - secret = ss->ssl3.hs.clientEarlyTrafficSecret; + if (!ss->opt.requestCertificate && + (ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) { + dtls_ReceivedFirstMessageInFlight(ss); } - rv = tls13_VerifyFinished(ss, finished, secret, b, length, hashes); - if (rv != SECSuccess) - return SECFailure; - rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData, - CipherSpecRead, PR_TRUE); + CipherSpecRead, PR_FALSE); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return SECFailure; } - rv = tls13_FinishHandshake(ss); + if (IS_DTLS(ss)) { + ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText); + /* We need to keep the handshake cipher spec so we can + * read re-transmitted client Finished. */ + rv = dtls_StartTimer(ss, ss->ssl3.hs.hdTimer, + DTLS_RETRANSMIT_FINISHED_MS, + dtls13_HolddownTimerCb); + if (rv != SECSuccess) { + return SECFailure; + } + } + + rv = tls13_ComputeFinalSecrets(ss); if (rv != SECSuccess) { - return SECFailure; /* Error code and alerts handled below */ + return SECFailure; } + ssl_GetXmitBufLock(ss); if (ss->opt.enableSessionTickets) { - rv = tls13_SendNewSessionTicket(ss); + rv = tls13_SendNewSessionTicket(ss, NULL, 0); if (rv != SECSuccess) { - ssl_ReleaseXmitBufLock(ss); - return SECFailure; /* Error code and alerts handled below */ + goto loser; } rv = ssl3_FlushHandshake(ss, 0); + if (rv != SECSuccess) { + goto loser; + } } ssl_ReleaseXmitBufLock(ss); - if (rv != SECSuccess) - return SECFailure; - return SECSuccess; + return tls13_FinishHandshake(ss); + +loser: + ssl_ReleaseXmitBufLock(ss); + return SECFailure; } static SECStatus tls13_FinishHandshake(sslSocket *ss) { - SECStatus rv; - PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->ssl3.hs.restartTarget == NULL); - rv = tls13_ComputeFinalSecrets(ss); - if (rv != SECSuccess) - return SECFailure; - /* The first handshake is now completed. */ ss->handshake = NULL; @@ -3652,9 +4270,15 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert, return SECFailure; /* error code is set. */ } } - if (ss->ssl3.hs.certificateRequest) { - PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE); - ss->ssl3.hs.certificateRequest = NULL; + if (ss->ssl3.hs.clientCertRequested) { + SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE); + if (ss->xtnData.certReqAuthorities.arena) { + PORT_FreeArena(ss->xtnData.certReqAuthorities.arena, PR_FALSE); + ss->xtnData.certReqAuthorities.arena = NULL; + } + PORT_Memset(&ss->xtnData.certReqAuthorities, 0, + sizeof(ss->xtnData.certReqAuthorities)); + ss->ssl3.hs.clientCertRequested = PR_FALSE; } if (sendClientCert) { @@ -3670,7 +4294,7 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert, if (rv != SECSuccess) { return SECFailure; /* err code was set. */ } - rv = ssl3_FlushHandshake(ss, IS_DTLS(ss) ? ssl_SEND_FLAG_NO_RETRANSMIT : 0); + rv = ssl3_FlushHandshake(ss, 0); if (rv != SECSuccess) { /* No point in sending an alert here because we're not going to * be able to send it if we couldn't flush the handshake. */ @@ -3678,11 +4302,6 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert, return SECFailure; } - rv = dtls_StartHolddownTimer(ss); - if (rv != SECSuccess) { - return SECFailure; /* err code was set. */ - } - return SECSuccess; } @@ -3717,11 +4336,28 @@ tls13_SendClientSecondRound(sslSocket *ss) return SECWouldBlock; } + rv = tls13_ComputeApplicationSecrets(ss); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + return SECFailure; + } + if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { + ssl_GetXmitBufLock(ss); /*******************************/ rv = tls13_SendEndOfEarlyData(ss); + ssl_ReleaseXmitBufLock(ss); /*******************************/ if (rv != SECSuccess) { return SECFailure; /* Error code already set. */ } + } else if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss) && + ss->ssl3.hs.zeroRttState == ssl_0rtt_none && + !ss->ssl3.hs.helloRetry) { + ssl_GetXmitBufLock(ss); /*******************************/ + rv = ssl3_SendChangeCipherSpecsInt(ss); + ssl_ReleaseXmitBufLock(ss); /*******************************/ + if (rv != SECSuccess) { + return rv; + } } rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, @@ -3731,12 +4367,6 @@ tls13_SendClientSecondRound(sslSocket *ss) return SECFailure; } - rv = tls13_ComputeApplicationSecrets(ss); - if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; - } - rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData, CipherSpecRead, PR_FALSE); if (rv != SECSuccess) { @@ -3756,12 +4386,17 @@ tls13_SendClientSecondRound(sslSocket *ss) return SECFailure; } rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData, - CipherSpecWrite, PR_TRUE); + CipherSpecWrite, PR_FALSE); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } + rv = tls13_ComputeFinalSecrets(ss); + if (rv != SECSuccess) { + return SECFailure; + } + /* The handshake is now finished */ return tls13_FinishHandshake(ss); } @@ -3777,6 +4412,7 @@ tls13_SendClientSecondRound(sslSocket *ss) * struct { * uint32 ticket_lifetime; * uint32 ticket_age_add; + * opaque ticket_nonce<1..255>; * opaque ticket<1..2^16-1>; * TicketExtension extensions<0..2^16-2>; * } NewSessionTicket; @@ -3784,14 +4420,22 @@ tls13_SendClientSecondRound(sslSocket *ss) PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */ -SECStatus -tls13_SendNewSessionTicket(sslSocket *ss) +static SECStatus +tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, + unsigned int appTokenLen) { PRUint16 message_length; + PK11SymKey *secret; SECItem ticket_data = { 0, NULL, 0 }; SECStatus rv; NewSessionTicket ticket = { 0 }; PRUint32 max_early_data_size_len = 0; + PRUint8 ticketNonce[sizeof(ss->ssl3.hs.ticketNonce)]; + sslBuffer ticketNonceBuf = SSL_BUFFER(ticketNonce); + + SSL_TRC(3, ("%d: TLS13[%d]: send new session ticket message %d", + SSL_GETPID(), ss->fd, ss->ssl3.hs.ticketNonce)); + ticket.flags = 0; if (ss->opt.enable0RttData) { ticket.flags |= ticket_allow_early_data; @@ -3799,18 +4443,44 @@ tls13_SendNewSessionTicket(sslSocket *ss) } ticket.ticket_lifetime_hint = ssl_ticket_lifetime; - rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data); + /* The ticket age obfuscator. */ + rv = PK11_GenerateRandom((PRUint8 *)&ticket.ticket_age_add, + sizeof(ticket.ticket_age_add)); + if (rv != SECSuccess) + goto loser; + + rv = sslBuffer_AppendNumber(&ticketNonceBuf, ss->ssl3.hs.ticketNonce, + sizeof(ticketNonce)); + if (rv != SECSuccess) { + goto loser; + } + ++ss->ssl3.hs.ticketNonce; + rv = tls13_HkdfExpandLabel(ss->ssl3.hs.resumptionMasterSecret, + tls13_GetHash(ss), + ticketNonce, sizeof(ticketNonce), + kHkdfLabelResumption, + strlen(kHkdfLabelResumption), + tls13_GetHkdfMechanism(ss), + tls13_GetHashSize(ss), &secret); + if (rv != SECSuccess) { + goto loser; + } + + rv = ssl3_EncodeSessionTicket(ss, &ticket, appToken, appTokenLen, + secret, &ticket_data); + PK11_FreeSymKey(secret); if (rv != SECSuccess) goto loser; message_length = 4 + /* lifetime */ 4 + /* ticket_age_add */ + 1 + sizeof(ticketNonce) + /* ticket_nonce */ 2 + max_early_data_size_len + /* max_early_data_size_len */ 2 + /* ticket length */ ticket_data.len; - rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_new_session_ticket, message_length); if (rv != SECSuccess) goto loser; @@ -3820,13 +4490,12 @@ tls13_SendNewSessionTicket(sslSocket *ss) if (rv != SECSuccess) goto loser; - /* The ticket age obfuscator. */ - rv = PK11_GenerateRandom((PRUint8 *)&ticket.ticket_age_add, - sizeof(ticket.ticket_age_add)); + rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_age_add, 4); if (rv != SECSuccess) goto loser; - rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_age_add, 4); + /* The ticket nonce. */ + rv = ssl3_AppendHandshakeVariable(ss, ticketNonce, sizeof(ticketNonce), 1); if (rv != SECSuccess) goto loser; @@ -3843,7 +4512,7 @@ tls13_SendNewSessionTicket(sslSocket *ss) if (max_early_data_size_len) { rv = ssl3_AppendHandshakeNumber( - ss, ssl_tls13_ticket_early_data_info_xtn, 2); + ss, ssl_tls13_early_data_xtn, 2); if (rv != SECSuccess) goto loser; @@ -3867,6 +4536,42 @@ loser: return SECFailure; } +SECStatus +SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token, + unsigned int tokenLen) +{ + sslSocket *ss; + SECStatus rv; + + ss = ssl_FindSocket(fd); + if (!ss) { + return SECFailure; + } + + if (IS_DTLS(ss)) { + PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION); + return SECFailure; + } + + if (!ss->sec.isServer || !ss->firstHsDone || + ss->version < SSL_LIBRARY_VERSION_TLS_1_3 || + tokenLen > 0xffff) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + ssl_GetSSL3HandshakeLock(ss); + ssl_GetXmitBufLock(ss); + rv = tls13_SendNewSessionTicket(ss, token, tokenLen); + if (rv == SECSuccess) { + rv = ssl3_FlushHandshake(ss, 0); + } + ssl_ReleaseXmitBufLock(ss); + ssl_ReleaseSSL3HandshakeLock(ss); + + return rv; +} + static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) { @@ -3874,6 +4579,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) PRUint32 utmp; NewSessionTicket ticket = { 0 }; SECItem data; + SECItem ticket_nonce; SECItem ticket_data; SSL_TRC(3, ("%d: TLS13[%d]: handle new session ticket message", @@ -3890,7 +4596,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECFailure; } - ticket.received_timestamp = PR_Now(); + ticket.received_timestamp = ssl_TimeUsec(); rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b, &length); if (rv != SECSuccess) { @@ -3908,6 +4614,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) } ticket.ticket_age_add = PR_ntohl(utmp); + /* The nonce. */ + rv = ssl3_ConsumeHandshakeVariable(ss, &ticket_nonce, 1, &b, &length); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, + decode_error); + return SECFailure; + } + /* Get the ticket value. */ rv = ssl3_ConsumeHandshakeVariable(ss, &ticket_data, 2, &b, &length); if (rv != SECSuccess || !ticket_data.len) { @@ -3918,14 +4632,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) /* Parse extensions. */ rv = ssl3_ConsumeHandshakeVariable(ss, &data, 2, &b, &length); - if (rv != SECSuccess) { + if (rv != SECSuccess || length) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, decode_error); return SECFailure; } rv = ssl3_HandleExtensions(ss, &data.data, - &data.len, new_session_ticket); + &data.len, ssl_hs_new_session_ticket); if (rv != SECSuccess) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, decode_error); @@ -3936,13 +4650,9 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) ticket.max_early_data_size = ss->xtnData.max_early_data_size; } - if (length != 0) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, - decode_error); - return SECFailure; - } - if (!ss->opt.noCache) { + PK11SymKey *secret; + PORT_Assert(ss->sec.ci.sid); rv = SECITEM_CopyItem(NULL, &ticket.ticket, &ticket_data); if (rv != SECSuccess) { @@ -3979,9 +4689,22 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ticket); PORT_Assert(!ticket.ticket.data); - rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid); - if (rv != SECSuccess) + rv = tls13_HkdfExpandLabel(ss->ssl3.hs.resumptionMasterSecret, + tls13_GetHash(ss), + ticket_nonce.data, ticket_nonce.len, + kHkdfLabelResumption, + strlen(kHkdfLabelResumption), + tls13_GetHkdfMechanism(ss), + tls13_GetHashSize(ss), &secret); + if (rv != SECSuccess) { return SECFailure; + } + + rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid, secret); + PK11_FreeSymKey(secret); + if (rv != SECSuccess) { + return SECFailure; + } /* Cache the session. */ ss->sec.cache(ss->sec.ci.sid); @@ -3990,111 +4713,103 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECSuccess; } -typedef enum { - ExtensionNotUsed, - ExtensionClientOnly, - ExtensionSendClear, - ExtensionSendClearOrHrr, - ExtensionSendHrr, - ExtensionSendEncrypted, - ExtensionSendCertificate, - ExtensionNewSessionTicket -} Tls13ExtensionStatus; +#define _M(a) (1 << PR_MIN(a, 31)) +#define _M1(a) (_M(ssl_hs_##a)) +#define _M2(a, b) (_M1(a) | _M1(b)) +#define _M3(a, b, c) (_M1(a) | _M2(b, c)) static const struct { PRUint16 ex_value; - Tls13ExtensionStatus status; + PRUint32 messages; } KnownExtensions[] = { - { ssl_server_name_xtn, ExtensionSendEncrypted }, - { ssl_supported_groups_xtn, ExtensionSendEncrypted }, - { ssl_ec_point_formats_xtn, ExtensionNotUsed }, - { ssl_signature_algorithms_xtn, ExtensionClientOnly }, - { ssl_use_srtp_xtn, ExtensionSendEncrypted }, - { ssl_app_layer_protocol_xtn, ExtensionSendEncrypted }, - { ssl_padding_xtn, ExtensionNotUsed }, - { ssl_extended_master_secret_xtn, ExtensionNotUsed }, - { ssl_session_ticket_xtn, ExtensionClientOnly }, - { ssl_tls13_key_share_xtn, ExtensionSendClearOrHrr }, - { ssl_tls13_pre_shared_key_xtn, ExtensionSendClear }, - { ssl_tls13_early_data_xtn, ExtensionSendEncrypted }, - { ssl_next_proto_nego_xtn, ExtensionNotUsed }, - { ssl_renegotiation_info_xtn, ExtensionNotUsed }, - { ssl_signed_cert_timestamp_xtn, ExtensionSendCertificate }, - { ssl_cert_status_xtn, ExtensionSendCertificate }, - { ssl_tls13_ticket_early_data_info_xtn, ExtensionNewSessionTicket }, - { ssl_tls13_cookie_xtn, ExtensionSendHrr }, - { ssl_tls13_short_header_xtn, ExtensionSendClear } + { ssl_server_name_xtn, _M2(client_hello, encrypted_extensions) }, + { ssl_supported_groups_xtn, _M2(client_hello, encrypted_extensions) }, + { ssl_signature_algorithms_xtn, _M2(client_hello, certificate_request) }, + { ssl_signature_algorithms_cert_xtn, _M2(client_hello, + certificate_request) }, + { ssl_use_srtp_xtn, _M2(client_hello, encrypted_extensions) }, + { ssl_app_layer_protocol_xtn, _M2(client_hello, encrypted_extensions) }, + { ssl_padding_xtn, _M1(client_hello) }, + { ssl_tls13_key_share_xtn, _M3(client_hello, server_hello, + hello_retry_request) }, + { ssl_tls13_pre_shared_key_xtn, _M2(client_hello, server_hello) }, + { ssl_tls13_psk_key_exchange_modes_xtn, _M1(client_hello) }, + { ssl_tls13_early_data_xtn, _M3(client_hello, encrypted_extensions, + new_session_ticket) }, + { ssl_signed_cert_timestamp_xtn, _M3(client_hello, certificate_request, + certificate) }, + { ssl_cert_status_xtn, _M3(client_hello, certificate_request, + certificate) }, + { 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) } }; -PRBool -tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message) +tls13ExtensionStatus +tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message) { unsigned int i; - PORT_Assert((message == client_hello) || - (message == server_hello) || - (message == hello_retry_request) || - (message == encrypted_extensions) || - (message == new_session_ticket) || - (message == certificate) || - (message == certificate_request)); + PORT_Assert((message == ssl_hs_client_hello) || + (message == ssl_hs_server_hello) || + (message == ssl_hs_hello_retry_request) || + (message == ssl_hs_encrypted_extensions) || + (message == ssl_hs_new_session_ticket) || + (message == ssl_hs_certificate) || + (message == ssl_hs_certificate_request)); for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) { - if (KnownExtensions[i].ex_value == extension) + /* Hacky check for message numbers > 30. */ + PORT_Assert(!(KnownExtensions[i].messages & (1U << 31))); + if (KnownExtensions[i].ex_value == extension) { break; + } } - if (i == PR_ARRAY_SIZE(KnownExtensions)) { - /* We have never heard of this extension which is OK - * in client_hello and new_session_ticket. */ - return (message == client_hello) || - (message == new_session_ticket); - } - - switch (KnownExtensions[i].status) { - case ExtensionNotUsed: - return PR_FALSE; - case ExtensionClientOnly: - return message == client_hello; - case ExtensionSendClear: - return message == client_hello || - message == server_hello; - case ExtensionSendClearOrHrr: - return message == client_hello || - message == server_hello || - message == hello_retry_request; - case ExtensionSendHrr: - return message == client_hello || - message == hello_retry_request; - case ExtensionSendEncrypted: - return message == client_hello || - message == encrypted_extensions; - case ExtensionNewSessionTicket: - return message == new_session_ticket; - case ExtensionSendCertificate: - return message == client_hello || - message == certificate; + if (i >= PR_ARRAY_SIZE(KnownExtensions)) { + return tls13_extension_unknown; } - PORT_Assert(0); + /* Return "disallowed" if the message mask bit isn't set. */ + if (!(_M(message) & KnownExtensions[i].messages)) { + SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d", + SSL_GETPID(), extension, message)); - /* Not reached */ - return PR_TRUE; + return tls13_extension_disallowed; + } + + return tls13_extension_allowed; } +#undef _M +#undef _M1 +#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. */ -static void -tls13_FormatAdditionalData(PRUint8 *aad, unsigned int length, - sslSequenceNumber seqNum) +static SECStatus +tls13_FormatAdditionalData(sslSocket *ss, PRUint8 *aad, unsigned int length, + DTLSEpoch epoch, sslSequenceNumber seqNum) { - PRUint8 *ptr = aad; + SECStatus rv; + sslBuffer buf = SSL_BUFFER_FIXED(aad, length); PORT_Assert(length == 8); - ptr = ssl_EncodeUintX(seqNum, 8, ptr); - PORT_Assert((ptr - aad) == length); + if (IS_DTLS(ss)) { + rv = sslBuffer_AppendNumber(&buf, epoch, 2); + if (rv != SECSuccess) { + return SECFailure; + } + } + rv = sslBuffer_AppendNumber(&buf, seqNum, IS_DTLS(ss) ? 6 : 8); + if (rv != SECSuccess) { + return SECFailure; + } + return SECSuccess; } PRInt32 @@ -4127,13 +4842,14 @@ tls13_ProtectRecord(sslSocket *ss, PRUint32 contentLen, sslBuffer *wrBuf) { - const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def; + const ssl3BulkCipherDef *cipher_def = cwSpec->cipherDef; const int tagLen = cipher_def->tag_size; SECStatus rv; - SSL_TRC(3, ("%d: TLS13[%d]: spec=%d (%s) protect record 0x%0llx len=%u", - SSL_GETPID(), ss->fd, cwSpec, cwSpec->phase, - cwSpec->write_seq_num, contentLen)); + 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)); if (contentLen + 1 + tagLen > wrBuf->space) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -4154,15 +4870,18 @@ tls13_ProtectRecord(sslSocket *ss, /* Add the content type at the end. */ wrBuf->buf[contentLen] = type; - tls13_FormatAdditionalData(aad, sizeof(aad), cwSpec->write_seq_num); - rv = cwSpec->aead( - ss->sec.isServer ? &cwSpec->server : &cwSpec->client, - PR_FALSE, /* do encrypt */ - wrBuf->buf, /* output */ - (int *)&wrBuf->len, /* out len */ - wrBuf->space, /* max out */ - wrBuf->buf, contentLen + 1, /* input */ - aad, sizeof(aad)); + rv = tls13_FormatAdditionalData(ss, aad, sizeof(aad), cwSpec->epoch, + cwSpec->seqNum); + 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)); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); return SECFailure; @@ -4182,19 +4901,27 @@ tls13_ProtectRecord(sslSocket *ss, * 2. Call PORT_SetError() witn an appropriate code. */ SECStatus -tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, +tls13_UnprotectRecord(sslSocket *ss, + ssl3CipherSpec *spec, + SSL3Ciphertext *cText, sslBuffer *plaintext, SSL3AlertDescription *alert) { - ssl3CipherSpec *crSpec = ss->ssl3.crSpec; - const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def; + const ssl3BulkCipherDef *cipher_def = spec->cipherDef; + sslSequenceNumber seqNum; PRUint8 aad[8]; SECStatus rv; *alert = bad_record_mac; /* Default alert for most issues. */ - SSL_TRC(3, ("%d: TLS13[%d]: spec=%d (%s) unprotect record 0x%0llx len=%u", - SSL_GETPID(), ss->fd, crSpec, crSpec->phase, - crSpec->read_seq_num, cText->buf->len)); + 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)); /* We can perform this test in variable time because the record's total * length and the ciphersuite are both public knowledge. */ @@ -4216,9 +4943,8 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext return SECFailure; } - /* Check the version number in the record */ - if ((IS_DTLS(ss) && cText->version != kDtlsRecordVersion) || - (!IS_DTLS(ss) && cText->version != kTlsRecordVersion)) { + /* 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", @@ -4228,18 +4954,18 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext /* Decrypt */ PORT_Assert(cipher_def->type == type_aead); - tls13_FormatAdditionalData(aad, sizeof(aad), - IS_DTLS(ss) ? cText->seq_num - : crSpec->read_seq_num); - rv = crSpec->aead( - ss->sec.isServer ? &crSpec->client : &crSpec->server, - PR_TRUE, /* do decrypt */ - plaintext->buf, /* out */ - (int *)&plaintext->len, /* outlen */ - plaintext->space, /* maxout */ - cText->buf->buf, /* in */ - cText->buf->len, /* inlen */ - aad, sizeof(aad)); + rv = tls13_FormatAdditionalData(ss, aad, sizeof(aad), spec->epoch, seqNum); + if (rv != SECSuccess) { + return SECFailure; + } + rv = spec->aead(&spec->keyMaterial, + PR_TRUE, /* do decrypt */ + plaintext->buf, /* out */ + (int *)&plaintext->len, /* outlen */ + plaintext->space, /* maxout */ + cText->buf->buf, /* in */ + cText->buf->len, /* inlen */ + aad, sizeof(aad)); if (rv != SECSuccess) { SSL_TRC(3, ("%d: TLS13[%d]: record has bogus MAC", @@ -4271,14 +4997,14 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext --plaintext->len; /* Check that we haven't received too much 0-RTT data. */ - if (crSpec->epoch == TrafficKeyEarlyApplicationData && + if (spec->epoch == TrafficKeyEarlyApplicationData && cText->type == content_application_data) { - if (plaintext->len > crSpec->earlyDataRemaining) { + if (plaintext->len > spec->earlyDataRemaining) { *alert = unexpected_message; PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA); return SECFailure; } - crSpec->earlyDataRemaining -= plaintext->len; + spec->earlyDataRemaining -= plaintext->len; } SSL_TRC(10, @@ -4326,7 +5052,7 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss) /* Don't do anything if there is no early_data xtn, which means we're * not doing early data. */ - if (!ssl3_ClientExtensionAdvertised(ss, ssl_tls13_early_data_xtn)) { + if (!ssl3_ExtensionAdvertised(ss, ssl_tls13_early_data_xtn)) { return SECSuccess; } @@ -4341,25 +5067,41 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss) ss->xtnData.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE; rv = SECITEM_CopyItem(NULL, &ss->xtnData.nextProto, &ss->sec.ci.sid->u.ssl3.alpnSelection); - if (rv != SECSuccess) - return rv; + if (rv != SECSuccess) { + return SECFailure; + } + } + + if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) { + /* Pretend that this is a proper ChangeCipherSpec even though it is sent + * before receiving the ServerHello. */ + ssl_GetSpecWriteLock(ss); + tls13_SetSpecRecordVersion(ss, ss->ssl3.cwSpec); + ssl_ReleaseSpecWriteLock(ss); + ssl_GetXmitBufLock(ss); + rv = ssl3_SendChangeCipherSpecsInt(ss); + ssl_ReleaseXmitBufLock(ss); + if (rv != SECSuccess) { + return SECFailure; + } } /* Cipher suite already set in tls13_SetupClientHello. */ ss->ssl3.hs.preliminaryInfo = 0; - rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelClient, - kHkdfLabelEarlyTrafficSecret, - NULL, - &ss->ssl3.hs.clientEarlyTrafficSecret); - if (rv != SECSuccess) + rv = tls13_DeriveEarlySecrets(ss); + if (rv != SECSuccess) { return SECFailure; + } + + /* Save cwSpec in case we get a HelloRetryRequest and have to send another + * ClientHello. */ + ssl_CipherSpecAddRef(ss->ssl3.cwSpec); rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData, CipherSpecWrite, PR_TRUE); if (rv != SECSuccess) { - return rv; + return SECFailure; } return SECSuccess; @@ -4392,32 +5134,45 @@ tls13_SendEndOfEarlyData(sslSocket *ss) { SECStatus rv; - SSL_TRC(3, ("%d: TLS13[%d]: send end_of_early_data extension", - SSL_GETPID(), ss->fd)); + SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd)); + PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - rv = SSL3_SendAlert(ss, alert_warning, end_of_early_data); + rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0); if (rv != SECSuccess) { - FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; + return rv; /* err set by AppendHandshake. */ } ss->ssl3.hs.zeroRttState = ssl_0rtt_done; return SECSuccess; } -SECStatus -tls13_HandleEndOfEarlyData(sslSocket *ss) +static SECStatus +tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 || - ss->ssl3.hs.zeroRttState != ssl_0rtt_accepted) { - (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); - PORT_SetError(SSL_ERROR_END_OF_EARLY_DATA_ALERT); + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + + rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA, + wait_end_of_early_data); + if (rv != SECSuccess) { return SECFailure; } - PORT_Assert(TLS13_IN_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert : wait_finished)); + /* We shouldn't be getting any more early data, and if we do, + * it is because of reordering and we drop it. */ + if (IS_DTLS(ss)) { + ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, + TrafficKeyEarlyApplicationData); + dtls_ReceivedFirstMessageInFlight(ss); + } + + PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted); + + if (length) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA, decode_error); + return SECFailure; + } rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, CipherSpecRead, PR_FALSE); @@ -4427,6 +5182,9 @@ tls13_HandleEndOfEarlyData(sslSocket *ss) } ss->ssl3.hs.zeroRttState = ssl_0rtt_done; + TLS13_SET_HS_STATE(ss, + ss->opt.requestCertificate ? wait_client_cert + : wait_finished); return SECSuccess; } @@ -4477,11 +5235,11 @@ tls13_EncodeDraftVersion(SSL3ProtocolVersion version) /* Pick the highest version we support that is also advertised. */ SECStatus -tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions) +tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions) { PRUint16 version; - /* Make a copy so we're nondestructive*/ - SECItem data = supported_versions->data; + /* Make a copy so we're nondestructive. */ + SECItem data = supportedVersions->data; SECItem versions; SECStatus rv; @@ -4511,3 +5269,22 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions) FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version); return SECFailure; } + +/* This is TLS 1.3 or might negotiate to it. */ +PRBool +tls13_MaybeTls13(sslSocket *ss) +{ + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { + return PR_TRUE; + } + + if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { + return PR_FALSE; + } + + if (!(ss->ssl3.hs.preliminaryInfo & ssl_preinfo_version)) { + return PR_TRUE; + } + + return PR_FALSE; +} diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h index 92eb545b0..1aaffb651 100644 --- a/security/nss/lib/ssl/tls13con.h +++ b/security/nss/lib/ssl/tls13con.h @@ -9,15 +9,25 @@ #ifndef __tls13con_h_ #define __tls13con_h_ +#include "sslexp.h" +#include "sslspec.h" + +typedef enum { + tls13_extension_allowed, + tls13_extension_disallowed, + tls13_extension_unknown +} tls13ExtensionStatus; + typedef enum { - StaticSharedSecret, - EphemeralSharedSecret -} SharedSecretType; + update_not_requested = 0, + update_requested = 1 +} tls13KeyUpdateRequest; #define TLS13_MAX_FINISHED_SIZE 64 SECStatus tls13_UnprotectRecord( - sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, + sslSocket *ss, ssl3CipherSpec *spec, + SSL3Ciphertext *cText, sslBuffer *plaintext, SSL3AlertDescription *alert); #if defined(WIN32) @@ -41,6 +51,14 @@ SSLHashType tls13_GetHash(const sslSocket *ss); unsigned int tls13_GetHashSizeForHash(SSLHashType hash); unsigned int tls13_GetHashSize(const sslSocket *ss); CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss); +SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes, + const PRUint8 *buf, unsigned int len); +SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss, + SSL3Hashes *hashes); +SECStatus tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key, + const char *label, + unsigned int labelLen, + PK11SymKey **dest); void tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc); SECStatus tls13_SetupClientHello(sslSocket *ss); @@ -49,27 +67,30 @@ PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend PRBool tls13_AllowPskCipher(const sslSocket *ss, const ssl3CipherSuiteDef *cipher_def); PRBool tls13_PskSuiteEnabled(sslSocket *ss); -SECStatus tls13_ComputePskBinder(sslSocket *ss, PRBool sending, - unsigned int prefixLength, - PRUint8 *output, unsigned int *outputLen, - unsigned int maxOutputLen); +SECStatus tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions); SECStatus tls13_HandleClientHelloPart2(sslSocket *ss, const SECItem *suites, - sslSessionID *sid); + sslSessionID *sid, + const PRUint8 *msg, + unsigned int len); SECStatus tls13_HandleServerHelloPart2(sslSocket *ss); SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, - PRUint32 length, - SSL3Hashes *hashesPtr); -SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, + PRUint32 length); +SECStatus tls13_ConstructHelloRetryRequest(sslSocket *ss, + ssl3CipherSuite cipherSuite, + const sslNamedGroupDef *selectedGroup, + PRUint8 *cookie, + unsigned int cookieLen, + sslBuffer *buffer); +SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *b, PRUint32 length); void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry); void tls13_DestroyKeyShares(PRCList *list); SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef); void tls13_DestroyEarlyData(PRCList *list); -void tls13_CipherSpecAddRef(ssl3CipherSpec *spec); -void tls13_CipherSpecRelease(ssl3CipherSpec *spec); -void tls13_DestroyCipherSpecs(PRCList *list); -PRBool tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message); +SECStatus tls13_SetAlertCipherSpec(sslSocket *ss); +tls13ExtensionStatus tls13_ExtensionStatus(PRUint16 extension, + SSLHandshakeType message); SECStatus tls13_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, @@ -77,13 +98,25 @@ SECStatus tls13_ProtectRecord(sslSocket *ss, PRUint32 contentLen, sslBuffer *wrBuf); PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len); -SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss); SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf); PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid); PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version); -PRUint16 tls13_DecodeDraftVersion(PRUint16 version); SECStatus tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions); -SECStatus tls13_SendNewSessionTicket(sslSocket *ss); + +PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid); +void tls13_AntiReplayRollover(PRTime now); + +SECStatus SSLExp_SetupAntiReplay(PRTime window, unsigned int k, + unsigned int bits); + +SECStatus SSLExp_HelloRetryRequestCallback(PRFileDesc *fd, + SSLHelloRetryRequestCallback cb, + void *arg); +SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, + PRBool buffer); +SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate); +PRBool tls13_MaybeTls13(sslSocket *ss); +void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec); #endif /* __tls13con_h_ */ diff --git a/security/nss/lib/ssl/tls13err.h b/security/nss/lib/ssl/tls13err.h new file mode 100644 index 000000000..8cdeb12eb --- /dev/null +++ b/security/nss/lib/ssl/tls13err.h @@ -0,0 +1,28 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __tls13err_h_ +#define __tls13err_h_ + +/* Use this instead of FATAL_ERROR when an alert isn't possible. */ +#define LOG_ERROR(ss, prError) \ + do { \ + SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \ + SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \ + PORT_SetError(prError); \ + } while (0) + +/* Log an error and generate an alert because something is irreparably wrong. */ +#define FATAL_ERROR(ss, prError, desc) \ + do { \ + LOG_ERROR(ss, prError); \ + tls13_FatalError(ss, prError, desc); \ + } while (0) + +void tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc); +#endif diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c index c2ce390ff..899f23827 100644 --- a/security/nss/lib/ssl/tls13exthandle.c +++ b/security/nss/lib/ssl/tls13exthandle.c @@ -14,50 +14,35 @@ #include "ssl3exthandle.h" #include "tls13exthandle.h" -PRInt32 -tls13_ServerSendStatusRequestXtn( - const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) +SECStatus +tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; const sslServerCert *serverCert = ss->sec.serverCert; const SECItem *item; SECStatus rv; if (!serverCert->certStatusArray || !serverCert->certStatusArray->len) { - return 0; + return SECSuccess; } item = &serverCert->certStatusArray->items[0]; /* Only send the first entry. */ - extension_length = 2 + 2 + 1 /* status_type */ + 3 + item->len; - if (maxBytes < (PRUint32)extension_length) { - return 0; + /* status_type == ocsp */ + rv = sslBuffer_AppendNumber(buf, 1 /*ocsp*/, 1); + if (rv != SECSuccess) { + return SECFailure; } - if (append) { - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); - if (rv != SECSuccess) - return -1; - /* length of extension_data */ - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - return -1; - /* status_type == ocsp */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 1 /*ocsp*/, 1); - if (rv != SECSuccess) - return rv; /* err set by AppendHandshake. */ - /* opaque OCSPResponse<1..2^24-1> */ - rv = ssl3_ExtAppendHandshakeVariable(ss, item->data, item->len, 3); - if (rv != SECSuccess) - return rv; /* err set by AppendHandshake. */ + /* opaque OCSPResponse<1..2^24-1> */ + rv = sslBuffer_AppendVariable(buf, item->data, item->len, 3); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } /* @@ -101,41 +86,27 @@ tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey) return 0; } -static PRUint32 -tls13_SizeOfClientKeyShareExtension(const sslSocket *ss) -{ - PRCList *cursor; - /* Size is: extension(2) + extension_len(2) + client_shares(2) */ - PRUint32 size = 2 + 2 + 2; - for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs); - cursor != &ss->ephemeralKeyPairs; - cursor = PR_NEXT_LINK(cursor)) { - sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; - size += tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey); - } - return size; -} - static SECStatus -tls13_EncodeKeyShareEntry(const sslSocket *ss, const sslEphemeralKeyPair *keyPair) +tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair) { SECStatus rv; SECKEYPublicKey *pubKey = keyPair->keys->pubKey; unsigned int size = tls13_SizeOfKeyShareEntry(pubKey); - rv = ssl3_ExtAppendHandshakeNumber(ss, keyPair->group->name, 2); + rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2); if (rv != SECSuccess) return rv; - rv = ssl3_ExtAppendHandshakeNumber(ss, size - 4, 2); + rv = sslBuffer_AppendNumber(buf, size - 4, 2); if (rv != SECSuccess) return rv; switch (pubKey->keyType) { case ecKey: - rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey); + rv = sslBuffer_Append(buf, pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len); break; case dhKey: - rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_FALSE); + rv = ssl_AppendPaddedDHKeyShare(buf, pubKey, PR_FALSE); break; default: PORT_Assert(0); @@ -146,14 +117,16 @@ tls13_EncodeKeyShareEntry(const sslSocket *ss, const sslEphemeralKeyPair *keyPai return rv; } -PRInt32 -tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRUint32 extension_length; + SECStatus rv; + PRCList *cursor; + unsigned int lengthOffset; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { - return 0; + return SECSuccess; } /* Optimistically try to send an ECDHE key using the @@ -161,47 +134,28 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBo SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn", SSL_GETPID(), ss->fd)); - extension_length = tls13_SizeOfClientKeyShareExtension(ss); - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; + /* Save the offset to the length. */ + rv = sslBuffer_Skip(buf, 2, &lengthOffset); + if (rv != SECSuccess) { + return SECFailure; } - if (append) { - SECStatus rv; - PRCList *cursor; - - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); - if (rv != SECSuccess) - goto loser; - - /* The extension length */ - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - goto loser; - - /* The length of KeyShares */ - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 6, 2); - if (rv != SECSuccess) - goto loser; - - for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs); - cursor != &ss->ephemeralKeyPairs; - cursor = PR_NEXT_LINK(cursor)) { - sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; - rv = tls13_EncodeKeyShareEntry(ss, keyPair); - if (rv != SECSuccess) - goto loser; + for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs); + cursor != &ss->ephemeralKeyPairs; + cursor = PR_NEXT_LINK(cursor)) { + sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; + rv = tls13_EncodeKeyShareEntry(buf, keyPair); + if (rv != SECSuccess) { + return SECFailure; } - - xtnData->advertised[xtnData->numAdvertised++] = - ssl_tls13_key_share_xtn; + } + rv = sslBuffer_InsertLength(buf, lengthOffset, 2); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; - -loser: - return -1; + *added = PR_TRUE; + return SECSuccess; } static SECStatus @@ -250,7 +204,8 @@ loser: * |xtnData->remoteKeyShares| for future use. The key * share is processed in tls13_HandleServerKeyShare(). */ SECStatus -tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); @@ -281,7 +236,8 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PR } SECStatus -tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; PRUint32 tmp; @@ -331,7 +287,8 @@ tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, * |xtnData->remoteKeyShares| for future use. The key * share is processed in tls13_HandleClientKeyShare(). */ SECStatus -tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; PRUint32 length; @@ -364,16 +321,6 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PR goto loser; } - /* Check that the client only offered one share if this is - * after HRR. */ - if (ss->ssl3.hs.helloRetry) { - if (PR_PREV_LINK(&xtnData->remoteKeyShares) != - PR_NEXT_LINK(&xtnData->remoteKeyShares)) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); - goto loser; - } - } - return SECSuccess; loser: @@ -381,12 +328,10 @@ loser: return SECFailure; } -PRInt32 -tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRUint32 extension_length; - PRUint32 entry_length; SECStatus rv; sslEphemeralKeyPair *keyPair; @@ -397,31 +342,13 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBo keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); - entry_length = tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey); - extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */ - if (maxBytes < extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_ExtAppendHandshakeNumber(ss, entry_length, 2); - if (rv != SECSuccess) - goto loser; - - rv = tls13_EncodeKeyShareEntry(ss, keyPair); - if (rv != SECSuccess) - goto loser; + rv = tls13_EncodeKeyShareEntry(buf, keyPair); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; - -loser: - return -1; + *added = PR_TRUE; + return SECSuccess; } /* Called by clients. @@ -448,113 +375,83 @@ loser: * Presently the only way to get a PSK is by resumption, so this is * really a ticket label and there will be at most one. */ -PRInt32 +SECStatus tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length; - PRInt32 identities_length; - PRInt32 binders_length; NewSessionTicket *session_ticket; + PRTime age; + const static PRUint8 binder[TLS13_MAX_FINISHED_SIZE] = { 0 }; + unsigned int binderLen; + SECStatus rv; /* We only set statelessResume on the client in TLS 1.3 code. */ - if (!ss->statelessResume) - return 0; + if (!ss->statelessResume) { + return SECSuccess; + } + + /* Save where this extension starts so that if we have to add padding, it + * can be inserted before this extension. */ + PORT_Assert(buf->len >= 4); + xtnData->lastXtnOffset = buf->len - 4; PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); - /* The length computations are simplified by the fact that there - * is just one ticket at most. */ + /* Send a single ticket identity. */ session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket; - identities_length = - 2 + /* vector length */ - 2 + session_ticket->ticket.len + /* identity length + ticket len */ - 4; /* obfuscated_ticket_age */ - binders_length = - 2 + /* vector length */ - 1 + tls13_GetHashSizeForHash( - tls13_GetHashForCipherSuite(ss->sec.ci.sid->u.ssl3.cipherSuite)); - extension_length = - 2 + 2 + /* Type + length */ - identities_length + binders_length; - - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - SECStatus rv; - PRTime age; - unsigned int prefixLength; - PRUint8 binder[TLS13_MAX_FINISHED_SIZE]; - unsigned int binderLen; - - /* extension_type */ - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_ExtAppendHandshakeNumber(ss, identities_length - 2, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data, - session_ticket->ticket.len, 2); - if (rv != SECSuccess) - goto loser; + rv = sslBuffer_AppendNumber(buf, 2 + /* identity length */ + session_ticket->ticket.len + /* ticket */ + 4 /* obfuscated_ticket_age */, + 2); + if (rv != SECSuccess) + goto loser; + rv = sslBuffer_AppendVariable(buf, session_ticket->ticket.data, + session_ticket->ticket.len, 2); + if (rv != SECSuccess) + goto loser; - /* Obfuscated age. */ - age = PR_Now() - session_ticket->received_timestamp; - age /= PR_USEC_PER_MSEC; - age += session_ticket->ticket_age_add; - rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4); - if (rv != SECSuccess) - goto loser; + /* Obfuscated age. */ + age = ssl_TimeUsec() - session_ticket->received_timestamp; + age /= PR_USEC_PER_MSEC; + age += session_ticket->ticket_age_add; + rv = sslBuffer_AppendNumber(buf, age, 4); + if (rv != SECSuccess) + goto loser; - /* Now the binders. */ - prefixLength = ss->ssl3.hs.messages.len; - rv = tls13_ComputePskBinder(CONST_CAST(sslSocket, ss), PR_TRUE, - prefixLength, binder, &binderLen, - sizeof(binder)); - if (rv != SECSuccess) - goto loser; - PORT_Assert(binderLen == tls13_GetHashSize(ss)); - rv = ssl3_ExtAppendHandshakeNumber(ss, binders_length - 2, 2); - if (rv != SECSuccess) - goto loser; - rv = ssl3_ExtAppendHandshakeVariable(ss, - binder, binderLen, 1); - if (rv != SECSuccess) - goto loser; + /* Write out the binder list length. */ + binderLen = tls13_GetHashSize(ss); + rv = sslBuffer_AppendNumber(buf, binderLen + 1, 2); + if (rv != SECSuccess) + goto loser; + /* Write zeroes for the binder for the moment. */ + rv = sslBuffer_AppendVariable(buf, binder, binderLen, 1); + if (rv != SECSuccess) + goto loser; - PRINT_BUF(50, (ss, "Sending PreSharedKey value", - session_ticket->ticket.data, - session_ticket->ticket.len)); + PRINT_BUF(50, (ss, "Sending PreSharedKey value", + session_ticket->ticket.data, + session_ticket->ticket.len)); - xtnData->sentSessionTicketInClientHello = PR_TRUE; - xtnData->advertised[xtnData->numAdvertised++] = - ssl_tls13_pre_shared_key_xtn; - } - return extension_length; + xtnData->sentSessionTicketInClientHello = PR_TRUE; + *added = PR_TRUE; + return SECSuccess; loser: xtnData->ticketTimestampVerified = PR_FALSE; - return -1; + return SECFailure; } /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs * that contain session tickets. */ SECStatus -tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { SECItem inner; SECStatus rv; unsigned int numIdentities = 0; unsigned int numBinders = 0; + SECItem *appToken; SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension", SSL_GETPID(), ss->fd)); @@ -564,16 +461,26 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } + /* The application token is set via the cookie extension if this is the + * second ClientHello. Don't set it twice. The cookie extension handler + * sets |helloRetry| and that will have been called already because this + * extension always comes last. */ + if (!ss->ssl3.hs.helloRetry) { + appToken = &xtnData->applicationToken; + } else { + appToken = NULL; + } + /* Parse the identities list. */ - rv = ssl3_ExtConsumeHandshakeVariable(ss, - &inner, 2, &data->data, &data->len); + rv = ssl3_ExtConsumeHandshakeVariable(ss, &inner, 2, + &data->data, &data->len); if (rv != SECSuccess) { return SECFailure; } while (inner.len) { SECItem label; - PRUint32 utmp; + PRUint32 obfuscatedAge; rv = ssl3_ExtConsumeHandshakeVariable(ss, &label, 2, &inner.data, &inner.len); @@ -583,9 +490,8 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData goto alert_loser; } - /* Read and discard session ticket age. Bug 1295163 */ - rv = ssl3_ExtConsumeHandshake(ss, &utmp, 4, - &inner.data, &inner.len); + rv = ssl3_ExtConsumeHandshakeNumber(ss, &obfuscatedAge, 4, + &inner.data, &inner.len); if (rv != SECSuccess) return rv; @@ -593,17 +499,29 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData PRINT_BUF(50, (ss, "Handling PreSharedKey value", label.data, label.len)); rv = ssl3_ProcessSessionTicketCommon( - CONST_CAST(sslSocket, ss), &label); + CONST_CAST(sslSocket, ss), &label, appToken); /* This only happens if we have an internal error, not * a malformed ticket. Bogus tickets just don't resume * and return SECSuccess. */ if (rv != SECSuccess) return SECFailure; + + if (ss->sec.ci.sid) { + /* xtnData->ticketAge contains the baseline we use for + * calculating the ticket age (i.e., our RTT estimate less the + * value of ticket_age_add). + * + * Add that to the obfuscated ticket age to recover the client's + * view of the ticket age plus the estimated RTT. + * + * See ssl3_EncodeSessionTicket() for details. */ + xtnData->ticketAge += obfuscatedAge; + } } ++numIdentities; } - xtnData->pskBinderPrefixLen = ss->ssl3.hs.messages.len - data->len; + xtnData->pskBindersLen = data->len; /* Parse the binders list. */ rv = ssl3_ExtConsumeHandshakeVariable(ss, @@ -635,7 +553,7 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData /* Keep track of negotiated extensions. Note that this does not * mean we are resuming. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn; return SECSuccess; @@ -645,43 +563,27 @@ alert_loser: return SECFailure; } -PRInt32 +SECStatus tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) + sslBuffer *buf, PRBool *added) { - PRInt32 extension_length = - 2 + 2 + 2; /* type + len + index */ SECStatus rv; - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2); - if (rv != SECSuccess) - return -1; - - rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2); - if (rv != SECSuccess) - return -1; - - /* We only process the first session ticket the client sends, - * so the index is always 0. */ - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; + /* We only process the first session ticket the client sends, + * so the index is always 0. */ + rv = sslBuffer_AppendNumber(buf, 0, 2); + if (rv != SECSuccess) { + return SECFailure; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs * that contain session tickets. */ SECStatus -tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { PRUint32 index; @@ -713,7 +615,7 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn; return SECSuccess; } @@ -721,43 +623,20 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData /* * struct { } EarlyDataIndication; */ -PRInt32 +SECStatus tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) + sslBuffer *buf, PRBool *added) { - SECStatus rv; - PRInt32 extension_length; - - if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid)) - return 0; - - /* type + length */ - extension_length = 2 + 2; - - if (maxBytes < (PRUint32)extension_length) { - PORT_Assert(0); - return 0; - } - - if (append) { - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2); - if (rv != SECSuccess) - return -1; - - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - - xtnData->advertised[xtnData->numAdvertised++] = - ssl_tls13_early_data_xtn; + if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid)) { + return SECSuccess; } - return extension_length; + *added = PR_TRUE; + return SECSuccess; } SECStatus -tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", @@ -779,44 +658,14 @@ tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, P return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn; return SECSuccess; } -/* This is only registered if we are sending it. */ -PRInt32 -tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes) -{ - SSL_TRC(3, ("%d: TLS13[%d]: send early_data extension", - SSL_GETPID(), ss->fd)); - - PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted); - if (maxBytes < 4) { - PORT_Assert(0); - return 0; - } - - if (append) { - SECStatus rv; - - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2); - if (rv != SECSuccess) - return -1; - - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; - } - - return 4; -} - /* This will only be called if we also offered the extension. */ SECStatus -tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", @@ -834,19 +683,19 @@ tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, P } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn; return SECSuccess; } SECStatus -tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - SECItem *data) +tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { PRUint32 utmp; SECStatus rv; - SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension", + SSL_TRC(3, ("%d: TLS13[%d]: handle ticket early_data extension", SSL_GETPID(), ss->fd)); /* The server must not send this extension when negotiating < TLS 1.3. */ @@ -873,59 +722,71 @@ tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData * /* * struct { + * select (Handshake.msg_type) { + * case client_hello: * ProtocolVersion versions<2..254>; + * case server_hello: + * ProtocolVersion version; + * }; * } SupportedVersions; */ -PRInt32 -tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes) +SECStatus +tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extensions_len; PRUint16 version; + unsigned int lengthOffset; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { - return 0; + return SECSuccess; } - SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension", + SSL_TRC(3, ("%d: TLS13[%d]: client send supported_versions extension", SSL_GETPID(), ss->fd)); - /* Extension type, extension len fiels, vector len field, - * length of the values. */ - extensions_len = 2 + 2 + 1 + - 2 * (ss->vrange.max - ss->vrange.min + 1); + rv = sslBuffer_Skip(buf, 1, &lengthOffset); + if (rv != SECSuccess) { + return SECFailure; + } - if (maxBytes < (PRUint32)extensions_len) { - PORT_Assert(0); - return 0; + for (version = ss->vrange.max; version >= ss->vrange.min; --version) { + rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2); + if (rv != SECSuccess) { + return SECFailure; + } } - if (append) { - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2); - if (rv != SECSuccess) - return -1; + rv = sslBuffer_InsertLength(buf, lengthOffset, 1); + if (rv != SECSuccess) { + return SECFailure; + } - rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 4, 2); - if (rv != SECSuccess) - return -1; + *added = PR_TRUE; + return SECSuccess; +} - rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 5, 1); - if (rv != SECSuccess) - return -1; +SECStatus +tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) +{ + SECStatus rv; - for (version = ss->vrange.max; version >= ss->vrange.min; --version) { - rv = ssl3_ExtAppendHandshakeNumber( - ss, tls13_EncodeDraftVersion(version), 2); - if (rv != SECSuccess) - return -1; - } + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension", + SSL_GETPID(), ss->fd)); - xtnData->advertised[xtnData->numAdvertised++] = - ssl_tls13_supported_versions_xtn; + rv = sslBuffer_AppendNumber( + buf, tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2); + if (rv != SECSuccess) { + return SECFailure; } - return extensions_len; + *added = PR_TRUE; + return SECSuccess; } /* @@ -934,7 +795,8 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD * } Cookie; */ SECStatus -tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; @@ -960,41 +822,57 @@ tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUi return SECSuccess; } -PRInt32 -tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +SECStatus +tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRInt32 extension_len; + SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || !ss->ssl3.hs.cookie.len) { - return 0; + return SECSuccess; } SSL_TRC(3, ("%d: TLS13[%d]: send cookie extension", SSL_GETPID(), ss->fd)); + rv = sslBuffer_AppendVariable(buf, ss->ssl3.hs.cookie.data, + ss->ssl3.hs.cookie.len, 2); + if (rv != SECSuccess) { + return SECFailure; + } - /* Extension type, length, cookie length, cookie value. */ - extension_len = 2 + 2 + 2 + ss->ssl3.hs.cookie.len; + *added = PR_TRUE; + return SECSuccess; +} - if (maxBytes < (PRUint32)extension_len) { - PORT_Assert(0); - return 0; - } +SECStatus +tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) +{ + SECStatus rv; - if (append) { - SECStatus rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_cookie_xtn, 2); - if (rv != SECSuccess) - return -1; + SSL_TRC(3, ("%d: TLS13[%d]: handle cookie extension", + SSL_GETPID(), ss->fd)); - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2); - if (rv != SECSuccess) - return -1; + rv = ssl3_ExtConsumeHandshakeVariable(ss, &xtnData->cookie, 2, + &data->data, &data->len); + if (rv != SECSuccess) { + return SECFailure; + } - rv = ssl3_ExtAppendHandshakeVariable(ss, ss->ssl3.hs.cookie.data, - ss->ssl3.hs.cookie.len, 2); - if (rv != SECSuccess) - return -1; + if (xtnData->cookie.len == 0) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); + return SECFailure; } - return extension_len; + + if (data->len) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); + return SECFailure; + } + + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_cookie_xtn; + + return SECSuccess; } /* @@ -1004,54 +882,33 @@ tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRB * PskKeyExchangeMode ke_modes<1..255>; * } PskKeyExchangeModes; */ -PRInt32 -tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes) +SECStatus +tls13_ClientSendPskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { static const PRUint8 ke_modes[] = { tls13_psk_dh_ke }; - static const unsigned long ke_modes_len = sizeof(ke_modes); - PRInt32 extension_len; + SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || ss->opt.noCache) { - return 0; + return SECSuccess; } - extension_len = - 2 + 2 + /* Type + length */ - 1 + ke_modes_len; /* key exchange modes vector */ - SSL_TRC(3, ("%d: TLS13[%d]: send psk key exchange modes extension", SSL_GETPID(), ss->fd)); - if (maxBytes < (PRUint32)extension_len) { - PORT_Assert(0); - return 0; + rv = sslBuffer_AppendVariable(buf, ke_modes, sizeof(ke_modes), 1); + if (rv != SECSuccess) { + return SECFailure; } - if (append) { - SECStatus rv = ssl3_ExtAppendHandshakeNumber( - ss, ssl_tls13_psk_key_exchange_modes_xtn, 2); - if (rv != SECSuccess) - return -1; - - rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2); - if (rv != SECSuccess) - return -1; - - rv = ssl3_ExtAppendHandshakeVariable( - ss, ke_modes, ke_modes_len, 1); - if (rv != SECSuccess) - return -1; - } - return extension_len; + *added = PR_TRUE; + return SECSuccess; } SECStatus -tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data) +tls13_ServerHandlePskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, + SECItem *data) { SECStatus rv; @@ -1076,112 +933,126 @@ tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss, } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + xtnData->negotiated[xtnData->numNegotiated++] = + ssl_tls13_psk_key_exchange_modes_xtn; return SECSuccess; } -PRInt32 -tls13_SendShortHeaderXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes) +SECStatus +tls13_SendCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - PRUint32 extension_len = 2 + 2; /* Type + length (0). */ + unsigned int calen; + const SECItem *name; + unsigned int nnames; + SECStatus rv; - if (!ss->opt.enableShortHeaders) { - return 0; - } + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - /* Presently this is incompatible with 0-RTT. We will fix if - * it becomes more than an experiment. */ - if (ss->opt.enable0RttData) { - return 0; + rv = ssl_GetCertificateRequestCAs(ss, &calen, &name, &nnames); + if (rv != SECSuccess) { + return SECFailure; } - if (IS_DTLS(ss)) { - return 0; + if (!calen) { + return SECSuccess; } - /* Don't send this if TLS 1.3 isn't at least possible. */ - if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { - /* This should only happen on the client. */ - PORT_Assert(!ss->sec.isServer); - return 0; + rv = sslBuffer_AppendNumber(buf, calen, 2); + if (rv != SECSuccess) { + return SECFailure; } - SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension", - SSL_GETPID(), ss->fd)); - - if (maxBytes < extension_len) { - PORT_Assert(0); - return 0; + while (nnames) { + rv = sslBuffer_AppendVariable(buf, name->data, name->len, 2); + if (rv != SECSuccess) { + return SECFailure; + } + ++name; + --nnames; } - if (append) { - SECStatus rv; + *added = PR_TRUE; + return SECSuccess; +} - rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_short_header_xtn, 2); - if (rv != SECSuccess) - return -1; +SECStatus +tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data) +{ + SECStatus rv; + PLArenaPool *arena; - rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); - if (rv != SECSuccess) - return -1; + if (!data->len) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); + PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST); + return SECFailure; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } - xtnData->advertised[xtnData->numAdvertised++] = - ssl_tls13_short_header_xtn; + xtnData->certReqAuthorities.arena = arena; + rv = ssl3_ParseCertificateRequestCAs((sslSocket *)ss, + &data->data, &data->len, + &xtnData->certReqAuthorities); + if (rv != SECSuccess) { + goto loser; } + if (data->len) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); + PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST); + goto loser; + } + return SECSuccess; - return extension_len; +loser: + PORT_FreeArena(arena, PR_FALSE); + xtnData->certReqAuthorities.arena = NULL; + return SECFailure; } SECStatus -tls13_HandleShortHeaderXtn( - const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - SECItem *data) +tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) { - SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension", - SSL_GETPID(), ss->fd)); + SECStatus rv; - /* The client might have asked for this, but we didn't negotiate TLS 1.3. */ - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; - } + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - /* Presently this is incompatible with 0-RTT. We will fix if - * it becomes more than an experiment. */ - if (ss->opt.enable0RttData) { + if (!xtnData->selectedGroup) { return SECSuccess; } - if (IS_DTLS(ss)) { - PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); - return SECFailure; - } - - if (data->len) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); + rv = sslBuffer_AppendNumber(buf, xtnData->selectedGroup->name, 2); + if (rv != SECSuccess) { return SECFailure; } - if (!ss->opt.enableShortHeaders) { - /* Ignore. */ - return SECSuccess; - } + *added = PR_TRUE; + return SECSuccess; +} - /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ex_type; +SECStatus +tls13_ServerSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added) +{ + SECStatus rv; - if (ss->sec.isServer) { - SECStatus rv; + PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + PORT_Assert(xtnData->cookie.len > 0); - rv = ssl3_RegisterExtensionSender(ss, xtnData, - ssl_tls13_short_header_xtn, - tls13_SendShortHeaderXtn); - if (rv != SECSuccess) { - return SECFailure; - } + rv = sslBuffer_AppendVariable(buf, + xtnData->cookie.data, xtnData->cookie.len, 2); + if (rv != SECSuccess) { + return SECFailure; } + *added = PR_TRUE; return SECSuccess; } diff --git a/security/nss/lib/ssl/tls13exthandle.h b/security/nss/lib/ssl/tls13exthandle.h index b798c6b55..edce94d83 100644 --- a/security/nss/lib/ssl/tls13exthandle.h +++ b/security/nss/lib/ssl/tls13exthandle.h @@ -9,66 +9,80 @@ #ifndef __tls13exthandle_h_ #define __tls13exthandle_h_ -PRInt32 tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); -PRInt32 tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus tls13_ServerSendStatusRequestXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ClientSendKeyShareXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 tls13_ServerSendKeyShareXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -PRInt32 tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, - PRUint32 maxBytes); -SECStatus tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus tls13_ServerSendKeyShareXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRUint16 ex_type, +SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -PRInt32 tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -SECStatus tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +SECStatus tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ClientSendEarlyDataXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -SECStatus tls13_ClientHandleTicketEarlyDataInfoXtn( - const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - SECItem *data); -PRInt32 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, +SECStatus tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, + TLSExtensionData *xtnData, SECItem *data); -PRInt32 tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, - PRUint32 maxBytes); -PRInt32 tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss, +SECStatus tls13_ClientSendHrrCookieXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ClientSendPskModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ServerHandlePskModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus tls13_SendCertAuthoritiesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *append); +SECStatus tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); -SECStatus tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRUint16 ex_type, SECItem *data); -PRInt32 tls13_SendShortHeaderXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - PRBool append, PRUint32 maxBytes); -SECStatus tls13_HandleShortHeaderXtn( - const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - SECItem *data); + SECItem *data); +SECStatus tls13_ServerHandleCookieXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + SECItem *data); +SECStatus tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); +SECStatus tls13_ServerSendHrrCookieXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + sslBuffer *buf, PRBool *added); #endif diff --git a/security/nss/lib/ssl/tls13hashstate.c b/security/nss/lib/ssl/tls13hashstate.c new file mode 100644 index 000000000..e3232f524 --- /dev/null +++ b/security/nss/lib/ssl/tls13hashstate.c @@ -0,0 +1,181 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "pk11func.h" +#include "ssl.h" +#include "sslt.h" +#include "sslimpl.h" +#include "selfencrypt.h" +#include "tls13con.h" +#include "tls13err.h" +#include "tls13hashstate.h" + +/* + * The cookie is structured as a self-encrypted structure with the + * inner value being. + * + * struct { + * uint8 indicator = 0xff; // To disambiguate from tickets. + * uint16 cipherSuite; // Selected cipher suite. + * uint16 keyShare; // Requested key share group (0=none) + * opaque applicationToken<0..65535>; // Application token + * opaque ch_hash[rest_of_buffer]; // H(ClientHello) + * } CookieInner; + */ +SECStatus +tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup, + const PRUint8 *appToken, unsigned int appTokenLen, + PRUint8 *buf, unsigned int *len, unsigned int maxlen) +{ + SECStatus rv; + SSL3Hashes hashes; + PRUint8 cookie[1024]; + sslBuffer cookieBuf = SSL_BUFFER(cookie); + static const PRUint8 indicator = 0xff; + + /* Encode header. */ + rv = sslBuffer_Append(&cookieBuf, &indicator, 1); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(&cookieBuf, ss->ssl3.hs.cipher_suite, 2); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendNumber(&cookieBuf, + selectedGroup ? selectedGroup->name : 0, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Application token. */ + rv = sslBuffer_AppendVariable(&cookieBuf, appToken, appTokenLen, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Compute and encode hashes. */ + rv = tls13_ComputeHandshakeHashes(ss, &hashes); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_Append(&cookieBuf, hashes.u.raw, hashes.len); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Encrypt right into the buffer. */ + rv = ssl_SelfEncryptProtect(ss, cookieBuf.buf, cookieBuf.len, + buf, len, maxlen); + if (rv != SECSuccess) { + return SECFailure; + } + + return SECSuccess; +} + +/* Recover the hash state from the cookie. */ +SECStatus +tls13_RecoverHashState(sslSocket *ss, + unsigned char *cookie, unsigned int cookieLen, + ssl3CipherSuite *previousCipherSuite, + const sslNamedGroupDef **previousGroup) +{ + SECStatus rv; + unsigned char plaintext[1024]; + SECItem ptItem = { siBuffer, plaintext, 0 }; + sslBuffer messageBuf = SSL_BUFFER_EMPTY; + PRUint32 sentinel; + PRUint32 cipherSuite; + PRUint32 group; + const sslNamedGroupDef *selectedGroup; + PRUint32 appTokenLen; + PRUint8 *appToken; + + rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen, + ptItem.data, &ptItem.len, sizeof(plaintext)); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Should start with 0xff. */ + rv = ssl3_ConsumeNumberFromItem(&ptItem, &sentinel, 1); + if ((rv != SECSuccess) || (sentinel != 0xff)) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + return SECFailure; + } + /* The cipher suite should be the same or there are some shenanigans. */ + rv = ssl3_ConsumeNumberFromItem(&ptItem, &cipherSuite, 2); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + return SECFailure; + } + + /* The named group, if any. */ + rv = ssl3_ConsumeNumberFromItem(&ptItem, &group, 2); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + return SECFailure; + } + selectedGroup = ssl_LookupNamedGroup(group); + + /* Application token. */ + PORT_Assert(ss->xtnData.applicationToken.len == 0); + rv = ssl3_ConsumeNumberFromItem(&ptItem, &appTokenLen, 2); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + return SECFailure; + } + if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken, + appTokenLen) == NULL) { + FATAL_ERROR(ss, PORT_GetError(), internal_error); + return SECFailure; + } + ss->xtnData.applicationToken.len = appTokenLen; + rv = ssl3_ConsumeFromItem(&ptItem, &appToken, appTokenLen); + if (rv != SECSuccess) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + return SECFailure; + } + PORT_Memcpy(ss->xtnData.applicationToken.data, appToken, appTokenLen); + + /* The remainder is the hash. */ + if (ptItem.len != tls13_GetHashSize(ss)) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + return SECFailure; + } + + /* Now reinject the message. */ + SSL_ASSERT_HASHES_EMPTY(ss); + rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0, + ptItem.data, ptItem.len); + if (rv != SECSuccess) { + return SECFailure; + } + + /* And finally reinject the HRR. */ + rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite, + selectedGroup, + cookie, cookieLen, + &messageBuf); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0, + SSL_BUFFER_BASE(&messageBuf), + SSL_BUFFER_LEN(&messageBuf)); + sslBuffer_Clear(&messageBuf); + if (rv != SECSuccess) { + return SECFailure; + } + + *previousCipherSuite = cipherSuite; + *previousGroup = selectedGroup; + return SECSuccess; +} diff --git a/security/nss/lib/ssl/tls13hashstate.h b/security/nss/lib/ssl/tls13hashstate.h new file mode 100644 index 000000000..e9a4aa84f --- /dev/null +++ b/security/nss/lib/ssl/tls13hashstate.h @@ -0,0 +1,25 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __tls13hashstate_h_ +#define __tls13hashstate_h_ + +#include "ssl.h" +#include "sslt.h" +#include "sslimpl.h" + +SECStatus tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup, + const PRUint8 *appToken, unsigned int appTokenLen, + PRUint8 *buf, unsigned int *len, unsigned int maxlen); +SECStatus tls13_GetHrrCookieLength(sslSocket *ss, unsigned int *length); +SECStatus tls13_RecoverHashState(sslSocket *ss, + unsigned char *cookie, + unsigned int cookieLen, + ssl3CipherSuite *previousCipherSuite, + const sslNamedGroupDef **previousGroup); +#endif diff --git a/security/nss/lib/ssl/tls13hkdf.c b/security/nss/lib/ssl/tls13hkdf.c index 7e69bb882..8fa3375c6 100644 --- a/security/nss/lib/ssl/tls13hkdf.c +++ b/security/nss/lib/ssl/tls13hkdf.c @@ -134,10 +134,10 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, * Label, plus HandshakeHash. If it's ever to small, the code will abort. */ PRUint8 info[256]; - PRUint8 *ptr = info; - unsigned int infoLen; + sslBuffer infoBuf = SSL_BUFFER(info); PK11SymKey *derived; - const char *kLabelPrefix = "TLS 1.3, "; + SECStatus rv; + const char *kLabelPrefix = "tls13 "; const unsigned int kLabelPrefixLen = strlen(kLabelPrefix); if (handshakeHash) { @@ -170,29 +170,31 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, * - HkdfLabel.label is "TLS 1.3, " + Label * */ - infoLen = 2 + 1 + kLabelPrefixLen + labelLen + 1 + handshakeHashLen; - if (infoLen > sizeof(info)) { - PORT_Assert(0); - goto abort; + rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2); + if (rv != SECSuccess) { + return SECFailure; } - - ptr = ssl_EncodeUintX(keySize, 2, ptr); - ptr = ssl_EncodeUintX(labelLen + kLabelPrefixLen, 1, ptr); - PORT_Memcpy(ptr, kLabelPrefix, kLabelPrefixLen); - ptr += kLabelPrefixLen; - PORT_Memcpy(ptr, label, labelLen); - ptr += labelLen; - ptr = ssl_EncodeUintX(handshakeHashLen, 1, ptr); - if (handshakeHash) { - PORT_Memcpy(ptr, handshakeHash, handshakeHashLen); - ptr += handshakeHashLen; + rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_Append(&infoBuf, label, labelLen); + if (rv != SECSuccess) { + return SECFailure; + } + rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1); + if (rv != SECSuccess) { + return SECFailure; } - PORT_Assert((ptr - info) == infoLen); params.bExtract = CK_FALSE; params.bExpand = CK_TRUE; - params.pInfo = info; - params.ulInfoLen = infoLen; + params.pInfo = SSL_BUFFER_BASE(&infoBuf); + params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf); paramsi.data = (unsigned char *)¶ms; paramsi.len = sizeof(params); @@ -211,20 +213,17 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, char labelStr[100]; PORT_Memcpy(labelStr, label, labelLen); labelStr[labelLen] = 0; - SSL_TRC(50, ("HKDF Expand: label=[TLS 1.3, ] + '%s',requested length=%d", + SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d", labelStr, keySize)); } PRINT_KEY(50, (NULL, "PRK", prk)); PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen)); - PRINT_BUF(50, (NULL, "Info", info, infoLen)); + PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf), + SSL_BUFFER_LEN(&infoBuf))); PRINT_KEY(50, (NULL, "Derived key", derived)); #endif return SECSuccess; - -abort: - PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - return SECFailure; } SECStatus diff --git a/security/nss/lib/ssl/tls13replay.c b/security/nss/lib/ssl/tls13replay.c new file mode 100644 index 000000000..b090f9bca --- /dev/null +++ b/security/nss/lib/ssl/tls13replay.c @@ -0,0 +1,276 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Anti-replay measures for TLS 1.3. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nss.h" /* for NSS_RegisterShutdown */ +#include "nssilock.h" /* for PZMonitor */ +#include "pk11pub.h" +#include "prinit.h" /* for PR_CallOnce */ +#include "prmon.h" +#include "prtime.h" +#include "secerr.h" +#include "ssl.h" +#include "sslbloom.h" +#include "sslimpl.h" +#include "tls13hkdf.h" + +static struct { + /* Used to ensure that we only initialize the cleanup function once. */ + PRCallOnceType init; + /* Used to serialize access to the filters. */ + PZMonitor *lock; + /* The filters, use of which alternates. */ + sslBloomFilter filters[2]; + /* Which of the two filters is active (0 or 1). */ + PRUint8 current; + /* The time that we will next update. */ + PRTime nextUpdate; + /* The width of the window; i.e., the period of updates. */ + PRTime window; + /* This key ensures that the bloom filter index is unpredictable. */ + PK11SymKey *key; +} ssl_anti_replay; + +/* Clear the current state and free any resources we allocated. The signature + * here is odd to allow this to be called during shutdown. */ +static SECStatus +tls13_AntiReplayReset(void *appData, void *nssData) +{ + if (ssl_anti_replay.key) { + PK11_FreeSymKey(ssl_anti_replay.key); + ssl_anti_replay.key = NULL; + } + if (ssl_anti_replay.lock) { + PZ_DestroyMonitor(ssl_anti_replay.lock); + ssl_anti_replay.lock = NULL; + } + sslBloom_Destroy(&ssl_anti_replay.filters[0]); + sslBloom_Destroy(&ssl_anti_replay.filters[1]); + return SECSuccess; +} + +static PRStatus +tls13_AntiReplayInit(void) +{ + SECStatus rv = NSS_RegisterShutdown(tls13_AntiReplayReset, NULL); + if (rv != SECSuccess) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static SECStatus +tls13_AntiReplayKeyGen() +{ + PRUint8 buf[32]; + SECItem keyItem = { siBuffer, buf, sizeof(buf) }; + PK11SlotInfo *slot; + SECStatus rv; + + slot = PK11_GetInternalSlot(); + if (!slot) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + rv = PK11_GenerateRandomOnSlot(slot, buf, sizeof(buf)); + if (rv != SECSuccess) { + goto loser; + } + + ssl_anti_replay.key = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256, + PK11_OriginUnwrap, CKA_DERIVE, + &keyItem, NULL); + if (!ssl_anti_replay.key) { + goto loser; + } + + PK11_FreeSlot(slot); + return SECSuccess; + +loser: + PK11_FreeSlot(slot); + return SECFailure; +} + +/* Set a limit on the combination of number of hashes and bits in each hash. */ +#define SSL_MAX_BLOOM_FILTER_SIZE 64 + +/* + * The structures created by this function can be called concurrently on + * multiple threads if the server is multi-threaded. A monitor is used to + * ensure that only one thread can access the structures that change over time, + * but no such guarantee is provided for configuration data. + * + * Functions that read from static configuration data depend on there being a + * memory barrier between the setup and use of this function. + */ +SECStatus +SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits) +{ + SECStatus rv; + + if (k == 0 || bits == 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if ((k * (bits + 7) / 8) > SSL_MAX_BLOOM_FILTER_SIZE) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (PR_SUCCESS != PR_CallOnce(&ssl_anti_replay.init, + tls13_AntiReplayInit)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + (void)tls13_AntiReplayReset(NULL, NULL); + + ssl_anti_replay.lock = PZ_NewMonitor(nssILockSSL); + if (!ssl_anti_replay.lock) { + goto loser; /* Code already set. */ + } + + rv = tls13_AntiReplayKeyGen(); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + + rv = sslBloom_Init(&ssl_anti_replay.filters[0], k, bits); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + rv = sslBloom_Init(&ssl_anti_replay.filters[1], k, bits); + if (rv != SECSuccess) { + goto loser; /* Code already set. */ + } + /* When starting out, ensure that 0-RTT is not accepted until the window is + * updated. A ClientHello might have been accepted prior to a restart. */ + sslBloom_Fill(&ssl_anti_replay.filters[1]); + + ssl_anti_replay.current = 0; + ssl_anti_replay.nextUpdate = ssl_TimeUsec() + window; + ssl_anti_replay.window = window; + return SECSuccess; + +loser: + (void)tls13_AntiReplayReset(NULL, NULL); + return SECFailure; +} + +/* This is exposed to tests. Though it could, this doesn't take the lock on the + * basis that those tests use thread confinement. */ +void +tls13_AntiReplayRollover(PRTime now) +{ + ssl_anti_replay.current ^= 1; + ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window; + sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current); +} + +static void +tls13_AntiReplayUpdate() +{ + PRTime now; + + PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ssl_anti_replay.lock); + + now = ssl_TimeUsec(); + if (now < ssl_anti_replay.nextUpdate) { + return; + } + + tls13_AntiReplayRollover(now); +} + +PRBool +tls13_InWindow(const sslSocket *ss, const sslSessionID *sid) +{ + PRInt32 timeDelta; + + /* Calculate the difference between the client's view of the age of the + * ticket (in |ss->xtnData.ticketAge|) and the server's view, which we now + * calculate. The result should be close to zero. timeDelta is signed to + * make the comparisons below easier. */ + timeDelta = ss->xtnData.ticketAge - + ((ssl_TimeUsec() - sid->creationTime) / PR_USEC_PER_MSEC); + + /* Only allow the time delta to be at most half of our window. This is + * symmetrical, though it doesn't need to be; this assumes that clock errors + * on server and client will tend to cancel each other out. + * + * There are two anti-replay filters that roll over each window. In the + * worst case, immediately after a rollover of the filters, we only have a + * single window worth of recorded 0-RTT attempts. Thus, the period in + * which we can accept 0-RTT is at most one window wide. This uses PR_ABS() + * and half the window so that the first attempt can be up to half a window + * early and then replays will be caught until the attempts are half a + * window late. + * + * For example, a 0-RTT attempt arrives early, but near the end of window 1. + * The attempt is then recorded in window 1. Rollover to window 2 could + * occur immediately afterwards. Window 1 is still checked for new 0-RTT + * attempts for the remainder of window 2. Therefore, attempts to replay + * are detected because the value is recorded in window 1. When rollover + * occurs again, window 1 is erased and window 3 instated. If we allowed an + * attempt to be late by more than half a window, then this check would not + * prevent the same 0-RTT attempt from being accepted during window 1 and + * later window 3. + */ + return PR_ABS(timeDelta) < (ssl_anti_replay.window / 2); +} + +/* Checks for a duplicate in the two filters we have. Performs maintenance on + * the filters as a side-effect. This only detects a probable replay, it's + * possible that this will return true when the 0-RTT attempt is not genuinely a + * replay. In that case, we reject 0-RTT unnecessarily, but that's OK because + * no client expects 0-RTT to work every time. */ +PRBool +tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid) +{ + PRBool replay; + unsigned int size; + PRUint8 index; + SECStatus rv; + static const char *label = "tls13 anti-replay"; + PRUint8 buf[SSL_MAX_BLOOM_FILTER_SIZE]; + + /* If SSL_SetupAntiReplay hasn't been called, then treat all attempts at + * 0-RTT as a replay. */ + if (!ssl_anti_replay.init.initialized) { + return PR_TRUE; + } + + if (!tls13_InWindow(ss, sid)) { + return PR_TRUE; + } + + size = ssl_anti_replay.filters[0].k * + (ssl_anti_replay.filters[0].bits + 7) / 8; + PORT_Assert(size <= SSL_MAX_BLOOM_FILTER_SIZE); + rv = tls13_HkdfExpandLabelRaw(ssl_anti_replay.key, ssl_hash_sha256, + ss->xtnData.pskBinder.data, + ss->xtnData.pskBinder.len, + label, strlen(label), + buf, size); + if (rv != SECSuccess) { + return PR_TRUE; + } + + PZ_EnterMonitor(ssl_anti_replay.lock); + tls13_AntiReplayUpdate(); + + index = ssl_anti_replay.current; + replay = sslBloom_Add(&ssl_anti_replay.filters[index], buf); + if (!replay) { + replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1], + buf); + } + + PZ_ExitMonitor(ssl_anti_replay.lock); + return replay; +} |