diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-04-25 21:33:33 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-04-25 21:33:33 +0200 |
commit | fba28f19754f62b5227650143d5441fc86d4c7d7 (patch) | |
tree | 26629d73f83543ff92a060fd7b310bb748b13173 /security/nss/lib/ssl | |
parent | b4154e043bfc0d2f301d88304efc896989d650bf (diff) | |
download | UXP-fba28f19754f62b5227650143d5441fc86d4c7d7.tar UXP-fba28f19754f62b5227650143d5441fc86d4c7d7.tar.gz UXP-fba28f19754f62b5227650143d5441fc86d4c7d7.tar.lz UXP-fba28f19754f62b5227650143d5441fc86d4c7d7.tar.xz UXP-fba28f19754f62b5227650143d5441fc86d4c7d7.zip |
Revert "Update NSS to 3.35-RTM"
This reverts commit f1a0f0a56fdd0fc39f255174ce08c06b91c66c94.
Diffstat (limited to 'security/nss/lib/ssl')
48 files changed, 6309 insertions, 9107 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index c95fe661a..b73fb6bd0 100644 --- a/security/nss/lib/ssl/SSLerrs.h +++ b/security/nss/lib/ssl/SSLerrs.h @@ -473,7 +473,8 @@ 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.") -UNUSED_ERROR(149) +ER3(SSL_ERROR_END_OF_EARLY_DATA_ALERT, (SSL_ERROR_BASE + 149), + "SSL received an unexpected end of early data alert.") ER3(SSL_ERROR_MISSING_ALPN_EXTENSION, (SSL_ERROR_BASE + 150), "SSL didn't receive an expected ALPN extension.") @@ -510,33 +511,3 @@ 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 2765c8342..88c7c084a 100644 --- a/security/nss/lib/ssl/authcert.c +++ b/security/nss/lib/ssl/authcert.c @@ -17,7 +17,6 @@ #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 @@ -64,7 +63,7 @@ NSS_GetClientAuthData(void *arg, if (!cert) continue; /* Only check unexpired certs */ - if (CERT_CheckCertValidTimes(cert, ssl_TimeUsec(), PR_TRUE) != + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != secCertTimeValid) { CERT_DestroyCertificate(cert); continue; diff --git a/security/nss/lib/ssl/config.mk b/security/nss/lib/ssl/config.mk index d13613f78..c8b053cab 100644 --- a/security/nss/lib/ssl/config.mk +++ b/security/nss/lib/ssl/config.mk @@ -57,6 +57,11 @@ 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 deleted file mode 100644 index aba0f62ab..000000000 --- a/security/nss/lib/ssl/dtls13con.c +++ /dev/null @@ -1,457 +0,0 @@ -/* -*- 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 deleted file mode 100644 index bf14d3bd2..000000000 --- a/security/nss/lib/ssl/dtls13con.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- 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 2f335f924..fbd1779db 100644 --- a/security/nss/lib/ssl/dtlscon.c +++ b/security/nss/lib/ssl/dtlscon.c @@ -10,17 +10,16 @@ #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[] = { @@ -31,9 +30,6 @@ 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[] = { @@ -123,9 +119,9 @@ static DTLSQueuedMessage * dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type, const unsigned char *data, PRUint32 len) { - DTLSQueuedMessage *msg; + DTLSQueuedMessage *msg = NULL; - msg = PORT_ZNew(DTLSQueuedMessage); + msg = PORT_ZAlloc(sizeof(DTLSQueuedMessage)); if (!msg) return NULL; @@ -141,7 +137,7 @@ dtls_AllocQueuedMessage(ssl3CipherSpec *cwSpec, SSL3ContentType type, msg->type = type; /* Safe if we are < 1.3, since the refct is * already very high. */ - ssl_CipherSpecAddRef(cwSpec); + tls13_CipherSpecAddRef(cwSpec); return msg; } @@ -159,7 +155,7 @@ dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg) /* Safe if we are < 1.3, since the refct is * already very high. */ - ssl_CipherSpecRelease(msg->cwSpec); + tls13_CipherSpecRelease(msg->cwSpec); PORT_ZFree(msg->data, msg->len); PORT_Free(msg); } @@ -188,38 +184,37 @@ 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 (timer->cb == dtls_RetransmitTimerExpiredCb) { + if (ss->ssl3.hs.rtTimerCb == 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() - timer->started) > - (timer->timeout / 4)) { + if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > + (ss->ssl3.hs.rtTimeoutMs / 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, ss->ssl3.hs.rtTimer); + dtls_CancelTimer(ss); 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() - timer->started, - timer->timeout / 4)); + PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted, + ss->ssl3.hs.rtTimeoutMs / 4)); } - } else if (timer->cb == dtls_FinishedTimerCb) { + } else if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb) { SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected in holddown", SSL_GETPID(), ss->fd)); /* Retransmit the messages and re-arm the timer @@ -227,14 +222,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, ss->ssl3.hs.rtTimer); + dtls_CancelTimer(ss); rv = dtls_TransmitMessageFlight(ss); if (rv == SECSuccess) { rv = dtls_StartHolddownTimer(ss); } } else { - PORT_Assert(timer->cb == NULL); + PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); /* ... and ignore it. */ } return rv; @@ -243,8 +238,19 @@ 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); } @@ -267,8 +273,7 @@ dtls_HandleHandshakeMessage(sslSocket *ss, PRUint8 *data, PRBool last) #define OFFSET_MASK(o) (1 << (o % 8)) SECStatus -dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, - sslBuffer *origBuf) +dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) { /* XXX OK for now. * This doesn't work properly with asynchronous certificate validation. @@ -278,9 +283,6 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, */ 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)); @@ -296,7 +298,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, if (buf.len < 12) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - goto loser; + break; } /* Parse the header */ @@ -321,28 +323,14 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, if (buf.len < fragment_length) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - goto loser; + break; } /* Sanity check the packet contents */ if ((fragment_length + fragment_offset) > message_length) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - 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; + break; } /* There are three ways we could not be ready for this packet. @@ -358,20 +346,20 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, (fragment_offset == 0) && (fragment_length == message_length)) { /* Complete next message. Process immediately */ - ss->ssl3.hs.msg_type = (SSLHandshakeType)type; + ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; ss->ssl3.hs.msg_len = message_length; rv = dtls_HandleHandshakeMessage(ss, buf.buf, buf.len == fragment_length); if (rv == SECFailure) { - goto loser; + break; /* Discard the remainder of the record. */ } } 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); - goto loser; + break; } else if (message_seq > ss->ssl3.hs.recvMessageSeq) { /* Case 2 * @@ -381,12 +369,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, * * 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 @@ -397,18 +380,18 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length); if (rv != SECSuccess) - goto loser; + break; /* Make room for the fragment map */ rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments, map_length); if (rv != SECSuccess) - goto loser; + break; /* 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 = (SSLHandshakeType)type; + ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; ss->ssl3.hs.msg_len = message_length; } @@ -420,14 +403,14 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, ss->ssl3.hs.recvdHighWater = -1; PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); rv = SECFailure; - goto loser; + break; } - /* 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); - } + /* 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); /* This logic is a bit tricky. We have two values for * reassembly state: @@ -443,11 +426,12 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, if (fragment_offset <= (unsigned int)ss->ssl3.hs.recvdHighWater) { /* Either this is the adjacent fragment or an overlapping * fragment */ - if (end > ss->ssl3.hs.recvdHighWater) { - ss->ssl3.hs.recvdHighWater = end; - } + ss->ssl3.hs.recvdHighWater = fragment_offset + + fragment_length; } else { - for (offset = fragment_offset; offset < end; offset++) { + for (offset = fragment_offset; + offset < fragment_offset + fragment_length; + offset++) { ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |= OFFSET_MASK(offset); } @@ -473,7 +457,7 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, buf.len == fragment_length); if (rv == SECFailure) { - goto loser; + break; /* Discard the rest of the record. */ } } } @@ -483,26 +467,6 @@ dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch, sslSequenceNumber seqNum, 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 @@ -596,8 +560,6 @@ 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); } } @@ -614,7 +576,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)) { @@ -627,239 +589,175 @@ dtls_RetransmitTimerExpiredCb(sslSocket *ss) rv = dtls_TransmitMessageFlight(ss); if (rv == SECSuccess) { /* Re-arm the timer */ - timer->timeout *= 2; - if (timer->timeout > DTLS_RETRANSMIT_MAX_MS) { - timer->timeout = DTLS_RETRANSMIT_MAX_MS; + ss->ssl3.hs.rtTimeoutMs *= 2; + if (ss->ssl3.hs.rtTimeoutMs > DTLS_RETRANSMIT_MAX_MS) { + ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_MAX_MS; } - timer->started = PR_IntervalNow(); - timer->cb = dtls_RetransmitTimerExpiredCb; + ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); + ss->ssl3.hs.rtTimerCb = dtls_RetransmitTimerExpiredCb; SSL_TRC(30, ("%d: SSL3[%d]: Retransmit #%d, next in %d", SSL_GETPID(), ss->fd, - ss->ssl3.hs.rtRetries, timer->timeout)); + ss->ssl3.hs.rtRetries, ss->ssl3.hs.rtTimeoutMs)); } /* 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. - * - * TODO: Space separate UDP packets out a little. + * into as few records as seems reasonable * * Called from: * dtls_FlushHandshake() * dtls_RetransmitTimerExpiredCb() */ -SECStatus +static SECStatus dtls_TransmitMessageFlight(sslSocket *ss) { SECStatus rv = SECSuccess; PRCList *msg_p; - - SSL_TRC(10, ("%d: SSL3[%d]: dtls_TransmitMessageFlight", - SSL_GETPID(), ss->fd)); + PRUint16 room_left = ss->ssl3.mtu; + PRInt32 sent; 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. This function uses ss->pendingBuf temporarily and it - * needs to be empty to start. + /* 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 */ PORT_Assert(!ss->pendingBuf.len); - for (msg_p = PR_LIST_HEAD(&ss->ssl3.hs.lastMessageFlight); - msg_p != &ss->ssl3.hs.lastMessageFlight;) { + msg_p != &ss->ssl3.hs.lastMessageFlight; + msg_p = PR_NEXT_LINK(msg_p)) { DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p; - /* Move the pointer forward so that the functions below are free to - * remove messages from the list. */ - msg_p = PR_NEXT_LINK(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; + } - /* 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. */ + 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; + } - if (msg->type == content_handshake) { - rv = dtls_FragmentHandshake(ss, msg); + room_left = ss->ssl3.mtu - ss->pendingBuf.len; } else { - PORT_Assert(!tls13_MaybeTls13(ss)); - rv = dtls_SendFragment(ss, msg, msg->data, msg->len); - } - if (rv != SECSuccess) { - break; + /* 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; + } } } - /* Finally, flush any data that wasn't flushed already. */ - if (rv == SECSuccess) { + /* Finally, we need to flush */ + if (rv == SECSuccess) rv = dtls_SendSavedWriteData(ss); - } /* Give up the locks */ ssl_ReleaseSpecReadLock(ss); @@ -898,59 +796,23 @@ dtls_SendSavedWriteData(sslSocket *ss) return SECSuccess; } -void -dtls_InitTimers(sslSocket *ss) -{ - 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]; - } -} - -SECStatus -dtls_StartTimer(sslSocket *ss, dtlsTimer *timer, PRUint32 time, DTLSTimerCb cb) +static SECStatus +dtls_StartTimer(sslSocket *ss, 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; -} + PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); -SECStatus -dtls_RestartTimer(sslSocket *ss, dtlsTimer *timer) -{ - timer->started = PR_IntervalNow(); + ss->ssl3.hs.rtRetries = 0; + ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); + ss->ssl3.hs.rtTimeoutMs = time; + ss->ssl3.hs.rtTimerCb = cb; return SECSuccess; } -PRBool -dtls_TimerActive(sslSocket *ss, dtlsTimer *timer) -{ - return timer->cb != NULL; -} /* Start a timer for retransmission. */ static SECStatus dtls_StartRetransmitTimer(sslSocket *ss) { - ss->ssl3.hs.rtRetries = 0; - return dtls_StartTimer(ss, ss->ssl3.hs.rtTimer, - DTLS_RETRANSMIT_INITIAL_MS, + return dtls_StartTimer(ss, DTLS_RETRANSMIT_INITIAL_MS, dtls_RetransmitTimerExpiredCb); } @@ -958,9 +820,7 @@ dtls_StartRetransmitTimer(sslSocket *ss) SECStatus dtls_StartHolddownTimer(sslSocket *ss) { - ss->ssl3.hs.rtRetries = 0; - return dtls_StartTimer(ss, ss->ssl3.hs.rtTimer, - DTLS_RETRANSMIT_FINISHED_MS, + return dtls_StartTimer(ss, DTLS_RETRANSMIT_FINISHED_MS, dtls_FinishedTimerCb); } @@ -971,25 +831,11 @@ dtls_StartHolddownTimer(sslSocket *ss) * dtls_CheckTimer() */ void -dtls_CancelTimer(sslSocket *ss, dtlsTimer *timer) +dtls_CancelTimer(sslSocket *ss) { - 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)); - 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]); - } + ss->ssl3.hs.rtTimerCb = NULL; } /* Check the pending timer and fire the callback if it expired @@ -999,33 +845,22 @@ dtls_CancelAllTimers(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; + } - 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)); + if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > + PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) { + /* Timer has expired */ + DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb; - /* Cancel the timer so that we can call the CB safely */ - dtls_CancelTimer(ss, timer); + /* Cancel the timer so that we can call the CB safely */ + dtls_CancelTimer(ss); - /* Now call the CB */ - cb(ss); - } + /* Now call the CB */ + cb(ss); } ssl_ReleaseSSL3HandshakeLock(ss); } @@ -1039,6 +874,9 @@ 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 @@ -1057,8 +895,8 @@ dtls_RehandshakeCleanup(sslSocket *ss) return; } PORT_Assert((ss->version < SSL_LIBRARY_VERSION_TLS_1_3)); - dtls_CancelAllTimers(ss); - dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); + dtls_CancelTimer(ss); + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); ss->ssl3.hs.sendMessageSeq = 0; ss->ssl3.hs.recvMessageSeq = 0; } @@ -1121,8 +959,6 @@ 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 @@ -1267,53 +1103,27 @@ SECStatus DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout) { sslSocket *ss = NULL; - PRBool found = PR_FALSE; - PRIntervalTime now = PR_IntervalNow(); - PRIntervalTime to; - unsigned int i; - - *timeout = PR_INTERVAL_NO_TIMEOUT; + PRIntervalTime elapsed; + PRIntervalTime desired; ss = ssl_FindSocket(socket); - if (!ss) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); + if (!ss) return SECFailure; - } - if (!IS_DTLS(ss)) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); + if (!IS_DTLS(ss)) 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]; - - 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); + if (!ss->ssl3.hs.rtTimerCb) return SECFailure; + + 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; } return SECSuccess; @@ -1327,50 +1137,72 @@ 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 |*seqNumOut| to the - * packet sequence number (removing the epoch). + * 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. */ PRBool -dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec, - const SSL3Ciphertext *cText, - sslSequenceNumber *seqNumOut) +dtls_IsRelevant(sslSocket *ss, const SSL3Ciphertext *cText, + PRBool *sameEpoch, PRUint64 *seqNum) { - 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)); + 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)); return PR_FALSE; } - *seqNumOut = seqNum; + *seqNum = dtls_seq_num; return PR_TRUE; } -void -dtls_ReceivedFirstMessageInFlight(sslSocket *ss) +/* 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) { - if (!IS_DTLS(ss)) - return; + SECStatus rv = SECSuccess; + DTLSEpoch messageEpoch = cText->seq_num >> 48; - /* 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; - } + /* Drop messages from other epochs if we are ignoring things. */ + if (!sameEpoch && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) { + return SECSuccess; } - /* Empty the ACK queue (TLS 1.3 only). */ - ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL); + 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); + } + ssl_ReleaseSSL3HandshakeLock(ss); + } + return rv; } diff --git a/security/nss/lib/ssl/dtlscon.h b/security/nss/lib/ssl/dtlscon.h deleted file mode 100644 index d094380f8..000000000 --- a/security/nss/lib/ssl/dtlscon.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- 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 c3b34c6cc..e2123af84 100644 --- a/security/nss/lib/ssl/exports.gyp +++ b/security/nss/lib/ssl/exports.gyp @@ -15,7 +15,6 @@ '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 ca9b9ee7b..fbb88baff 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -10,7 +10,6 @@ EXPORTS = \ ssl.h \ sslt.h \ sslerr.h \ - sslexp.h \ sslproto.h \ preenc.h \ $(NULL) @@ -20,15 +19,13 @@ MAPFILE = $(OBJDIR)/ssl.def CSRCS = \ dtlscon.c \ - dtls13con.c \ prelib.c \ ssl3con.c \ ssl3gthr.c \ sslauth.c \ - sslbloom.c \ sslcon.c \ ssldef.c \ - sslencode.c \ + ssl3encode.c \ sslenum.c \ sslerr.c \ sslerrstrs.c \ @@ -41,7 +38,6 @@ CSRCS = \ sslsecur.c \ sslsnce.c \ sslsock.c \ - sslspec.c \ ssltrace.c \ sslver.c \ authcert.c \ @@ -51,9 +47,7 @@ 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 97217b4a6..6d6e25cfc 100644 --- a/security/nss/lib/ssl/selfencrypt.c +++ b/security/nss/lib/ssl/selfencrypt.c @@ -11,6 +11,7 @@ #include "pk11func.h" #include "ssl.h" #include "sslt.h" +#include "ssl3encode.h" #include "sslimpl.h" #include "selfencrypt.h" @@ -120,11 +121,12 @@ 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) }; - /* Write directly to out. */ - sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen); + unsigned char mac[SHA256_LENGTH]; /* SHA-256 */ + unsigned int macLen; + SECItem outItem = { siBuffer, out, maxOutLen }; + SECItem lengthBytesItem; SECStatus rv; /* Generate a random IV */ @@ -135,54 +137,52 @@ ssl_SelfEncryptProtectInt( } /* Add header. */ - rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN); + rv = ssl3_AppendToItem(&outItem, keyName, SELF_ENCRYPT_KEY_NAME_LEN); if (rv != SECSuccess) { return SECFailure; } - rv = sslBuffer_Append(&buf, iv, sizeof(iv)); + rv = ssl3_AppendToItem(&outItem, iv, sizeof(iv)); if (rv != SECSuccess) { return SECFailure; } - /* Leave space for the length of the ciphertext. */ - rv = sslBuffer_Skip(&buf, 2, &lenOffset); + /* Skip forward by two so we can encode the ciphertext in place. */ + lengthBytesItem = outItem; + rv = ssl3_AppendNumberToItem(&outItem, 0, 2); if (rv != SECSuccess) { return SECFailure; } - /* Encode the ciphertext in place. */ rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem, - SSL_BUFFER_NEXT(&buf), &len, - SSL_BUFFER_SPACE(&buf), in, inLen); - if (rv != SECSuccess) { - return SECFailure; - } - rv = sslBuffer_Skip(&buf, len, NULL); + outItem.data, &len, outItem.len, in, inLen); if (rv != SECSuccess) { return SECFailure; } - rv = sslBuffer_InsertLength(&buf, lenOffset, 2); + outItem.data += len; + outItem.len -= len; + + /* Now encode the ciphertext length. */ + rv = ssl3_AppendNumberToItem(&lengthBytesItem, len, 2); if (rv != SECSuccess) { return SECFailure; } - /* MAC the entire output buffer into the output. */ - PORT_Assert(buf.space - buf.len >= SHA256_LENGTH); + /* MAC the entire output buffer and append the MAC to the end. */ rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, - SSL_BUFFER_BASE(&buf), /* input */ - SSL_BUFFER_LEN(&buf), - SSL_BUFFER_NEXT(&buf), &len, /* output */ - SHA256_LENGTH); + out, outItem.data - out, + mac, &macLen, sizeof(mac)); if (rv != SECSuccess) { return SECFailure; } - rv = sslBuffer_Skip(&buf, len, NULL); + PORT_Assert(macLen == sizeof(mac)); + + rv = ssl3_AppendToItem(&outItem, mac, macLen); if (rv != SECSuccess) { return SECFailure; } - *outLen = SSL_BUFFER_LEN(&buf); + *outLen = outItem.data - out; return SECSuccess; } @@ -269,17 +269,6 @@ 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 5415ac09f..5bc8e4348 100644 --- a/security/nss/lib/ssl/selfencrypt.h +++ b/security/nss/lib/ssl/selfencrypt.h @@ -11,7 +11,6 @@ #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 9a447dbef..94d304223 100644 --- a/security/nss/lib/ssl/ssl.def +++ b/security/nss/lib/ssl/ssl.def @@ -234,9 +234,3 @@ 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 3694ab91a..03b2d6014 100644 --- a/security/nss/lib/ssl/ssl.gyp +++ b/security/nss/lib/ssl/ssl.gyp @@ -13,20 +13,18 @@ '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', @@ -39,14 +37,11 @@ '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"', { @@ -62,6 +57,14 @@ '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 25aabbaa2..7e538ac1f 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -107,7 +107,8 @@ 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 /* (unsupported, deprecated, off) */ +#define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */ + /* DEFLATE (off by default) */ #define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */ #define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signaling */ /* Cipher Suite Value (SCSV) or */ @@ -230,46 +231,25 @@ 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. 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. + * handshake callback. * * WARNING: 0-RTT data has different anti-replay and PFS properties than - * the rest of the TLS data. See [draft-ietf-tls-tls13; Section 8] + * the rest of the TLS data. See [draft-ietf-tls-tls13; Section 6.2.3] * 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, PRIntn on); -SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRIntn on); +SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on); +SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on); #endif -/* 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); +/* 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); SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle); /* SSLNextProtoCallback is called during the handshake for the client, when a @@ -1394,13 +1374,6 @@ 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 61878ae99..5cbe2bd09 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -34,13 +34,14 @@ #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_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms, - PK11SymKey **msp); -static SECStatus ssl3_DeriveConnectionKeys(sslSocket *ss, - PK11SymKey *masterSecret); +static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); +static SECStatus ssl3_DeriveConnectionKeys(sslSocket *ss); static SECStatus ssl3_HandshakeFailure(sslSocket *ss); static SECStatus ssl3_SendCertificate(sslSocket *ss); static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); @@ -50,28 +51,27 @@ static SECStatus ssl3_SendServerHelloDone(sslSocket *ss); static SECStatus ssl3_SendServerKeyExchange(sslSocket *ss); static SECStatus ssl3_HandleClientHelloPart2(sslSocket *ss, SECItem *suites, - sslSessionID *sid, - const PRUint8 *msg, - unsigned int len); + SECItem *comps, + sslSessionID *sid); static SECStatus ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, int *retErrCode); static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, - PRUint32 length); + PRUint32 length, + SSL3Hashes *hashesPtr); 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); -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); +#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */ +#define MIN_SEND_BUF_LENGTH 4000 /* This list of SSL3 cipher suites is sorted in descending order of * precedence (desirability). It only includes cipher suites we implement. @@ -214,6 +214,52 @@ 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, @@ -222,125 +268,173 @@ 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, 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 }, - }; +{ +/* 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 */ static const CK_MECHANISM_TYPE auth_alg_defs[] = { CKM_INVALID_MECHANISM, /* ssl_auth_null */ @@ -377,20 +471,44 @@ typedef struct SSLCipher2MechStr { /* indexed by type SSLCipherAlgorithm */ static const SSLCipher2Mech alg2Mech[] = { /* calg, cmech */ - { 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 }, + { 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 } */ }; +#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, @@ -436,57 +554,48 @@ ssl3_DecodeHandshakeType(int msgType) static char line[40]; switch (msgType) { - case ssl_hs_hello_request: + case hello_request: rv = "hello_request (0)"; break; - case ssl_hs_client_hello: + case client_hello: rv = "client_hello (1)"; break; - case ssl_hs_server_hello: + case server_hello: rv = "server_hello (2)"; break; - case ssl_hs_hello_verify_request: + case hello_verify_request: rv = "hello_verify_request (3)"; break; - 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)"; + case new_session_ticket: + rv = "session_ticket (4)"; break; - case ssl_hs_hello_retry_request: + case hello_retry_request: rv = "hello_retry_request (6)"; break; - case ssl_hs_encrypted_extensions: + case encrypted_extensions: rv = "encrypted_extensions (8)"; break; - case ssl_hs_certificate: + case certificate: rv = "certificate (11)"; break; - case ssl_hs_server_key_exchange: + case server_key_exchange: rv = "server_key_exchange (12)"; break; - case ssl_hs_certificate_request: + case certificate_request: rv = "certificate_request (13)"; break; - case ssl_hs_server_hello_done: + case server_hello_done: rv = "server_hello_done (14)"; break; - case ssl_hs_certificate_verify: + case certificate_verify: rv = "certificate_verify (15)"; break; - case ssl_hs_client_key_exchange: + case client_key_exchange: rv = "client_key_exchange (16)"; break; - case ssl_hs_finished: + case 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; @@ -513,9 +622,6 @@ 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; @@ -768,12 +874,20 @@ 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. */ -unsigned int +int ssl3_config_match_init(sslSocket *ss) { ssl3CipherSuiteCfg *suite; @@ -782,9 +896,9 @@ ssl3_config_match_init(sslSocket *ss) CK_MECHANISM_TYPE cipher_mech; SSLAuthType authType; SSLKEAType keaType; - unsigned int i; - unsigned int numPresent = 0; - unsigned int numEnabled = 0; + int i; + int numPresent = 0; + int numEnabled = 0; PORT_Assert(ss); if (!ss) { @@ -795,7 +909,6 @@ 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) { @@ -831,7 +944,7 @@ ssl3_config_match_init(sslSocket *ss) suite->isPresent = PR_FALSE; } - if (cipher_alg != ssl_calg_null && + if (cipher_alg != calg_null && !PK11_TokenExists(cipher_mech)) { suite->isPresent = PR_FALSE; } @@ -842,7 +955,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; @@ -887,10 +1000,10 @@ config_match(const ssl3CipherSuiteCfg *suite, int policy, /* Return the number of cipher suites that are usable. */ /* called from ssl3_SendClientHello */ -static unsigned int +static int count_cipher_suites(sslSocket *ss, int policy) { - unsigned int i, count = 0; + int i, count = 0; if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) { return 0; @@ -899,7 +1012,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; @@ -908,7 +1021,7 @@ count_cipher_suites(sslSocket *ss, int policy) /* * Null compression, mac and encryption functions */ -SECStatus +static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, const unsigned char *input, int inputLen) { @@ -928,19 +1041,6 @@ 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. @@ -952,8 +1052,6 @@ 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; @@ -965,14 +1063,9 @@ ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion, return SECFailure; } - 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 = PR_MIN(peerVersion, ss->vrange.max); + PORT_Assert(ssl3_VersionIsSupported(ss->protocolVariant, ss->version)); - ss->version = negotiated; return SECSuccess; } @@ -1011,16 +1104,24 @@ 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, SSL3_RANDOM_LENGTH); + rv = PK11_GenerateRandom(random->rand, SSL3_RANDOM_LENGTH); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); } @@ -1034,7 +1135,7 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key, { SECStatus rv = SECFailure; PRBool doDerEncode = PR_FALSE; - PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); + PRBool isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(ss->ssl3.hs.signatureScheme); SECItem hashItem; @@ -1320,110 +1421,124 @@ static SECStatus ssl3_ComputeDHKeyHash(sslSocket *ss, SSLHashType hashAlg, SSL3Hashes *hashes, SECItem dh_p, SECItem dh_g, SECItem dh_Ys, PRBool padY) { - sslBuffer buf = SSL_BUFFER_EMPTY; - SECStatus rv; - unsigned int yLen; - unsigned int i; + PRUint8 *hashBuf; + PRUint8 *pBuf; + SECStatus rv = SECSuccess; + unsigned int bufLen, yLen; + PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 4096 / 8 + 2 + 4096 / 8]; PORT_Assert(dh_p.data); PORT_Assert(dh_g.data); PORT_Assert(dh_Ys.data); - rv = sslBuffer_Append(&buf, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); - if (rv != SECSuccess) { - goto loser; - } - 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); - for (i = dh_Ys.len; i < yLen; ++i) { - rv = sslBuffer_AppendNumber(&buf, 0, 1); - if (rv != SECSuccess) { - goto loser; + 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, dh_Ys.data, dh_Ys.len); - if (rv != SECSuccess) { - goto loser; - } - rv = ssl3_ComputeCommonKeyHash(hashAlg, SSL_BUFFER_BASE(&buf), - SSL_BUFFER_LEN(&buf), hashes); - 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; } + /* 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); - 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)); - } + rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes); - sslBuffer_Clear(&buf); - return SECSuccess; + 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)); + } + } -loser: - sslBuffer_Clear(&buf); - return SECFailure; + if (hashBuf != buf && hashBuf != NULL) + PORT_Free(hashBuf); + return rv; } -static SECStatus -ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction, - const ssl3CipherSuiteDef *suiteDef, - ssl3CipherSpec **specp) +/* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */ +static void +ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat) { - 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 (mat->write_key != NULL) { + PK11_FreeSymKey(mat->write_key); + mat->write_key = NULL; } - - spec = ssl_CreateCipherSpec(ss, direction); - if (!spec) { - return SECFailure; + if (mat->write_mac_key != NULL) { + PK11_FreeSymKey(mat->write_mac_key); + mat->write_mac_key = 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); + if (mat->write_mac_context != NULL) { + PK11_DestroyContext(mat->write_mac_context, PR_TRUE); + mat->write_mac_context = NULL; } - ssl_SetSpecVersions(ss, spec); +} - ssl_SaveCipherSpec(ss, spec); - *specp = spec; - return SECSuccess; +/* Called from ssl3_SendChangeCipherSpecs() and +** ssl3_HandleChangeCipherSpecs() +** ssl3_DestroySSL3Info +** Caller must hold SpecWriteLock. +*/ +void +ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName) +{ + /* 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; + } + if (spec->destroyDecompressContext && spec->decompressContext) { + spec->destroyDecompressContext(spec->decompressContext, 1); + spec->decompressContext = NULL; + } + if (spec->master_secret != NULL) { + PK11_FreeSymKey(spec->master_secret); + spec->master_secret = NULL; + } + spec->msItem.data = NULL; + spec->msItem.len = 0; + ssl3_CleanupKeyMaterial(&spec->client); + ssl3_CleanupKeyMaterial(&spec->server); + spec->destroyCompressContext = NULL; + spec->destroyDecompressContext = NULL; } /* Fill in the pending cipher spec with info from the selected ciphersuite. @@ -1433,116 +1548,272 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction, ** Acquires & releases SpecWriteLock. */ SECStatus -ssl3_SetupBothPendingCipherSpecs(sslSocket *ss) +ssl3_SetupPendingCipherSpec(sslSocket *ss) { + ssl3CipherSpec *pwSpec; + ssl3CipherSpec *cwSpec; ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite; + SSL3MACAlgorithm mac; SSL3KeyExchangeAlgorithm kea; - const ssl3CipherSuiteDef *suiteDef; - SECStatus rv; + const ssl3CipherSuiteDef *suite_def; + PRBool isTLS; 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. */ - if (ss->ssl3.cwSpec->macDef->mac == ssl_mac_null) { + cwSpec = ss->ssl3.cwSpec; + if (cwSpec->mac_def->mac == mac_null) { /* SSL records are not being MACed. */ - ss->ssl3.cwSpec->version = ss->version; + 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)); - suiteDef = ssl_LookupCipherSuiteDef(suite); - if (suiteDef == NULL) { - goto loser; + suite_def = ssl_LookupCipherSuiteDef(suite); + if (suite_def == NULL) { + ssl_ReleaseSpecWriteLock(ss); + return SECFailure; /* error code set by ssl_LookupCipherSuiteDef */ } if (IS_DTLS(ss)) { /* Double-check that we did not pick an RC4 suite */ - PORT_Assert(suiteDef->bulk_cipher_alg != cipher_rc4); + PORT_Assert(suite_def->bulk_cipher_alg != cipher_rc4); } - ss->ssl3.hs.suite_def = suiteDef; + kea = suite_def->key_exchange_alg; + mac = suite_def->mac_alg; + if (mac <= ssl_mac_sha && mac != ssl_mac_null && isTLS) + mac += 2; - kea = suiteDef->key_exchange_alg; + ss->ssl3.hs.suite_def = suite_def; ss->ssl3.hs.kea_def = &kea_defs[kea]; PORT_Assert(ss->ssl3.hs.kea_def->kea == kea); - rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecRead, suiteDef, - &ss->ssl3.prSpec); - if (rv != SECSuccess) { - goto loser; + 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; } - rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecWrite, suiteDef, - &ss->ssl3.pwSpec); - if (rv != SECSuccess) { - goto loser; +} + +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; } - ssl_ReleaseSpecWriteLock(ss); /*******************************/ + 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; +} -loser: - ssl_ReleaseSpecWriteLock(ss); - return SECFailure; +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; + } + + 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; + } + + *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; } -/* 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. +static SECStatus +ssl3_DestroyDecompressContext(void *void_context, PRBool unused) +{ + inflateEnd(void_context); + PORT_Free(void_context); + 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; +} + +/* 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. * * TLS pseudo-header includes the record's version field, SSL's doesn't. Which - * pseudo-header definition to use should be decided based on the version of + * pseudo-header defintiion 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 SECStatus -ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch, - sslSequenceNumber seqNum, +static unsigned int +ssl3_BuildRecordPseudoHeader(unsigned char *out, + sslSequenceNumber seq_num, SSL3ContentType type, PRBool includesVersion, SSL3ProtocolVersion version, PRBool isDTLS, - 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; - } + 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; /* SSL3 MAC doesn't include the record's version field. */ - if (includesVersion) { - /* TLS MAC and AEAD additional data include version. */ - rv = sslBuffer_AppendNumber(buf, version, 2); - if (rv != SECSuccess) { - return SECFailure; - } - } - rv = sslBuffer_AppendNumber(buf, length, 2); - if (rv != SECSuccess) { - return SECFailure; + if (!includesVersion) { + out[9] = MSB(length); + out[10] = LSB(length); + return 11; } - return SECSuccess; + /* 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); + } + out[11] = MSB(length); + out[12] = LSB(length); + return 13; } static SECStatus @@ -1562,12 +1833,13 @@ ssl3_AESGCM(ssl3KeyMaterial *keys, unsigned int uOutLen; CK_GCM_PARAMS gcmParams; - const int tagSize = 16; - const int explicitNonceLen = 8; + 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; /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the * nonce is formed. */ - memcpy(nonce, keys->iv, 4); + memcpy(nonce, keys->write_iv, 4); if (doDecrypt) { memcpy(nonce + 4, in, explicitNonceLen); in += explicitNonceLen; @@ -1596,10 +1868,10 @@ ssl3_AESGCM(ssl3KeyMaterial *keys, gcmParams.ulTagBits = tagSize * 8; if (doDecrypt) { - rv = PK11_Decrypt(keys->key, CKM_AES_GCM, ¶m, out, &uOutLen, + rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, maxout, in, inlen); } else { - rv = PK11_Encrypt(keys->key, CKM_AES_GCM, ¶m, out, &uOutLen, + rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, maxout, in, inlen); } *outlen += (int)uOutLen; @@ -1621,12 +1893,12 @@ ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, unsigned char nonce[12]; CK_NSS_AEAD_PARAMS aeadParams; - const int tagSize = 16; + const int tagSize = bulk_cipher_defs[cipher_chacha20].tag_size; /* 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->iv, 12); + PORT_Memcpy(nonce, keys->write_iv, 12); /* XOR the last 8 bytes of the IV with the sequence number. */ PORT_Assert(additionalDataLen >= 8); @@ -1645,10 +1917,10 @@ ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, aeadParams.ulTagLen = tagSize; if (doDecrypt) { - rv = PK11_Decrypt(keys->key, CKM_NSS_CHACHA20_POLY1305, ¶m, + rv = PK11_Decrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, ¶m, out, &uOutLen, maxout, in, inlen); } else { - rv = PK11_Encrypt(keys->key, CKM_NSS_CHACHA20_POLY1305, ¶m, + rv = PK11_Encrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, ¶m, out, &uOutLen, maxout, in, inlen); } *outlen = (int)uOutLen; @@ -1661,31 +1933,44 @@ ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, * Caller holds Spec write lock. */ static SECStatus -ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec) +ssl3_InitPendingContexts(sslSocket *ss) { - CK_MECHANISM_TYPE encMechanism; - CK_ATTRIBUTE_TYPE encMode; - SECItem macParam; + ssl3CipherSpec *pwSpec; + const ssl3BulkCipherDef *cipher_def; + PK11Context *serverContext = NULL; + PK11Context *clientContext = NULL; + SECItem *param; + CK_MECHANISM_TYPE mechanism; + CK_MECHANISM_TYPE mac_mech; 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); - macLength = spec->macDef->mac_size; - calg = spec->cipherDef->calg; + pwSpec = ss->ssl3.pwSpec; + cipher_def = pwSpec->cipher_def; + macLength = pwSpec->mac_size; + calg = cipher_def->calg; PORT_Assert(alg2Mech[calg].calg == calg); - if (spec->cipherDef->type == type_aead) { - spec->cipher = NULL; - spec->cipherContext = NULL; + 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; switch (calg) { - case ssl_calg_aes_gcm: - spec->aead = ssl3_AESGCM; + case calg_aes_gcm: + pwSpec->aead = ssl3_AESGCM; break; - case ssl_calg_chacha20: - spec->aead = ssl3_ChaCha20Poly1305; + case calg_chacha20: + pwSpec->aead = ssl3_ChaCha20Poly1305; break; default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -1698,43 +1983,128 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec) ** Now setup the MAC contexts, ** crypto contexts are setup below. */ - macParam.data = (unsigned char *)&macLength; - macParam.len = sizeof(macLength); - macParam.type = siBuffer; - spec->keyMaterial.macContext = PK11_CreateContextBySymKey( - spec->macDef->mmech, CKA_SIGN, spec->keyMaterial.macKey, &macParam); - if (!spec->keyMaterial.macContext) { + 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); - return SECFailure; + 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) { + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); + goto fail; } /* ** Now setup the crypto contexts. */ - if (calg == ssl_calg_null) { - spec->cipher = Null_Cipher; + + if (calg == calg_null) { + pwSpec->encode = Null_Cipher; + pwSpec->decode = Null_Cipher; return SECSuccess; } + mechanism = ssl3_Alg2Mech(calg); - spec->cipher = (SSLCipher)PK11_CipherOp; - encMechanism = ssl3_Alg2Mech(calg); - encMode = (spec->direction == CipherSpecWrite) ? CKA_ENCRYPT : CKA_DECRYPT; + /* + * 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; + } /* - * build the context + * build the client context */ - iv.data = spec->keyMaterial.iv; - iv.len = spec->cipherDef->iv_size; - spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode, - spec->keyMaterial.key, - &iv); - if (!spec->cipherContext) { + 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) { ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - return SECFailure; + goto fail; } + 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 @@ -1744,78 +2114,73 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec) * 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 |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|. + * If the old master secret is reused, pms is NULL and the master secret is + * already in pwSpec->master_secret. */ SECStatus -ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret, PRBool derive) +ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) { - PK11SymKey *masterSecret; ssl3CipherSpec *pwSpec; - ssl3CipherSpec *prSpec; + ssl3CipherSpec *cwSpec; SECStatus rv; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(secret); ssl_GetSpecWriteLock(ss); /**************************************/ - PORT_Assert(ss->ssl3.pwSpec); - PORT_Assert(ss->ssl3.cwSpec->epoch == ss->ssl3.crSpec->epoch); - prSpec = ss->ssl3.prSpec; - pwSpec = ss->ssl3.pwSpec; + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - 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; - } + pwSpec = ss->ssl3.pwSpec; + cwSpec = ss->ssl3.cwSpec; - if (derive) { - rv = ssl3_ComputeMasterSecret(ss, secret, &masterSecret); + if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) { + rv = ssl3_DeriveMasterSecret(ss, pms); if (rv != SECSuccess) { - goto loser; + goto done; /* err code set by ssl3_DeriveMasterSecret */ } - } else { - masterSecret = secret; } - - PORT_Assert(masterSecret); - rv = ssl3_DeriveConnectionKeys(ss, masterSecret); - if (rv != SECSuccess) { - if (derive) { - /* masterSecret was created here. */ - PK11_FreeSymKey(masterSecret); + if (pwSpec->master_secret) { + rv = ssl3_DeriveConnectionKeys(ss); + if (rv == SECSuccess) { + rv = ssl3_InitPendingContexts(ss); } - goto loser; + } else { + PORT_Assert(pwSpec->master_secret); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; } - - /* 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; + goto done; } - rv = ssl3_InitPendingContexts(ss, ss->ssl3.pwSpec); - if (rv != SECSuccess) { - 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; - ssl_ReleaseSpecWriteLock(ss); /******************************/ - return SECSuccess; + dtls_InitRecvdRecords(&pwSpec->recvdRecords); + } -loser: +done: ssl_ReleaseSpecWriteLock(ss); /******************************/ - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; + if (rv != SECSuccess) + ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); + return rv; } /* @@ -1848,33 +2213,36 @@ 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 inputLen, + int inputLength, unsigned char *outbuf, - unsigned int *outLen) + unsigned int *outLength) { - PK11Context *context; - int macSize = spec->macDef->mac_size; + const ssl3MACDef *mac_def; SECStatus rv; PRINT_BUF(95, (NULL, "frag hash1: header", header, headerLen)); - PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLen)); + PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength)); - if (spec->macDef->mac == ssl_mac_null) { - *outLen = 0; + mac_def = spec->mac_def; + if (mac_def->mac == mac_null) { + *outLength = 0; return SECSuccess; } - 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); + 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); - PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLen)); + PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLength)); if (rv != SECSuccess) { rv = SECFailure; @@ -1892,6 +2260,7 @@ ssl3_ComputeRecordMAC( static SECStatus ssl3_ComputeRecordMACConstantTime( ssl3CipherSpec *spec, + PRBool useServerMacKey, const unsigned char *header, unsigned int headerLen, const PRUint8 *input, @@ -1903,13 +2272,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->macDef->mac_size); + PORT_Assert(inputLen >= spec->mac_size); PORT_Assert(originalLen >= inputLen); - if (spec->macDef->mac == ssl_mac_null) { + if (spec->mac_def->mac == mac_null) { *outLen = 0; return SECSuccess; } @@ -1919,7 +2288,7 @@ ssl3_ComputeRecordMACConstantTime( macType = CKM_NSS_SSL3_MAC_CONSTANT_TIME; } - params.macAlg = spec->macDef->mmech; + params.macAlg = spec->mac_def->mmech; params.ulBodyTotalLen = originalLen; params.pHeader = (unsigned char *)header; /* const cast */ params.ulHeaderLen = headerLen; @@ -1936,14 +2305,19 @@ ssl3_ComputeRecordMACConstantTime( outputItem.len = *outLen; outputItem.type = 0; - rv = PK11_SignWithSymKey(spec->keyMaterial.macKey, macType, ¶m, - &outputItem, &inputItem); + key = spec->server.write_mac_key; + if (!useServerMacKey) { + key = spec->client.write_mac_key; + } + + rv = PK11_SignWithSymKey(key, 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, header, headerLen, - input, inputLen - macSize, + return ssl3_ComputeRecordMAC(spec, useServerMacKey, + header, headerLen, + input, inputLen - spec->mac_size, outbuf, outLen); } @@ -1953,7 +2327,7 @@ ssl3_ComputeRecordMACConstantTime( return rv; } - PORT_Assert(outputItem.len == (unsigned)macSize); + PORT_Assert(outputItem.len == (unsigned)spec->mac_size); *outLen = outputItem.len; return rv; @@ -1989,30 +2363,34 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) /* Caller must hold the spec read lock. */ SECStatus -ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, - PRBool isServer, - PRBool isDTLS, - SSL3ContentType type, - const PRUint8 *pIn, - PRUint32 contentLen, - sslBuffer *wrBuf) -{ +ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, + PRBool isServer, + PRBool isDTLS, + PRBool capRecordVersion, + SSL3ContentType type, + const PRUint8 *pIn, + PRUint32 contentLen, + sslBuffer *wrBuf) +{ + const ssl3BulkCipherDef *cipher_def; SECStatus rv; PRUint32 macLen = 0; PRUint32 fragLen; PRUint32 p1Len, p2Len, oddLen = 0; unsigned int ivLen = 0; - unsigned char pseudoHeaderBuf[13]; - sslBuffer pseudoHeader = SSL_BUFFER(pseudoHeaderBuf); + unsigned char pseudoHeader[13]; + unsigned int pseudoHeaderLen; + + cipher_def = cwSpec->cipher_def; - if (cwSpec->cipherDef->type == type_block && + if (cipher_def->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 = cwSpec->cipherDef->iv_size; + ivLen = cipher_def->iv_size; if (ivLen > wrBuf->space) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; @@ -2022,7 +2400,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); return rv; } - rv = cwSpec->cipher(cwSpec->cipherContext, + rv = cwSpec->encode(cwSpec->encodeContext, wrBuf->buf, /* output */ (int *)&wrBuf->len, /* outlen */ ivLen, /* max outlen */ @@ -2034,14 +2412,24 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, } } - 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 (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; if (nonceLen + contentLen + tagLen > wrBuf->space) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -2049,26 +2437,23 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, } rv = cwSpec->aead( - &cwSpec->keyMaterial, + isServer ? &cwSpec->server : &cwSpec->client, PR_FALSE, /* do encrypt */ wrBuf->buf, /* output */ (int *)&wrBuf->len, /* out len */ wrBuf->space, /* max out */ pIn, contentLen, /* input */ - SSL_BUFFER_BASE(&pseudoHeader), SSL_BUFFER_LEN(&pseudoHeader)); + pseudoHeader, pseudoHeaderLen); 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, SSL_BUFFER_BASE(&pseudoHeader), - SSL_BUFFER_LEN(&pseudoHeader), - pIn, contentLen, + rv = ssl3_ComputeRecordMAC(cwSpec, isServer, pseudoHeader, + pseudoHeaderLen, pIn, contentLen, wrBuf->buf + ivLen + contentLen, &macLen); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); @@ -2083,16 +2468,16 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, * Pad the text (if we're doing a block cipher) * then Encrypt it */ - if (cwSpec->cipherDef->type == type_block) { + if (cipher_def->type == type_block) { unsigned char *pBuf; int padding_length; int i; - oddLen = contentLen % blockSize; + oddLen = contentLen % cipher_def->block_size; /* Assume blockSize is a power of two */ - padding_length = blockSize - 1 - ((fragLen) & (blockSize - 1)); + padding_length = cipher_def->block_size - 1 - ((fragLen) & (cipher_def->block_size - 1)); fragLen += padding_length + 1; - PORT_Assert((fragLen % blockSize) == 0); + PORT_Assert((fragLen % cipher_def->block_size) == 0); /* Pad according to TLS rules (also acceptable to SSL3). */ pBuf = &wrBuf->buf[ivLen + fragLen - 1]; @@ -2110,13 +2495,13 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, } if (oddLen) { p2Len += oddLen; - PORT_Assert((blockSize < 2) || - (p2Len % blockSize) == 0); + PORT_Assert((cipher_def->block_size < 2) || + (p2Len % cipher_def->block_size) == 0); memmove(wrBuf->buf + ivLen + p1Len, pIn + p1Len, oddLen); } if (p1Len > 0) { int cipherBytesPart1 = -1; - rv = cwSpec->cipher(cwSpec->cipherContext, + rv = cwSpec->encode(cwSpec->encodeContext, wrBuf->buf + ivLen, /* output */ &cipherBytesPart1, /* actual outlen */ p1Len, /* max outlen */ @@ -2131,7 +2516,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec, } if (p2Len > 0) { int cipherBytesPart2 = -1; - rv = cwSpec->cipher(cwSpec->cipherContext, + rv = cwSpec->encode(cwSpec->encodeContext, wrBuf->buf + ivLen + p1Len, &cipherBytesPart2, /* output and actual outLen */ p2Len, /* max outlen */ @@ -2149,66 +2534,34 @@ ssl3_MACEncryptRecord(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, SSL3ContentType type, +ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, + PRBool capRecordVersion, SSL3ContentType type, const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) { - unsigned int headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH - : SSL3_RECORD_HEADER_LENGTH; - sslBuffer protBuf = SSL_BUFFER_FIXED(SSL_BUFFER_BASE(wrBuf) + headerLen, - SSL_BUFFER_SPACE(wrBuf) - headerLen); + const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def; + PRUint16 headerLen; + sslBuffer protBuf; + SSL3ProtocolVersion version = cwSpec->version; PRBool isTLS13; + PRUint8 *ptr = wrBuf->buf; SECStatus rv; - PORT_Assert(cwSpec->direction == CipherSpecWrite); - PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0); - PORT_Assert(cwSpec->cipherDef->max_records <= RECORD_SEQ_MAX); - if (cwSpec->seqNum >= cwSpec->cipherDef->max_records) { - /* We should have automatically updated before here in TLS 1.3. */ - PORT_Assert(cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3); + 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) { SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx", - SSL_GETPID(), cwSpec->seqNum)); + SSL_GETPID(), cwSpec->write_seq_num)); PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS); return SECFailure; } @@ -2216,22 +2569,15 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, isTLS13 = (PRBool)(cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3); #ifdef UNSAFE_FUZZER_MODE - { - 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. */ - } + rv = Null_Cipher(NULL, protBuf.buf, (int *)&protBuf.len, protBuf.space, + pIn, contentLen); #else if (isTLS13) { rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, &protBuf); } else { - rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), type, - pIn, contentLen, &protBuf); + rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, + IS_DTLS(ss), capRecordVersion, type, + pIn, contentLen, &protBuf); } #endif if (rv != SECSuccess) { @@ -2239,58 +2585,40 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, } PORT_Assert(protBuf.len <= MAX_FRAGMENT_LENGTH + (isTLS13 ? 256 : 1024)); + wrBuf->len = protBuf.len + headerLen; - rv = ssl_InsertRecordHeader(ss, cwSpec, type, SSL_BUFFER_LEN(&protBuf), - wrBuf); - if (rv != SECSuccess) { - return SECFailure; - } - - PORT_Assert(SSL_BUFFER_LEN(wrBuf) == headerLen); - rv = sslBuffer_Skip(wrBuf, SSL_BUFFER_LEN(&protBuf), NULL); - if (rv != SECSuccess) { - PORT_Assert(0); /* Can't fail. */ - return SECFailure; - } - ++cwSpec->seqNum; - - return SECSuccess; -} + 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; + } -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; + if (IS_DTLS(ss)) { + version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version; + version = dtls_TLSVersionToDTLSVersion(version); - 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; + 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); } + (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 @@ -2311,6 +2639,16 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSL3ContentType type, * 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, @@ -2321,9 +2659,10 @@ 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), @@ -2331,7 +2670,6 @@ 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", @@ -2339,41 +2677,114 @@ 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; } - 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; - } - while (nIn > 0) { - unsigned int written = 0; - PRInt32 sent; + PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH); + unsigned int spaceNeeded; + unsigned int numRecords; - ssl_GetSpecReadLock(ss); - rv = ssl_ProtectNextRecord(ss, spec, type, pIn, nIn, &written); - ssl_ReleaseSpecReadLock(ss); - if (rv != SECSuccess) { - return SECFailure; + ssl_GetSpecReadLock(ss); /********************************/ + + 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; } - PORT_Assert(written > 0); - /* DTLS should not fragment non-application data here. */ - if (IS_DTLS(ss) && type != content_application_data) { - PORT_Assert(written == nIn); + 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. */ + } + } + + 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)); + } } - pIn += written; - nIn -= written; + spec_locked_loser: + ssl_ReleaseSpecReadLock(ss); /************************************/ + + if (rv != SECSuccess) + return SECFailure; + + pIn += contentLen; + nIn -= contentLen; PORT_Assert(nIn >= 0); /* If there's still some previously saved ciphertext, @@ -2383,64 +2794,58 @@ ssl3_SendRecord(sslSocket *ss, if ((ss->pendingBuf.len > 0) || (flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf), - SSL_BUFFER_LEN(wrBuf)); + rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ - goto loser; + return SECFailure; } + 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); - goto loser; + return SECFailure; } if (ss->pendingBuf.len) { flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER; } } - } else { - PORT_Assert(SSL_BUFFER_LEN(wrBuf) > 0); + } else if (wrBuf->len > 0) { + PRInt32 sent; ss->handshakeBegun = 1; - sent = ssl_DefSend(ss, SSL_BUFFER_BASE(wrBuf), - SSL_BUFFER_LEN(wrBuf), + sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len, flags & ~ssl_SEND_FLAG_MASK); if (sent < 0) { - if (PORT_GetError() != PR_WOULD_BLOCK_ERROR) { + if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - goto loser; + return SECFailure; } /* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */ sent = 0; } - if (SSL_BUFFER_LEN(wrBuf) > (unsigned int)sent) { + wrBuf->len -= sent; + if (wrBuf->len) { if (IS_DTLS(ss)) { /* DTLS just says no in this case. No buffering */ - PORT_SetError(PR_WOULD_BLOCK_ERROR); - goto loser; + PR_SetError(PR_WOULD_BLOCK_ERROR, 0); + return SECFailure; } /* now take all the remaining unsent new ciphertext and * append it to the buffer of previously unsent ciphertext. */ - rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf) + sent, - SSL_BUFFER_LEN(wrBuf) - sent); + rv = ssl_SaveWriteData(ss, wrBuf->buf + sent, wrBuf->len); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ - goto loser; + return SECFailure; } } } - wrBuf->len = 0; - totalSent += written; + totalSent += contentLen; } return totalSent; - -loser: - /* Don't leave bits of buffer lying around. */ - wrBuf->len = 0; - return -1; } #define SSL3_PENDING_HIGH_WATER 1024 @@ -2454,7 +2859,6 @@ 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 */ @@ -2481,16 +2885,6 @@ 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; @@ -2505,13 +2899,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */ ssl_GetXmitBufLock(ss); } - - if (splitNeeded) { - toSend = 1; - splitNeeded = PR_FALSE; - } else { - toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); - } + toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); /* * Note that the 0 epoch is OK because flags will never require @@ -2571,8 +2959,9 @@ 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. @@ -2584,7 +2973,8 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) { - static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER; + static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER | + ssl_SEND_FLAG_CAP_RECORD_VERSION; PRInt32 count = -1; SECStatus rv; @@ -2715,15 +3105,6 @@ 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) { @@ -2959,6 +3340,9 @@ 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; @@ -2970,6 +3354,7 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) switch (desc) { case close_notify: case user_canceled: + case end_of_early_data: break; default: level = alert_fatal; @@ -2989,6 +3374,9 @@ 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; @@ -3011,64 +3399,59 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) * and pending write spec pointers. */ -SECStatus -ssl3_SendChangeCipherSpecsInt(sslSocket *ss) +static SECStatus +ssl3_SendChangeCipherSpecs(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 SECFailure; /* error code set by ssl3_FlushHandshake */ + return rv; /* error code set by ssl3_FlushHandshake */ } - if (!IS_DTLS(ss)) { - PRInt32 sent; - sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec, - &change, 1, ssl_SEND_FLAG_FORCE_INTO_BUFFER); + sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec, &change, 1, + ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (sent < 0) { - return SECFailure; /* error code set by ssl3_SendRecord */ + return (SECStatus)sent; /* error code set by ssl3_SendRecord */ } } else { - SECStatus rv; rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1); if (rv != SECSuccess) { - return SECFailure; + return rv; } } - 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; - ssl_CipherSpecRelease(ss->ssl3.cwSpec); - ss->ssl3.cwSpec = ss->ssl3.pwSpec; - ss->ssl3.pwSpec = NULL; + ss->ssl3.pwSpec = ss->ssl3.cwSpec; + ss->ssl3.cwSpec = pwSpec; SSL_TRC(3, ("%d: SSL3[%d] Set Current Write Cipher Suite to Pending", SSL_GETPID(), ss->fd)); - /* 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); + /* 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); + } } ssl_ReleaseSpecWriteLock(ss); /**************************************/ @@ -3084,6 +3467,7 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) static SECStatus ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) { + ssl3CipherSpec *prSpec; SSL3WaitState ws = ss->ssl3.hs.ws; SSL3ChangeCipherSpecChoice change; @@ -3093,18 +3477,19 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) SSL_TRC(3, ("%d: SSL3[%d]: handle change_cipher_spec record", SSL_GETPID(), ss->fd)); - /* 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; + 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; } - /* Handshake messages should not span ChangeCipherSpec. */ if (ss->ssl3.hs.header_bytes) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); @@ -3123,44 +3508,26 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER); return SECFailure; } - 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)); + /* Swap the pending and current read specs. */ 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); /*************************************/ + prSpec = ss->ssl3.prSpec; + ss->ssl3.prSpec = ss->ssl3.crSpec; + ss->ssl3.crSpec = prSpec; ss->ssl3.hs.ws = wait_finished; + + 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_ReleaseSpecWriteLock(ss); /*************************************/ return SECSuccess; } @@ -3283,8 +3650,12 @@ static SECStatus ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms, PK11SymKey **msp) { - PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); - PRBool isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); + 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); /* * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size @@ -3330,9 +3701,9 @@ ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms, } master_params.pVersion = pms_version_ptr; - master_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random; + master_params.RandomInfo.pClientRandom = cr; master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH; - master_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random; + master_params.RandomInfo.pServerRandom = sr; master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH; if (isTLS12) { master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss); @@ -3392,7 +3763,7 @@ tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms, pms_version_ptr = &pms_version; } - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + if (pwSpec->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; @@ -3424,6 +3795,7 @@ 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); @@ -3432,6 +3804,36 @@ 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. @@ -3448,18 +3850,17 @@ ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms, * */ static SECStatus -ssl3_DeriveConnectionKeys(sslSocket *ss, PK11SymKey *masterSecret) +ssl3_DeriveConnectionKeys(sslSocket *ss) { ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; - ssl3CipherSpec *prSpec = ss->ssl3.prSpec; - ssl3CipherSpec *clientSpec; - ssl3CipherSpec *serverSpec; - PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); + 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 && ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); - const ssl3BulkCipherDef *cipher_def = pwSpec->cipherDef; + (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); + const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; PK11SlotInfo *slot = NULL; - PK11SymKey *derivedKeyHandle = NULL; + PK11SymKey *symKey = NULL; void *pwArg = ss->pkcs11PinArg; int keySize; CK_TLS12_KEY_MAT_PARAMS key_material_params; /* may be used as a @@ -3470,53 +3871,48 @@ ssl3_DeriveConnectionKeys(sslSocket *ss, PK11SymKey *masterSecret) CK_MECHANISM_TYPE bulk_mechanism; SSLCipherAlgorithm calg; SECItem params; - PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == ssl_calg_null); + PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == calg_null); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); - PORT_Assert(masterSecret); + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - /* These functions operate in terms of who is writing specs. */ - if (ss->sec.isServer) { - clientSpec = prSpec; - serverSpec = pwSpec; - } else { - clientSpec = pwSpec; - serverSpec = prSpec; + if (!pwSpec->master_secret) { + PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); + return SECFailure; } - /* * 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 && - ss->version >= SSL_LIBRARY_VERSION_TLS_1_1) { + pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */ key_material_params.ulIVSizeInBits = 0; - PORT_Memset(clientSpec->keyMaterial.iv, 0, cipher_def->iv_size); - PORT_Memset(serverSpec->keyMaterial.iv, 0, cipher_def->iv_size); + memset(pwSpec->client.write_iv, 0, cipher_def->iv_size); + memset(pwSpec->server.write_iv, 0, cipher_def->iv_size); } key_material_params.bIsExport = PR_FALSE; - key_material_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random; + key_material_params.RandomInfo.pClientRandom = cr; key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH; - key_material_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random; + key_material_params.RandomInfo.pServerRandom = sr; 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; - 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; + returnedKeys.pIVClient = NULL; + returnedKeys.pIVServer = NULL; } - key_material_params.ulMacSizeInBits = pwSpec->macDef->mac_size * BPB; calg = cipher_def->calg; bulk_mechanism = ssl3_Alg2Mech(calg); @@ -3538,9 +3934,9 @@ ssl3_DeriveConnectionKeys(sslSocket *ss, PK11SymKey *masterSecret) /* CKM_SSL3_KEY_AND_MAC_DERIVE is defined to set ENCRYPT, DECRYPT, and * DERIVE by DEFAULT */ - derivedKeyHandle = PK11_Derive(masterSecret, key_derive, ¶ms, - bulk_mechanism, CKA_ENCRYPT, keySize); - if (!derivedKeyHandle) { + symKey = PK11_Derive(pwSpec->master_secret, key_derive, ¶ms, + bulk_mechanism, CKA_ENCRYPT, keySize); + if (!symKey) { ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); return SECFailure; } @@ -3548,44 +3944,41 @@ ssl3_DeriveConnectionKeys(sslSocket *ss, PK11SymKey *masterSecret) * don't because these types are used to map keytype anyway and both * mac's map to the same keytype. */ - slot = PK11_GetSlotFromKey(derivedKeyHandle); + slot = PK11_GetSlotFromKey(symKey); PK11_FreeSlot(slot); /* slot is held until the key is freed */ - clientSpec->keyMaterial.macKey = - PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, - CKM_SSL3_SHA1_MAC, returnedKeys.hClientMacSecret, - PR_TRUE, pwArg); - if (clientSpec->keyMaterial.macKey == NULL) { + 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) { goto loser; /* loser sets err */ } - serverSpec->keyMaterial.macKey = - PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, - CKM_SSL3_SHA1_MAC, returnedKeys.hServerMacSecret, - PR_TRUE, pwArg); - if (serverSpec->keyMaterial.macKey == NULL) { + 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) { goto loser; /* loser sets err */ } if (!skipKeysAndIVs) { - clientSpec->keyMaterial.key = - PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, - bulk_mechanism, returnedKeys.hClientKey, - PR_TRUE, pwArg); - if (clientSpec->keyMaterial.key == NULL) { + pwSpec->client.write_key = + PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, + bulk_mechanism, returnedKeys.hClientKey, PR_TRUE, pwArg); + if (pwSpec->client.write_key == NULL) { goto loser; /* loser sets err */ } - serverSpec->keyMaterial.key = - PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive, - bulk_mechanism, returnedKeys.hServerKey, - PR_TRUE, pwArg); - if (serverSpec->keyMaterial.key == NULL) { + pwSpec->server.write_key = + PK11_SymKeyFromHandle(slot, symKey, PK11_OriginDerive, + bulk_mechanism, returnedKeys.hServerKey, PR_TRUE, pwArg); + if (pwSpec->server.write_key == NULL) { goto loser; /* loser sets err */ } } - PK11_FreeSymKey(derivedKeyHandle); + PK11_FreeSymKey(symKey); return SECSuccess; loser: - PK11_FreeSymKey(derivedKeyHandle); + if (symKey) + PK11_FreeSymKey(symKey); ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); return SECFailure; } @@ -3629,11 +4022,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. */ @@ -3724,7 +4117,7 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l return sslBuffer_Append(&ss->ssl3.hs.messages, b, l); } - PRINT_BUF(90, (ss, "handshake hash input:", b, l)); + PRINT_BUF(90, (NULL, "handshake hash input:", b, l)); if (ss->ssl3.hs.hashType == handshake_hash_single) { PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); @@ -3748,8 +4141,104 @@ 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, SSLHandshakeType t, PRUint32 length) +ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) { SECStatus rv; @@ -3841,22 +4330,17 @@ 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_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *num, PRUint32 bytes, - PRUint8 **b, PRUint32 *length) +ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes, + PRUint8 **b, PRUint32 *length) { PRUint8 *buf = *b; - PRUint32 i; + int i; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); *num = 0; - if (bytes > sizeof(*num)) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - if (bytes > *length) { + if (bytes > *length || bytes > sizeof(*num)) { return ssl3_DecodeError(ss); } PRINT_BUF(60, (ss, "consume bytes:", *b, bytes)); @@ -3869,26 +4353,6 @@ ssl3_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *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 @@ -4298,8 +4762,6 @@ 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); @@ -4321,7 +4783,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, /* compute hashes for SSL3. */ unsigned char s[4]; - if (!spec->masterSecret) { + if (!spec->master_secret) { PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); rv = SECFailure; goto loser; @@ -4337,10 +4799,11 @@ 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, md5Pad)); + PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", 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_DigestKey(md5, spec->master_secret); + rv |= PK11_DigestOp(md5, mac_pad_1, mac_defs[mac_md5].pad_size); rv |= PK11_DigestFinal(md5, md5_inner, &outLength, MD5_LENGTH); PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); if (rv != SECSuccess) { @@ -4356,10 +4819,11 @@ 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, shaPad)); + PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", 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_DigestKey(sha, spec->master_secret); + rv |= PK11_DigestOp(sha, mac_pad_1, mac_defs[mac_sha].pad_size); rv |= PK11_DigestFinal(sha, sha_inner, &outLength, SHA1_LENGTH); PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); if (rv != SECSuccess) { @@ -4370,12 +4834,13 @@ 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, md5Pad)); + PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, + mac_defs[mac_md5].pad_size)); PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH)); rv |= PK11_DigestBegin(md5); - rv |= PK11_DigestKey(md5, spec->masterSecret); - rv |= PK11_DigestOp(md5, mac_pad_2, md5Pad); + rv |= PK11_DigestKey(md5, spec->master_secret); + rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); } rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH); @@ -4389,12 +4854,13 @@ 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, shaPad)); + PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, + mac_defs[mac_sha].pad_size)); PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH)); rv |= PK11_DigestBegin(sha); - rv |= PK11_DigestKey(sha, spec->masterSecret); - rv |= PK11_DigestOp(sha, mac_pad_2, shaPad); + rv |= PK11_DigestKey(sha, spec->master_secret); + rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); } rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH); @@ -4460,48 +4926,6 @@ 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) @@ -4518,18 +4942,18 @@ SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) { sslSessionID *sid; + ssl3CipherSpec *cwSpec; SECStatus rv; - unsigned int i; - unsigned int length; - unsigned int num_suites; - unsigned int actual_count = 0; + int i; + int length; + int num_suites; + int actual_count = 0; PRBool isTLS = PR_FALSE; PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; - PRBool unlockNeeded = PR_FALSE; - sslBuffer extensionBuf = SSL_BUFFER_EMPTY; - PRUint16 version = ss->vrange.max; + PRInt32 total_exten_len = 0; + unsigned numCompressionMethods; + PRUint16 version; 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))); @@ -4548,26 +4972,22 @@ 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)? */ - if (ssl3_config_match_init(ss) == 0) { + num_suites = ssl3_config_match_init(ss); + if (!num_suites) { return SECFailure; /* ssl3_config_match_init has set error code. */ } @@ -4615,7 +5035,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) } /* Check that we can recover the master secret. */ - if (sidOK) { + if (sidOK && sid->u.ssl3.keys.msIsWrapped) { PK11SlotInfo *slot = NULL; if (sid->u.ssl3.masterValid) { slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, @@ -4680,6 +5100,8 @@ 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; } } } @@ -4713,6 +5135,8 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) */ if (ss->firstHsDone) { version = ss->clientHelloVersion; + } else { + version = ss->vrange.max; } sid = ssl3_NewSessionID(ss, PR_FALSE); @@ -4725,9 +5149,10 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) isTLS = (version > SSL_LIBRARY_VERSION_3_0); ssl_GetSpecWriteLock(ss); - if (ss->ssl3.cwSpec->macDef->mac == ssl_mac_null) { + cwSpec = ss->ssl3.cwSpec; + if (cwSpec->mac_def->mac == mac_null) { /* SSL records are not being MACed. */ - ss->ssl3.cwSpec->version = version; + cwSpec->version = version; } ssl_ReleaseSpecWriteLock(ss); @@ -4751,10 +5176,9 @@ 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 ssl_ConstructExtensions. + * the lock across the calls to ssl3_CallHelloExtensionSenders. */ if (sid->u.ssl3.lock) { - unlockNeeded = PR_TRUE; PR_RWLock_Rlock(sid->u.ssl3.lock); } @@ -4762,14 +5186,24 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) type == client_hello_initial) { rv = tls13_SetupClientHello(ss); if (rv != SECSuccess) { - goto loser; + return SECFailure; } } if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) { - rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_client_hello); - if (rv != SECSuccess) { - goto loser; + 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; } + total_exten_len += extLen; + + if (total_exten_len > 0) + total_exten_len += 2; } if (IS_DTLS(ss)) { @@ -4779,7 +5213,10 @@ 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) { - goto loser; /* count_cipher_suites has set error code. */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return SECFailure; /* count_cipher_suites has set error code. */ } fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume || @@ -4792,30 +5229,37 @@ 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 + /* session id */ + 1 + (sid->version >= SSL_LIBRARY_VERSION_TLS_1_3 + ? 0 + : sid->u.ssl3.sessionIDLength) + 2 + num_suites * sizeof(ssl3CipherSuite) + - 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; - } + 1 + numCompressionMethods + total_exten_len; if (IS_DTLS(ss)) { - length += 1 + cookieLen; + length += 1 + ss->ssl3.hs.cookie.len; } - if (extensionBuf.len) { - rv = ssl_InsertPaddingExtension(ss, length, &extensionBuf); - if (rv != SECSuccess) { - goto loser; /* err set by ssl_InsertPaddingExtension */ + 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; } - length += 2 + extensionBuf.len; } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_hello, length); + rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by ssl3_AppendHandshake* */ } if (ss->firstHsDone) { @@ -4833,49 +5277,60 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2); } if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* 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) { - goto loser; /* err set by GetNewRandom. */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* 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) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* 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 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 { + else rv = ssl3_AppendHandshakeNumber(ss, 0, 1); - } if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by ssl3_AppendHandshake* */ } if (IS_DTLS(ss)) { rv = ssl3_AppendHandshakeVariable( - ss, ss->ssl3.hs.cookie.data, cookieLen, 1); + ss, ss->ssl3.hs.cookie.data, ss->ssl3.hs.cookie.len, 1); if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by ssl3_AppendHandshake* */ } } rv = ssl3_AppendHandshakeNumber(ss, num_suites * sizeof(ssl3CipherSuite), 2); if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by ssl3_AppendHandshake* */ } if (ss->ssl3.hs.sendingSCSV) { @@ -4883,7 +5338,10 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) rv = ssl3_AppendHandshakeNumber(ss, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, sizeof(ssl3CipherSuite)); if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by ssl3_AppendHandshake* */ } actual_count++; } @@ -4891,7 +5349,10 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV, sizeof(ssl3CipherSuite)); if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by ssl3_AppendHandshake* */ } actual_count++; } @@ -4900,14 +5361,20 @@ 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); - goto loser; + return SECFailure; } rv = ssl3_AppendHandshakeNumber(ss, suite->cipher_suite, sizeof(ssl3CipherSuite)); if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by ssl3_AppendHandshake* */ } } } @@ -4917,37 +5384,57 @@ 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); - goto loser; + return SECFailure; } - /* Compression methods: count is always 1, null compression. */ - rv = ssl3_AppendHandshakeNumber(ss, 1, 1); + rv = ssl3_AppendHandshakeNumber(ss, numCompressionMethods, 1); if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ + 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* */ + 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* */ + } } - 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); - } + if (total_exten_len) { + PRUint32 maxBytes = total_exten_len - 2; + PRInt32 extLen; + + rv = ssl3_AppendHandshakeNumber(ss, maxBytes, 2); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + if (sid->u.ssl3.lock) { + PR_RWLock_Unlock(sid->u.ssl3.lock); + } + return rv; /* err set by AppendHandshake. */ + } + + 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; } + maxBytes -= extLen; + + PORT_Assert(!maxBytes); } - sslBuffer_Clear(&extensionBuf); - if (unlockNeeded) { - /* Note: goto loser can't be used past this point. */ + if (sid->u.ssl3.lock) { PR_RWLock_Unlock(sid->u.ssl3.lock); } @@ -4963,6 +5450,9 @@ 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 */ @@ -4977,13 +5467,6 @@ 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 @@ -5535,7 +6018,7 @@ ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) /* Generate the pre-master secret ... */ ssl_GetSpecWriteLock(ss); - isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.pwSpec, NULL); ssl_ReleaseSpecWriteLock(ss); @@ -5558,20 +6041,41 @@ ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) goto loser; } -#ifdef TRACE - if (ssl_trace >= 100) { +#ifdef NSS_ALLOW_SSLKEYLOGFILE + if (ssl_keylog_iob) { SECStatus extractRV = PK11_ExtractKeyValue(pms); if (extractRV == SECSuccess) { SECItem *keyData = PK11_GetKeyData(pms); if (keyData && keyData->data && keyData->len) { - ssl_PrintBuf(ss, "Pre-Master Secret", - 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); + } } } } #endif - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange, + rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, isTLS ? enc_pms.len + 2 : enc_pms.len); if (rv != SECSuccess) { @@ -5586,7 +6090,7 @@ ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) goto loser; /* err set by ssl3_AppendHandshake* */ } - rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); + rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); pms = NULL; @@ -5610,27 +6114,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(sslBuffer *buf, const SECKEYPublicKey *pubKey, +ssl_AppendPaddedDHKeyShare(const sslSocket *ss, const SECKEYPublicKey *pubKey, PRBool appendLength) { SECStatus rv; unsigned int pad = pubKey->u.dh.prime.len - pubKey->u.dh.publicValue.len; if (appendLength) { - rv = sslBuffer_AppendNumber(buf, pubKey->u.dh.prime.len, 2); + rv = ssl3_ExtAppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2); if (rv != SECSuccess) { return rv; } } while (pad) { - rv = sslBuffer_AppendNumber(buf, 0, 1); + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 1); if (rv != SECSuccess) { return rv; } --pad; } - rv = sslBuffer_Append(buf, pubKey->u.dh.publicValue.data, - pubKey->u.dh.publicValue.len); + rv = ssl3_ExtAppendHandshake(ss, pubKey->u.dh.publicValue.data, + pubKey->u.dh.publicValue.len); if (rv != SECSuccess) { return rv; } @@ -5654,13 +6158,11 @@ 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->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); /* Copy DH parameters from server key */ @@ -5715,27 +6217,22 @@ ssl3_SendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) } /* Note: send the DH share padded to avoid triggering bugs. */ - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange, + rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, params->prime.len + 2); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } - rv = ssl_AppendPaddedDHKeyShare(&dhBuf, pubKey, PR_TRUE); + rv = ssl_AppendPaddedDHKeyShare(ss, 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_InitPendingCipherSpecs(ss, pms, PR_TRUE); + rv = ssl3_InitPendingCipherSpec(ss, pms); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } - sslBuffer_Clear(&dhBuf); PK11_FreeSymKey(pms); ssl_FreeEphemeralKeyPair(keyPair); return SECSuccess; @@ -5745,7 +6242,6 @@ loser: PK11_FreeSymKey(pms); if (keyPair) ssl_FreeEphemeralKeyPair(keyPair); - sslBuffer_Clear(&dhBuf); return SECFailure; } @@ -5926,8 +6422,8 @@ ssl3_PickServerSignatureScheme(sslSocket *ss) /* Sets error code, if needed. */ return ssl_PickSignatureScheme(ss, keyPair->pubKey, keyPair->privKey, - ss->xtnData.sigSchemes, - ss->xtnData.numSigSchemes, + ss->xtnData.clientSigSchemes, + ss->xtnData.numClientSigScheme, PR_FALSE /* requireSha1 */); } @@ -6044,7 +6540,7 @@ ssl3_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey) len = buf.len + 2 + (isTLS12 ? 2 : 0); - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len); + rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); if (rv != SECSuccess) { goto done; /* error code set by AppendHandshake */ } @@ -6068,9 +6564,11 @@ done: /* Once a cipher suite has been selected, make sure that the necessary secondary * information is properly set. */ SECStatus -ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes) +ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite, + PRBool initHashes) { - ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); + ss->ssl3.hs.cipher_suite = chosenSuite; + ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(chosenSuite); if (!ss->ssl3.hs.suite_def) { PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -6083,53 +6581,10 @@ ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes) if (!initHashes) { return SECSuccess; } - /* Now we have a cipher suite, initialize the handshake hashes. */ + /* Now we've 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. @@ -6137,16 +6592,14 @@ ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version, static SECStatus ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) { - PRUint32 cipher; + PRUint32 temp; + PRBool suite_found = PR_FALSE; + int i; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; - PRUint32 compression; SECStatus rv; SECItem sidBytes = { siBuffer, NULL, 0 }; - PRBool isHelloRetry; + PRBool isTLS = PR_FALSE; SSL3AlertDescription desc = illegal_parameter; - TLSExtension *versionExtension; - const PRUint8 *savedMsg = b; - const PRUint32 savedLength = length; #ifndef TLS_1_3_DRAFT_VERSION SSL3ProtocolVersion downgradeCheckVersion; #endif @@ -6155,6 +6608,7 @@ 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; @@ -6176,95 +6630,11 @@ 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) { @@ -6287,10 +6657,18 @@ 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 = protocol_version; + desc = illegal_parameter; 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 @@ -6310,8 +6688,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. */ - PRUint8 *downgrade_sentinel = - ss->ssl3.hs.server_random + + unsigned char *downgrade_sentinel = + ss->ssl3.hs.server_random.rand + SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); if (!PORT_Memcmp(downgrade_sentinel, tls13_downgrade_random, @@ -6326,64 +6704,110 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) } #endif - /* 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 (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 */ } - 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; + if (sidBytes.len > SSL3_SESSIONID_BYTES) { + if (isTLS) + desc = decode_error; + goto alert_loser; /* malformed. */ } } - /* Only initialize hashes if this isn't a Hello Retry. */ - rv = ssl_ClientSetCipherSuite(ss, ss->version, cipher, - !isHelloRetry); + /* find selected cipher suite in our list. */ + rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &b, &length); if (rv != SECSuccess) { - desc = illegal_parameter; + goto loser; /* alert has been sent */ + } + i = ssl3_config_match_init(ss); + PORT_Assert(i > 0); + if (i <= 0) { errCode = PORT_GetError(); - goto alert_loser; + goto 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; + } - dtls_ReceivedFirstMessageInFlight(ss); + break; /* failure */ + } - if (isHelloRetry) { - rv = tls13_HandleHelloRetryRequest(ss, savedMsg, savedLength); - if (rv != SECSuccess) { - goto loser; + suite_found = PR_TRUE; + break; /* success */ } - return SECSuccess; + } + if (!suite_found) { + desc = handshake_failure; + errCode = SSL_ERROR_NO_CYPHER_OVERLAP; + goto alert_loser; } - rv = ssl3_HandleParsedExtensions(ss, ssl_hs_server_hello); - ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); + rv = ssl3_SetCipherSuite(ss, (ssl3CipherSuite)temp, PR_TRUE); if (rv != SECSuccess) { + desc = internal_error; + errCode = PORT_GetError(); 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) { + /* 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; + } } if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { @@ -6411,51 +6835,6 @@ 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) { @@ -6481,7 +6860,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_SetupBothPendingCipherSpecs(ss); + rv = ssl3_SetupPendingCipherSpec(ss); if (rv != SECSuccess) { goto alert_loser; /* error code is set. */ } @@ -6504,7 +6883,9 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, goto alert_loser; } do { - PK11SymKey *masterSecret; + ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; + + SECItem wrappedMS; /* wrapped master secret. */ /* [draft-ietf-tls-session-hash-06; Section 5.3] * @@ -6536,12 +6917,60 @@ 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; - rv = ssl3_UnwrapMasterSecretClient(ss, sid, &masterSecret); - if (rv != SECSuccess) { - break; /* not considered an error */ + 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; + } } /* Got a Match */ @@ -6563,8 +6992,8 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); } - /* We are re-using the old MS, so no need to derive again. */ - rv = ssl3_InitPendingCipherSpecs(ss, masterSecret, PR_FALSE); + /* NULL value for PMS because we are reusing the old MS */ + rv = ssl3_InitPendingCipherSpec(ss, NULL); if (rv != SECSuccess) { goto alert_loser; /* err code was set */ } @@ -6669,11 +7098,11 @@ ssl_HandleDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) } rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH); - if (rv != SECSuccess || minDH <= 0) { + if (rv != SECSuccess) { minDH = SSL_DH_MIN_P_BITS; } dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p); - if (dh_p_bits < (unsigned)minDH) { + if (dh_p_bits < minDH) { errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY; goto alert_loser; } @@ -6854,7 +7283,7 @@ typedef struct dnameNode { */ SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, - CERTDistNames *ca_list) + PLArenaPool *arena, CERTDistNames *ca_list) { PRUint32 remaining; int nnames = 0; @@ -6869,7 +7298,7 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, if (remaining > *length) goto alert_loser; - ca_list->head = node = PORT_ArenaZNew(ca_list->arena, dnameNode); + ca_list->head = node = PORT_ArenaZNew(arena, dnameNode); if (node == NULL) goto no_mem; @@ -6895,14 +7324,14 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, if (remaining <= 0) break; /* success */ - node->next = PORT_ArenaZNew(ca_list->arena, dnameNode); + node->next = PORT_ArenaZNew(arena, dnameNode); node = node->next; if (node == NULL) goto no_mem; } ca_list->nnames = nnames; - ca_list->names = PORT_ArenaNewArray(ca_list->arena, SECItem, nnames); + ca_list->names = PORT_ArenaNewArray(arena, SECItem, nnames); if (nnames > 0 && ca_list->names == NULL) goto no_mem; @@ -7046,7 +7475,7 @@ ssl3_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) } } - rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, &ca_list); + rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list); if (rv != SECSuccess) goto done; /* alert sent in ssl3_ParseCertificateRequestCAs */ @@ -7146,7 +7575,7 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss, case SECFailure: default: send_no_certificate: - if (ss->version > SSL_LIBRARY_VERSION_3_0) { + if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { ss->ssl3.sendEmptyCert = PR_TRUE; } else { (void)SSL3_SendAlert(ss, alert_warning, no_certificate); @@ -7177,7 +7606,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->cipherDef->secret_key_size >= 10; + maybeFalseStart = ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10; ssl_ReleaseSpecReadLock(ss); if (!maybeFalseStart) { @@ -7429,7 +7858,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, ssl_hs_hello_request, 0); + rv = ssl3_AppendHandshakeHeader(ss, hello_request, 0); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake */ } @@ -7498,7 +7927,6 @@ 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; @@ -7609,8 +8037,8 @@ SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites, PRBool initHashes) { - unsigned int j; - unsigned int i; + int j; + int i; for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; @@ -7621,8 +8049,7 @@ 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) { - ss->ssl3.hs.cipher_suite = suite_i; - return ssl3_SetupCipherSuite(ss, initHashes); + return ssl3_SetCipherSuite(ss, suite_i, initHashes); } } } @@ -7721,6 +8148,7 @@ 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. */ @@ -7749,7 +8177,8 @@ ssl3_ServerCallSNICallback(sslSocket *ss) ret = SSL_SNI_SEND_ALERT; break; } - if (ssl3_config_match_init(ss) == 0) { + configedCiphers = ssl3_config_match_init(ss); + if (configedCiphers <= 0) { /* no ciphers are working/supported */ errCode = PORT_GetError(); desc = handshake_failure; @@ -7760,7 +8189,7 @@ ssl3_ServerCallSNICallback(sslSocket *ss) * the name from the offered list and reconfigured the socket. */ ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn, - ssl_SendEmptyExtension); + ssl3_SendServerNameXtn); } else { /* Callback returned index outside of the boundary. */ PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize); @@ -7859,14 +8288,13 @@ 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 || @@ -7891,9 +8319,6 @@ 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) { @@ -7903,7 +8328,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, ss); + ssl3_ResetExtensionData(&ss->xtnData); ss->statelessResume = PR_FALSE; if (IS_DTLS(ss)) { @@ -7924,7 +8349,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 */ } @@ -7941,9 +8366,6 @@ 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. */ @@ -7967,15 +8389,14 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) if (length) { /* Get length of hello extensions */ - PRUint32 extensionLength; - rv = ssl3_ConsumeHandshakeNumber(ss, &extensionLength, 2, &b, &length); + PRUint32 extension_length; + rv = ssl3_ConsumeHandshakeNumber(ss, &extension_length, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* alert already sent */ } - if (extensionLength != length) { - errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; - desc = decode_error; - goto alert_loser; + if (extension_length != length) { + ssl3_DecodeError(ss); /* send alert */ + goto loser; } rv = ssl3_ParseExtensions(ss, &b, &length); @@ -8006,35 +8427,17 @@ 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); - } - 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; - } + /* You can't resume TLS 1.3 like this. */ + if (isTLS13 && sidBytes.len) { + 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; @@ -8060,8 +8463,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) { - PRUint8 *downgrade_sentinel = - ss->ssl3.hs.server_random + + unsigned char *downgrade_sentinel = + ss->ssl3.hs.server_random.rand + SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random); switch (ss->vrange.max) { @@ -8082,25 +8485,8 @@ 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, ssl_hs_client_hello); - ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); + rv = ssl3_HandleParsedExtensions(ss, client_hello); if (rv != SECSuccess) { goto loser; /* malformed */ } @@ -8123,12 +8509,6 @@ 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)) { @@ -8141,30 +8521,34 @@ 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, ssl_hs_client_hello); + (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello); break; } } } - - /* 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; - } + /* 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; } /* We do stateful resumes only if we are in TLS < 1.3 and @@ -8237,14 +8621,21 @@ 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, savedMsg, savedLen); + rv = tls13_HandleClientHelloPart2(ss, &suites, sid); } else { - rv = ssl3_HandleClientHelloPart2(ss, &suites, sid, - savedMsg, savedLen); + rv = ssl3_HandleClientHelloPart2(ss, &suites, &comps, sid); } if (rv != SECSuccess) { errCode = PORT_GetError(); @@ -8261,60 +8652,22 @@ 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, - sslSessionID *sid, - const PRUint8 *msg, - unsigned int len) + SECItem *comps, + sslSessionID *sid) { + 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; - unsigned int j; + int j; - 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 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. */ if (sid) do { @@ -8323,6 +8676,18 @@ 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) { @@ -8330,7 +8695,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, @@ -8349,15 +8714,17 @@ 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) { - ss->ssl3.hs.cipher_suite = suite_i; - rv = ssl3_SetupCipherSuite(ss, PR_TRUE); + rv = ssl3_SetCipherSuite(ss, suite_i, PR_TRUE); if (rv != SECSuccess) { desc = internal_error; errCode = PORT_GetError(); goto alert_loser; } - goto cipher_found; + /* Use the cached compression method. */ + ss->ssl3.hs.compression = + sid->u.ssl3.compression; + goto compression_found; } } } while (0); @@ -8365,7 +8732,8 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, #ifndef PARANOID /* Look for a matching cipher suite. */ - if (ssl3_config_match_init(ss) == 0) { + j = ssl3_config_match_init(ss); + if (j <= 0) { /* no ciphers are working/supported by PK11 */ desc = internal_error; errCode = PORT_GetError(); /* error code is already set. */ goto alert_loser; @@ -8379,8 +8747,25 @@ ssl3_HandleClientHelloPart2(sslSocket *ss, goto alert_loser; } -cipher_found: + /* 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: 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 @@ -8390,10 +8775,12 @@ cipher_found: */ if (sid != NULL) do { - PK11SymKey *masterSecret; + ssl3CipherSpec *pwSpec; + SECItem wrappedMS; /* wrapped key */ if (sid->version != ss->version || - sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite) { + sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite || + sid->u.ssl3.compression != ss->ssl3.hs.compression) { break; /* not an error */ } @@ -8442,13 +8829,54 @@ cipher_found: } ss->sec.ci.sid = NULL; } - /* we need to resurrect the master secret.... */ - rv = ssl3_UnwrapMasterSecretServer(ss, sid, &masterSecret); - if (rv != SECSuccess) { - break; /* not an error */ - } + 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 */ + } + } ss->sec.ci.sid = sid; if (sid->peerCert != NULL) { ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); @@ -8456,6 +8884,8 @@ cipher_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) @@ -8466,8 +8896,6 @@ cipher_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); @@ -8502,8 +8930,13 @@ cipher_found: goto loser; } - /* We are re-using the old MS, so no need to derive again. */ - rv = ssl3_InitPendingCipherSpecs(ss, masterSecret, PR_FALSE); + 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); if (rv != SECSuccess) { errCode = PORT_GetError(); goto loser; @@ -8528,8 +8961,12 @@ cipher_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); @@ -8548,8 +8985,9 @@ cipher_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, - ssl_SendEmptyExtension); + ssl3_RegisterExtensionSender(ss, &ss->xtnData, + ssl_session_ticket_xtn, + ssl3_SendSessionTicketXtn); } rv = ssl3_ServerCallSNICallback(ss); @@ -8593,6 +9031,10 @@ cipher_found: return SECSuccess; alert_loser: + if (haveSpecWriteLock) { + ssl_ReleaseSpecWriteLock(ss); + haveSpecWriteLock = PR_FALSE; + } (void)SSL3_SendAlert(ss, alert_fatal, desc); /* FALLTHRU */ loser: @@ -8601,6 +9043,10 @@ loser: ssl_FreeSID(sid); } + if (haveSpecWriteLock) { + ssl_ReleaseSpecWriteLock(ss); + } + if (haveXmitBufLock) { ssl_ReleaseXmitBufLock(ss); } @@ -8614,7 +9060,7 @@ loser: * in asking to use the V3 handshake. */ SECStatus -ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int length, +ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, PRUint8 padding) { sslSessionID *sid = NULL; @@ -8622,11 +9068,11 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng unsigned char *random; SSL3ProtocolVersion version; SECStatus rv; - unsigned int i; - unsigned int j; - unsigned int sid_length; - unsigned int suite_length; - unsigned int rand_length; + int i; + int j; + int sid_length; + int suite_length; + int rand_length; int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; SSL3AlertDescription desc = handshake_failure; unsigned int total = SSL_HL_CLIENT_HELLO_HBYTES; @@ -8637,11 +9083,14 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng 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) { @@ -8673,11 +9122,6 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng 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) { @@ -8700,14 +9144,15 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng 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[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.rand[SSL3_RANDOM_LENGTH - rand_length], + random, rand_length); - PRINT_BUF(60, (ss, "client random:", ss->ssl3.hs.client_random, + PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0], SSL3_RANDOM_LENGTH)); - - if (ssl3_config_match_init(ss) == 0) { + i = ssl3_config_match_init(ss); + if (i <= 0) { errCode = PORT_GetError(); /* error code is already set. */ goto alert_loser; } @@ -8716,6 +9161,8 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng ** ** 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]; @@ -8726,8 +9173,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, unsigned int leng 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) { - ss->ssl3.hs.cipher_suite = suite_i; - rv = ssl3_SetupCipherSuite(ss, PR_TRUE); + rv = ssl3_SetCipherSuite(ss, suite_i, PR_TRUE); if (rv != SECSuccess) { desc = internal_error; errCode = PORT_GetError(); @@ -8763,7 +9209,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, ssl_hs_client_hello); + (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello); break; } } @@ -8775,6 +9221,8 @@ suite_found: goto alert_loser; } + ss->ssl3.hs.compression = ssl_compression_null; + rv = ssl3_SelectServerCert(ss); if (rv != SECSuccess) { errCode = PORT_GetError(); @@ -8818,64 +9266,6 @@ 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), @@ -8885,9 +9275,12 @@ ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry, SECStatus ssl3_SendServerHello(sslSocket *ss) { + sslSessionID *sid; SECStatus rv; - sslBuffer extensionBuf = SSL_BUFFER_EMPTY; - sslBuffer messageBuf = SSL_BUFFER_EMPTY; + PRUint32 maxBytes = 65535; + PRUint32 length; + PRInt32 extensions_len = 0; + SSL3ProtocolVersion version; SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(), ss->fd)); @@ -8901,43 +9294,94 @@ ssl3_SendServerHello(sslSocket *ss) return SECFailure; } - rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_server_hello); - if (rv != SECSuccess) { - goto loser; + 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 = ssl_ConstructServerHello(ss, PR_FALSE, &extensionBuf, &messageBuf); + rv = ssl3_AppendHandshakeHeader(ss, server_hello, length); if (rv != SECSuccess) { - goto loser; + 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); } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello, - SSL_BUFFER_LEN(&messageBuf)); + rv = ssl3_AppendHandshakeNumber(ss, version, 2); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + 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. */ } - rv = ssl3_AppendHandshake(ss, SSL_BUFFER_BASE(&messageBuf), - SSL_BUFFER_LEN(&messageBuf)); + 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. */ + } + } + + rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + 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. */ + } + } + 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; + } } if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - rv = ssl3_SetupBothPendingCipherSpecs(ss); + rv = ssl3_SetupPendingCipherSpec(ss); if (rv != SECSuccess) { - goto loser; /* err set */ + return rv; /* err set by ssl3_SetupPendingCipherSpec */ } } - sslBuffer_Clear(&extensionBuf); - sslBuffer_Clear(&messageBuf); return SECSuccess; - -loser: - sslBuffer_Clear(&extensionBuf); - sslBuffer_Clear(&messageBuf); - return SECFailure; } SECStatus @@ -8994,8 +9438,6 @@ 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. @@ -9019,7 +9461,7 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) } PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs); - if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->ssl3.pwSpec->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. */ @@ -9051,11 +9493,11 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) 2 + pubKey->u.dh.prime.len + 2 + signed_hash.len; - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { length += 2; } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length); + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } @@ -9072,16 +9514,12 @@ ssl3_SendDHServerKeyExchange(sslSocket *ss) goto loser; /* err set by AppendHandshake. */ } - rv = ssl_AppendPaddedDHKeyShare(&dhBuf, pubKey, PR_TRUE); - if (rv != SECSuccess) { - goto loser; /* err set by AppendPaddedDHKeyShare. */ - } - rv = ssl3_AppendBufferToHandshake(ss, &dhBuf); + rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_TRUE); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->ssl3.pwSpec->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. */ @@ -9093,15 +9531,12 @@ 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; } @@ -9136,15 +9571,14 @@ ssl3_SendServerKeyExchange(sslSocket *ss) } SECStatus -ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf) +ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 *len) { - unsigned int lengthOffset; unsigned int i; - PRBool found = PR_FALSE; - SECStatus rv; + PRUint8 *p = buf; - rv = sslBuffer_Skip(buf, 2, &lengthOffset); - if (rv != SECSuccess) { + PORT_Assert(maxLen >= ss->ssl3.signatureSchemeCount * 2); + if (maxLen < ss->ssl3.signatureSchemeCount * 2) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } @@ -9162,21 +9596,16 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf) if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) || (policy & NSS_USE_ALG_IN_SSL_KX)) { - rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2); - if (rv != SECSuccess) { - return SECFailure; - } - - found = PR_TRUE; + p = ssl_EncodeUintX((PRUint32)ss->ssl3.signatureSchemes[i], 2, p); } } - if (!found) { + if (p == buf) { PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM); return SECFailure; } - - return sslBuffer_InsertLength(buf, lengthOffset, 2); + *len = p - buf; + return SECSuccess; } static SECStatus @@ -9185,15 +9614,15 @@ ssl3_SendCertificateRequest(sslSocket *ss) PRBool isTLS12; const PRUint8 *certTypes; SECStatus rv; - PRUint32 length; - const SECItem *names; + int length; + SECItem *names; unsigned int calen; unsigned int nnames; - const SECItem *name; - unsigned int i; + SECItem *name; + int i; int certTypesLength; - PRUint8 sigAlgs[2 + MAX_SIGNATURE_SCHEMES * 2]; - sslBuffer sigAlgsBuf = SSL_BUFFER(sigAlgs); + PRUint8 sigAlgs[MAX_SIGNATURE_SCHEMES * 2]; + unsigned int sigAlgsLength = 0; SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake", SSL_GETPID(), ss->fd)); @@ -9201,7 +9630,7 @@ ssl3_SendCertificateRequest(sslSocket *ss) PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); + isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames); if (rv != SECSuccess) { @@ -9212,14 +9641,14 @@ ssl3_SendCertificateRequest(sslSocket *ss) length = 1 + certTypesLength + 2 + calen; if (isTLS12) { - rv = ssl3_EncodeSigAlgs(ss, &sigAlgsBuf); + rv = ssl3_EncodeSigAlgs(ss, sigAlgs, sizeof(sigAlgs), &sigAlgsLength); if (rv != SECSuccess) { return rv; } - length += SSL_BUFFER_LEN(&sigAlgsBuf); + length += 2 + sigAlgsLength; } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request, length); + rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -9228,8 +9657,7 @@ ssl3_SendCertificateRequest(sslSocket *ss) return rv; /* err set by AppendHandshake. */ } if (isTLS12) { - rv = ssl3_AppendHandshake(ss, SSL_BUFFER_BASE(&sigAlgsBuf), - SSL_BUFFER_LEN(&sigAlgsBuf)); + rv = ssl3_AppendHandshakeVariable(ss, sigAlgs, sigAlgsLength, 2); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -9259,7 +9687,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, ssl_hs_server_hello_done, 0); + rv = ssl3_AppendHandshakeHeader(ss, server_hello_done, 0); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -9275,7 +9703,8 @@ ssl3_SendServerHelloDone(sslSocket *ss) * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) +ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, + SSL3Hashes *hashes) { SECItem signed_hash = { siBuffer, NULL, 0 }; SECStatus rv; @@ -9283,9 +9712,9 @@ ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) SSL3AlertDescription desc = handshake_failure; PRBool isTLS; SSLSignatureScheme sigScheme; - SSL3Hashes hashes; - const PRUint8 *savedMsg = b; - const PRUint32 savedLen = length; + SSLHashType hashAlg; + SSL3Hashes localHashes; + SSL3Hashes *hashesForVerify = NULL; SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake", SSL_GETPID(), ss->fd)); @@ -9301,8 +9730,14 @@ 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 (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) { - PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_record); + if (!hashes) { + PORT_Assert(0); + desc = internal_error; + errCode = SEC_ERROR_LIBRARY_FAILURE; + goto alert_loser; + } + + if (ss->ssl3.hs.hashType == handshake_hash_record) { rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); if (rv != SECSuccess) { goto loser; /* malformed or unsupported. */ @@ -9315,20 +9750,25 @@ 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, - ss->ssl3.hs.messages.len, - ssl_SignatureSchemeToHashType(sigScheme), - &hashes); + hashes->u.transcriptLen, + hashAlg, &localHashes); + + if (rv == SECSuccess) { + hashesForVerify = &localHashes; + } else { + errCode = SSL_ERROR_DIGEST_FAILURE; + desc = decrypt_error; + goto alert_loser; + } } else { - PORT_Assert(ss->ssl3.hs.hashType != handshake_hash_record); + hashesForVerify = hashes; 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); @@ -9339,7 +9779,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, &hashes, &signed_hash); + rv = ssl3_VerifySignedHashes(ss, sigScheme, hashesForVerify, &signed_hash); if (rv != SECSuccess) { errCode = PORT_GetError(); desc = isTLS ? decrypt_error : handshake_failure; @@ -9352,14 +9792,6 @@ 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; @@ -9400,9 +9832,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->epoch == ss->ssl3.pwSpec->epoch); + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - calg = spec->cipherDef->calg; + calg = spec->cipher_def->calg; /* First get an appropriate slot. */ mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN; @@ -9470,7 +9902,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->epoch == ss->ssl3.pwSpec->epoch); + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); enc_pms.data = b; enc_pms.len = length; @@ -9567,7 +9999,7 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, } /* This step will derive the MS from the PMS, among other things. */ - rv = ssl3_InitPendingCipherSpecs(ss, currentPms, PR_TRUE); + rv = ssl3_InitPendingCipherSpec(ss, currentPms); PK11_FreeSymKey(currentPms); if (rv != SECSuccess) { @@ -9632,7 +10064,7 @@ ssl3_HandleDHClientKeyExchange(sslSocket *ss, return SECFailure; } - rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); + rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); ssl_FreeEphemeralKeyPairs(ss); return rv; @@ -9731,13 +10163,13 @@ ssl3_SendEmptyCertificate(sslSocket *ss) const SECItem *context; if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - PORT_Assert(ss->ssl3.hs.clientCertRequested); - context = &ss->xtnData.certReqContext; + PORT_Assert(ss->ssl3.hs.certificateRequest); + context = &ss->ssl3.hs.certificateRequest->context; len = context->len + 1; isTLS13 = PR_TRUE; } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate, len + 3); + rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3); if (rv != SECSuccess) { return rv; } @@ -9763,14 +10195,13 @@ ssl3_SendNewSessionTicket(sslSocket *ss) SECStatus rv; NewSessionTicket nticket = { 0 }; - rv = ssl3_EncodeSessionTicket(ss, &nticket, NULL, 0, - ss->ssl3.pwSpec->masterSecret, &ticket); + rv = ssl3_EncodeSessionTicket(ss, &nticket, &ticket); if (rv != SECSuccess) goto loser; /* Serialize the handshake message. Length = * lifetime (4) + ticket length (2) + ticket. */ - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_new_session_ticket, + rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, 4 + 2 + ticket.len); if (rv != SECSuccess) goto loser; @@ -9820,7 +10251,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 = ssl_TimeUsec(); + ss->ssl3.hs.newSessionTicket.received_timestamp = PR_Now(); if (length < 4) { (void)SSL3_SendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); @@ -9962,8 +10393,8 @@ ssl3_SendCertificate(sslSocket *ss) if (isTLS13) { contextLen = 1; /* Size of the context length */ if (!ss->sec.isServer) { - PORT_Assert(ss->ssl3.hs.clientCertRequested); - context = ss->xtnData.certReqContext; + PORT_Assert(ss->ssl3.hs.certificateRequest); + context = ss->ssl3.hs.certificateRequest->context; contextLen += context.len; } } @@ -9981,7 +10412,7 @@ ssl3_SendCertificate(sslSocket *ss) } } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate, + rv = ssl3_AppendHandshakeHeader(ss, certificate, contextLen + certChainLen + 3); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ @@ -10056,7 +10487,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, ssl_hs_certificate_status, len); + rv = ssl3_AppendHandshakeHeader(ss, certificate_status, len); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -10187,10 +10618,6 @@ ssl3_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECFailure; } - if (ss->sec.isServer) { - dtls_ReceivedFirstMessageInFlight(ss); - } - return ssl3_CompleteHandleCertificate(ss, b, length); } @@ -10410,8 +10837,7 @@ ssl3_AuthCertificate(sslSocket *ss) } if (pubKey) { KeyType pubKeyType; - PRUint32 minKey; - PRInt32 optval; + PRInt32 minKey; /* This partly fixes Bug 124230 and may cause problems for * callers which depend on the old (wrong) behavior. */ ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); @@ -10422,29 +10848,29 @@ ssl3_AuthCertificate(sslSocket *ss) case rsaPssKey: case rsaOaepKey: rv = - NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &optval); - if (rv == SECSuccess && optval > 0) { - minKey = (PRUint32)optval; - } else { - minKey = SSL_RSA_MIN_MODULUS_BITS; + NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minKey); + if (rv != + SECSuccess) { + minKey = + SSL_RSA_MIN_MODULUS_BITS; } break; case dsaKey: rv = - NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &optval); - if (rv == SECSuccess && optval > 0) { - minKey = (PRUint32)optval; - } else { - minKey = SSL_DSA_MIN_P_BITS; + NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &minKey); + if (rv != + SECSuccess) { + minKey = + SSL_DSA_MIN_P_BITS; } break; case dhKey: rv = - NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &optval); - if (rv == SECSuccess && optval > 0) { - minKey = (PRUint32)optval; - } else { - minKey = SSL_DH_MIN_P_BITS; + NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minKey); + if (rv != + SECSuccess) { + minKey = + SSL_DH_MIN_P_BITS; } break; default: @@ -10603,8 +11029,8 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec, PK11Context *prf_context; unsigned int retLen; - PORT_Assert(spec->masterSecret); - if (!spec->masterSecret) { + PORT_Assert(spec->master_secret); + if (!spec->master_secret) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } @@ -10619,7 +11045,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->masterSecret, ¶m); + spec->master_secret, ¶m); if (!prf_context) return SECFailure; @@ -10644,39 +11070,40 @@ ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec, const unsigned char *val, unsigned int valLen, unsigned char *out, unsigned int outLen) { - SECItem param = { siBuffer, NULL, 0 }; - CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL; - PK11Context *prf_context; - unsigned int retLen; - SECStatus rv; + SECStatus rv = SECSuccess; - if (!spec->masterSecret) { - PORT_Assert(spec->masterSecret); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } + 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->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; + 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; } - mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; - } - prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, - spec->masterSecret, ¶m); - if (!prf_context) - return SECFailure; + prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, + spec->master_secret, ¶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); + PK11_DestroyContext(prf_context, PR_TRUE); + } else { + PORT_Assert(spec->master_secret); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + } return rv; } @@ -10700,7 +11127,7 @@ ssl3_SendNextProto(sslSocket *ss) padding_len = 32 - ((ss->xtnData.nextProto.len + 2) % 32); - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_next_proto, ss->xtnData.nextProto.len + 2 + padding_len); + rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len + 2 + padding_len); if (rv != SECSuccess) { return rv; /* error code set by AppendHandshakeHeader */ } @@ -10716,44 +11143,40 @@ ssl3_SendNextProto(sslSocket *ss) return rv; } -/* called from ssl3_SendFinished and tls13_DeriveSecret. +/* called from ssl3_SendFinished * * This function is simply a debugging aid and therefore does not return a * SECStatus. */ -void -ssl3_RecordKeyLog(sslSocket *ss, const char *label, PK11SymKey *secret) +static void +ssl3_RecordKeyLog(sslSocket *ss) { #ifdef NSS_ALLOW_SSLKEYLOGFILE SECStatus rv; SECItem *keyData; - /* 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; + char buf[14 /* "CLIENT_RANDOM " */ + + SSL3_RANDOM_LENGTH * 2 /* client_random */ + + 1 /* " " */ + + 48 * 2 /* master secret */ + + 1 /* new line */]; + unsigned int j; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); if (!ssl_keylog_iob) return; - rv = PK11_ExtractKeyValue(secret); + rv = PK11_ExtractKeyValue(ss->ssl3.cwSpec->master_secret); if (rv != SECSuccess) return; - /* keyData does not need to be freed. */ - keyData = PK11_GetKeyData(secret); - if (!keyData || !keyData->data) - return; + ssl_GetSpecReadLock(ss); - 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)) + /* 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); return; + } /* https://developer.mozilla.org/en/NSS_Key_Log_Format */ @@ -10761,22 +11184,23 @@ ssl3_RecordKeyLog(sslSocket *ss, const char *label, PK11SymKey *secret) * keylog, so we have to do everything in a single call to * fwrite. */ - 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); + 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; #endif } @@ -10818,7 +11242,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, ssl_hs_finished, sizeof tlsFinished); + rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof tlsFinished); if (rv != SECSuccess) goto fail; /* err set by AppendHandshake. */ rv = ssl3_AppendHandshake(ss, &tlsFinished, sizeof tlsFinished); @@ -10831,7 +11255,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, ssl_hs_finished, sizeof hashes.u.s); + rv = ssl3_AppendHandshakeHeader(ss, 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); @@ -10843,7 +11267,7 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) goto fail; /* error code set by ssl3_FlushHandshake */ } - ssl3_RecordKeyLog(ss, "CLIENT_RANDOM", ss->ssl3.cwSpec->masterSecret); + ssl3_RecordKeyLog(ss); return SECSuccess; @@ -10855,8 +11279,8 @@ fail: * Caller holds the Spec read lock. */ SECStatus -ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid, - PK11SymKey *secret) +ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, + ssl3CipherSpec *spec) { PK11SymKey *wrappingKey = NULL; PK11SlotInfo *symKeySlot; @@ -10865,7 +11289,7 @@ ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid, PRBool isServer = ss->sec.isServer; CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; - symKeySlot = PK11_GetSlotFromKey(secret); + symKeySlot = PK11_GetSlotFromKey(spec->master_secret); if (!isServer) { int wrapKeyIndex; int incarnation; @@ -10926,7 +11350,7 @@ ssl3_CacheWrappedSecret(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, - secret, &wmsItem); + spec->master_secret, &wmsItem); /* rv is examined below. */ sid->u.ssl3.keys.wrapped_master_secret_len = wmsItem.len; PK11_FreeSymKey(wrappingKey); @@ -10939,13 +11363,13 @@ ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid, * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) +ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, + const SSL3Hashes *hashes) { 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)); @@ -10959,23 +11383,13 @@ ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECFailure; } - 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) { + if (!hashes) { + PORT_Assert(0); + SSL3_SendAlert(ss, alert_fatal, internal_error); 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; @@ -10988,7 +11402,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 @@ -11011,12 +11425,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; @@ -11086,7 +11500,7 @@ xmit_loser: } if (sid->cached == never_cached && !ss->opt.noCache) { - rv = ssl3_FillInCachedSID(ss, sid, ss->ssl3.crSpec->masterSecret); + rv = ssl3_FillInCachedSID(ss, sid); /* If the wrap failed, we don't cache the sid. * The connection continues normally however. @@ -11110,26 +11524,21 @@ xmit_loser: } SECStatus -ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret) +ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) { - PORT_Assert(secret); + SECStatus rv; /* 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; - 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->lastAccessTime = sid->creationTime = ssl_Time(); + sid->expirationTime = sid->creationTime + ssl3_sid_timeout; sid->localCert = CERT_DupCertificate(ss->sec.localCert); if (ss->sec.isServer) { sid->namedCurve = ss->sec.serverCert->namedCurve; @@ -11143,8 +11552,25 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret) } } + ssl_GetSpecReadLock(ss); /*************************************/ + /* Copy the master secret (wrapped or unwrapped) into the sid */ - return ssl3_CacheWrappedSecret(ss, ss->sec.ci.sid, secret); + 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; } /* The return type is SECStatus instead of void because this function needs @@ -11193,66 +11619,8 @@ 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 - * handshake message. + * hanshake message. * Caller must hold Handshake and RecvBuf locks. */ SECStatus @@ -11260,43 +11628,130 @@ 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))); - /* Start new handshake hashes when we start a new handshake. */ - if (ss->ssl3.hs.msg_type == ssl_hs_client_hello) { + 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) { ssl3_RestartHandshakeHashes(ss); } - 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; + /* 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. */ - /* 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; + /* 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); - default: - rv = ssl_HashHandshakeMessage(ss, ss->ssl3.hs.msg_type, b, length); - if (rv != SECSuccess) { - return SECFailure; - } + /* 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. */ } PORT_SetError(0); /* each message starts with no error. */ if (ss->ssl3.hs.ws == wait_certificate_status && - ss->ssl3.hs.msg_type != ssl_hs_certificate_status) { + ss->ssl3.hs.msg_type != 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 @@ -11313,7 +11768,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, epoch = ss->ssl3.crSpec->epoch; switch (ss->ssl3.hs.msg_type) { - case ssl_hs_client_hello: + case client_hello: if (!ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO); @@ -11321,7 +11776,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, } rv = ssl3_HandleClientHello(ss, b, length); break; - case ssl_hs_server_hello: + case server_hello: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO); @@ -11331,9 +11786,10 @@ 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); + rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length, hashesPtr); } else { - rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length); + rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length, + hashesPtr); } break; } @@ -11355,13 +11811,13 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, - PRUint32 length) + PRUint32 length, SSL3Hashes *hashesPtr) { SECStatus rv; PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); switch (ss->ssl3.hs.msg_type) { - case ssl_hs_hello_request: + case hello_request: if (length != 0) { (void)ssl3_DecodeError(ss); PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST); @@ -11375,7 +11831,13 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, rv = ssl3_HandleHelloRequest(ss); break; - case ssl_hs_hello_verify_request: + 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: if (!IS_DTLS(ss) || ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST); @@ -11383,13 +11845,13 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = dtls_HandleHelloVerifyRequest(ss, b, length); break; - case ssl_hs_certificate: + case certificate: rv = ssl3_HandleCertificate(ss, b, length); break; - case ssl_hs_certificate_status: + case certificate_status: rv = ssl3_HandleCertificateStatus(ss, b, length); break; - case ssl_hs_server_key_exchange: + case server_key_exchange: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH); @@ -11397,7 +11859,7 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleServerKeyExchange(ss, b, length); break; - case ssl_hs_certificate_request: + case certificate_request: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST); @@ -11405,7 +11867,7 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleCertificateRequest(ss, b, length); break; - case ssl_hs_server_hello_done: + case server_hello_done: if (length != 0) { (void)ssl3_DecodeError(ss); PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_DONE); @@ -11418,15 +11880,15 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleServerHelloDone(ss); break; - case ssl_hs_certificate_verify: + case 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); + rv = ssl3_HandleCertificateVerify(ss, b, length, hashesPtr); break; - case ssl_hs_client_key_exchange: + case client_key_exchange: if (!ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH); @@ -11434,7 +11896,7 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleClientKeyExchange(ss, b, length); break; - case ssl_hs_new_session_ticket: + case new_session_ticket: if (ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET); @@ -11442,8 +11904,8 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, } rv = ssl3_HandleNewSessionTicket(ss, b, length); break; - case ssl_hs_finished: - rv = ssl3_HandleFinished(ss, b, length); + case finished: + rv = ssl3_HandleFinished(ss, b, length, hashesPtr); break; default: (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); @@ -11484,7 +11946,7 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) t = *(buf->buf++); buf->len--; if (ss->ssl3.hs.header_bytes++ == 0) - ss->ssl3.hs.msg_type = (SSLHandshakeType)t; + ss->ssl3.hs.msg_type = (SSL3HandshakeType)t; else ss->ssl3.hs.msg_len = (ss->ssl3.hs.msg_len << 8) + t; if (ss->ssl3.hs.header_bytes < 4) @@ -11814,34 +12276,31 @@ ssl_CBCExtractMAC(sslBuffer *plaintext, * */ static SECStatus -ssl3_UnprotectRecord(sslSocket *ss, - ssl3CipherSpec *spec, - SSL3Ciphertext *cText, sslBuffer *plaintext, +ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, SSL3AlertDescription *alert) { - const ssl3BulkCipherDef *cipher_def = spec->cipherDef; + ssl3CipherSpec *crSpec = ss->ssl3.crSpec; + const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def; PRBool isTLS; unsigned int good; unsigned int ivLen = 0; SSL3ContentType rType; unsigned int minLength; unsigned int originalLen = 0; - PRUint8 headerBuf[13]; - sslBuffer header = SSL_BUFFER(headerBuf); + unsigned char header[13]; + unsigned int headerLen; 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 = spec->macDef->mac_size; + minLength = crSpec->mac_size; if (cipher_def->type == type_block) { /* CBC records have a padding length byte at the end. */ minLength++; - if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { + if (crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { /* With >= TLS 1.1, CBC records have an explicit IV. */ minLength += cipher_def->iv_size; } @@ -11856,7 +12315,7 @@ ssl3_UnprotectRecord(sslSocket *ss, } if (cipher_def->type == type_block && - spec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { + crSpec->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 @@ -11879,8 +12338,8 @@ ssl3_UnprotectRecord(sslSocket *ss, * the block it doesn't matter. The decryption of the next block * depends only on the ciphertext of the IV block. */ - rv = spec->cipher(spec->cipherContext, iv, &decoded, - sizeof(iv), cText->buf->buf, ivLen); + rv = crSpec->decode(crSpec->decodeContext, iv, &decoded, + sizeof(iv), cText->buf->buf, ivLen); good &= SECStatusToMask(rv); } @@ -11888,7 +12347,7 @@ ssl3_UnprotectRecord(sslSocket *ss, PRINT_BUF(80, (ss, "ciphertext:", cText->buf->buf + ivLen, cText->buf->len - ivLen)); - isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0); if (isTLS && cText->buf->len - ivLen > (MAX_FRAGMENT_LENGTH + 2048)) { *alert = record_overflow; @@ -11905,18 +12364,19 @@ ssl3_UnprotectRecord(sslSocket *ss, unsigned int decryptedLen = cText->buf->len - cipher_def->explicit_nonce_size - cipher_def->tag_size; - rv = ssl3_BuildRecordPseudoHeader( - spec->epoch, IS_DTLS(ss) ? cText->seq_num : spec->seqNum, - rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen, &header); - 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)); + 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); if (rv != SECSuccess) { good = 0; } @@ -11927,8 +12387,8 @@ ssl3_UnprotectRecord(sslSocket *ss, } /* decrypt from cText buf to plaintext. */ - rv = spec->cipher( - spec->cipherContext, plaintext->buf, (int *)&plaintext->len, + rv = crSpec->decode( + crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len, plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen); if (rv != SECSuccess) { goto decrypt_loser; @@ -11941,7 +12401,7 @@ ssl3_UnprotectRecord(sslSocket *ss, /* 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 = spec->macDef->mac_size; + const unsigned int macSize = crSpec->mac_size; if (!isTLS) { good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding( @@ -11953,32 +12413,32 @@ ssl3_UnprotectRecord(sslSocket *ss, } /* compute the MAC */ - rv = ssl3_BuildRecordPseudoHeader( - spec->epoch, IS_DTLS(ss) ? cText->seq_num : spec->seqNum, + headerLen = ssl3_BuildRecordPseudoHeader( + header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, rType, isTLS, cText->version, IS_DTLS(ss), - plaintext->len - spec->macDef->mac_size, &header); - PORT_Assert(rv == SECSuccess); + plaintext->len - crSpec->mac_size); + PORT_Assert(headerLen <= sizeof(header)); if (cipher_def->type == type_block) { rv = ssl3_ComputeRecordMACConstantTime( - spec, SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header), + crSpec, (PRBool)(!ss->sec.isServer), header, headerLen, plaintext->buf, plaintext->len, originalLen, hash, &hashBytes); ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf, - spec->macDef->mac_size); + crSpec->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 -= spec->macDef->mac_size; + plaintext->len -= crSpec->mac_size; } else { /* This is safe because we checked the minLength above. */ - plaintext->len -= spec->macDef->mac_size; + plaintext->len -= crSpec->mac_size; rv = ssl3_ComputeRecordMAC( - spec, SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header), + crSpec, (PRBool)(!ss->sec.isServer), header, headerLen, plaintext->buf, plaintext->len, hash, &hashBytes); /* We can read the MAC directly from the record because its location @@ -11988,8 +12448,8 @@ ssl3_UnprotectRecord(sslSocket *ss, good &= SECStatusToMask(rv); - if (hashBytes != (unsigned)spec->macDef->mac_size || - NSS_SecureMemcmp(givenHash, hash, spec->macDef->mac_size) != 0) { + if (hashBytes != (unsigned)crSpec->mac_size || + NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) { /* We're allowed to leak whether or not the MAC check was correct */ good = 0; } @@ -12005,84 +12465,7 @@ ssl3_UnprotectRecord(sslSocket *ss, return SECSuccess; } -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 +/* if cText is non-null, then decipher, check MAC, and decompress 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, @@ -12092,8 +12475,8 @@ ssl3_GetCipherSpec(sslSocket *ss, sslSequenceNumber seq) * checked, and is already sitting in databuf. It is processed as an SSL * Handshake message. * - * DOES NOT process the decrypted application data. - * On return, databuf contains the decrypted record. + * DOES NOT process the decrypted/decompressed application data. + * On return, databuf contains the decrypted/decompressed record. * * Called from ssl3_GatherCompleteHandshake * ssl3_RestartHandshakeAfterCertReq @@ -12109,15 +12492,20 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) { SECStatus rv; PRBool isTLS; - DTLSEpoch epoch; - sslSequenceNumber seqNum = 0; - ssl3CipherSpec *spec = NULL; - PRBool outOfOrderSpec = PR_FALSE; + sslSequenceNumber seq_num = 0; + ssl3CipherSpec *crSpec; 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); @@ -12131,48 +12519,41 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) if (cText == NULL) { SSL_DBG(("%d: SSL3[%d]: HandleRecord, resuming handshake", SSL_GETPID(), ss->fd)); - /* Note that this doesn't pass the epoch and sequence number of the - * record through, which DTLS 1.3 depends on. DTLS doesn't support - * asynchronous certificate validation, so that should be OK. */ - PORT_Assert(!IS_DTLS(ss)); - return ssl3_HandleNonApplicationData(ss, content_handshake, - 0, 0, databuf); + rType = content_handshake; + goto process_it; } ssl_GetSpecReadLock(ss); /******************************************/ - 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); + crSpec = ss->ssl3.crSpec; + isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0); + if (IS_DTLS(ss)) { - if (!dtls_IsRelevant(ss, spec, cText, &seqNum)) { + PRBool sameEpoch; + if (!dtls_IsRelevant(ss, cText, &sameEpoch, &seq_num)) { ssl_ReleaseSpecReadLock(ss); /*****************************/ databuf->len = 0; /* Needed to ensure data not left around */ - return SECSuccess; + /* Maybe retransmit if needed. */ + return dtls_MaybeRetransmitHandshake(ss, cText, sameEpoch); } } else { - seqNum = spec->seqNum + 1; + seq_num = crSpec->read_seq_num + 1; } - if (seqNum >= spec->cipherDef->max_records) { + if (seq_num >= crSpec->cipher_def->max_records) { ssl_ReleaseSpecReadLock(ss); /*****************************/ SSL_TRC(3, ("%d: SSL[%d]: read sequence number at limit 0x%0llx", - SSL_GETPID(), ss->fd, seqNum)); + SSL_GETPID(), ss->fd, seq_num)); PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS); return SECFailure; } - plaintext = databuf; + /* 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->len = 0; /* filled in by Unprotect call below. */ /* We're waiting for another ClientHello, which will appear unencrypted. @@ -12207,12 +12588,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 (spec->version < SSL_LIBRARY_VERSION_TLS_1_3 || - spec->cipherDef->calg == ssl_calg_null) { + if (crSpec->version < SSL_LIBRARY_VERSION_TLS_1_3 || + crSpec->cipher_def->calg == ssl_calg_null) { /* Unencrypted TLS 1.3 records use the pre-TLS 1.3 format. */ - rv = ssl3_UnprotectRecord(ss, spec, cText, plaintext, &alert); + rv = ssl3_UnprotectRecord(ss, cText, plaintext, &alert); } else { - rv = tls13_UnprotectRecord(ss, spec, cText, plaintext, &alert); + rv = tls13_UnprotectRecord(ss, cText, plaintext, &alert); } #endif @@ -12221,25 +12602,14 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd)); - /* Ensure that we don't process this data again. */ - databuf->len = 0; + /* Clear the temp buffer used for decompression upon failure. */ + sslBuffer_Clear(&temp_buf); - /* 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(); @@ -12252,11 +12622,10 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) } /* SECSuccess */ - spec->seqNum = PR_MAX(spec->seqNum, seqNum); + crSpec->read_seq_num = seq_num; if (IS_DTLS(ss)) { - dtls_RecordSetRecvd(&spec->recvdRecords, seqNum); + dtls_RecordSetRecvd(&crSpec->recvdRecords, seq_num); } - epoch = spec->epoch; ssl_ReleaseSpecReadLock(ss); /*****************************************/ @@ -12266,16 +12635,70 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) rType = cText->type; /* This must go after decryption because TLS 1.3 * has encrypted content types. */ - /* IMPORTANT: We are in DTLS 1.3 mode and we have processed something - * from the wrong epoch. Divert to a divert processing function to make - * sure we don't accidentally use the data unsafely. */ - if (outOfOrderSpec) { - PORT_Assert(IS_DTLS(ss) && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - return dtls13_HandleOutOfEpochRecord(ss, spec, rType, databuf); + /* 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); } - /* Check the length of the plaintext. */ - if (isTLS && databuf->len > MAX_FRAGMENT_LENGTH) { + /* + ** Having completed the decompression, check the length again. + */ + if (isTLS && databuf->len > (MAX_FRAGMENT_LENGTH + 1024)) { SSL3_SendAlert(ss, alert_fatal, record_overflow); PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); return SECFailure; @@ -12297,7 +12720,45 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) return SECFailure; } - return ssl3_HandleNonApplicationData(ss, rType, epoch, seqNum, databuf); +/* 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; } /* @@ -12315,36 +12776,83 @@ ssl_InitSecState(sslSecurityInfo *sec) sec->keaGroup = NULL; } -SECStatus +/* 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 ssl3_InitState(sslSocket *ss) { - SECStatus rv; + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + if (ss->ssl3.initialized) + return; /* Function should be idempotent */ ss->ssl3.policy = SSL_ALLOWED; ssl_InitSecState(&ss->sec); ssl_GetSpecWriteLock(ss); - PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs); - rv = ssl_SetupNullCipherSpec(ss, CipherSpecRead); - rv |= ssl_SetupNullCipherSpec(ss, CipherSpecWrite); - ss->ssl3.pwSpec = ss->ssl3.prSpec = NULL; + 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; 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 : idle_handshake; + ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; - ssl3_ResetExtensionData(&ss->xtnData, ss); + ssl3_ResetExtensionData(&ss->xtnData); PR_INIT_CLIST(&ss->ssl3.hs.remoteExtensions); if (IS_DTLS(ss)) { ss->ssl3.hs.sendMessageSeq = 0; ss->ssl3.hs.recvMessageSeq = 0; - ss->ssl3.hs.rtTimer->timeout = DTLS_RETRANSMIT_INITIAL_MS; + ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS; ss->ssl3.hs.rtRetries = 0; ss->ssl3.hs.recvdHighWater = -1; PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight); @@ -12360,6 +12868,8 @@ 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; @@ -12371,7 +12881,9 @@ ssl3_InitState(sslSocket *ss) ss->ssl3.hs.zeroRttState = ssl_0rtt_none; - return SECSuccess; + ssl_FilterSupportedGroups(ss); + + ss->ssl3.initialized = PR_TRUE; } /* record the export policy for this cipher suite */ @@ -12625,7 +13137,8 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - if (!ss->firstHsDone || (ss->ssl3.hs.ws != idle_handshake)) { + if (!ss->firstHsDone || + (ss->ssl3.initialized && (ss->ssl3.hs.ws != idle_handshake))) { PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); return SECFailure; } @@ -12639,11 +13152,6 @@ 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. */ @@ -12701,7 +13209,15 @@ ssl3_DestroySSL3Info(sslSocket *ss) SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE); SECITEM_FreeItem(&ss->ssl3.hs.srvVirtName, PR_FALSE); - SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, 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*/); /* Destroy the DTLS data */ if (IS_DTLS(ss)) { @@ -12713,10 +13229,10 @@ ssl3_DestroySSL3Info(sslSocket *ss) /* Destroy remote extensions */ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); - ssl3_DestroyExtensionData(&ss->xtnData); + ssl3_ResetExtensionData(&ss->xtnData); - /* Destroy cipher specs */ - ssl_DestroyCipherSpecs(&ss->ssl3.hs.cipherSpecs); + /* Destroy TLS 1.3 cipher specs */ + tls13_DestroyCipherSpecs(&ss->ssl3.hs.cipherSpecs); /* Destroy TLS 1.3 keys */ if (ss->ssl3.hs.currentSecret) @@ -12745,6 +13261,8 @@ 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) @@ -12783,7 +13301,7 @@ ssl3_ApplyNSSPolicy(void) } if (ssl_GetBulkCipherDef(suite)->type != type_aead) { - policyOid = MAP_NULL(ssl_GetMacDefByAlg(suite->mac_alg)->oid); + policyOid = MAP_NULL(mac_defs[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 913a14f63..b440b4b02 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, - PRUint8 *client_rand, PRUint8 *server_rand, + SSL3Random *client_rand, SSL3Random *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->version > SSL_LIBRARY_VERSION_3_0); - isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS12 = (PRBool)(ss->ssl3.pwSpec->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, ssl_hs_client_key_exchange, + rv = ssl3_AppendHandshakeHeader(ss, 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_InitPendingCipherSpecs(ss, pms, PR_TRUE); + rv = ssl3_InitPendingCipherSpec(ss, pms); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; @@ -250,6 +250,19 @@ 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() */ @@ -313,7 +326,7 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b, return SECFailure; } - rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); + rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); if (rv != SECSuccess) { /* error code set by ssl3_InitPendingCipherSpec */ @@ -584,8 +597,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) { @@ -690,7 +703,7 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss) ec_params.data[2] = keyPair->group->name & 0xff; pubKey = keyPair->keys->pubKey; - if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) { + if (ss->ssl3.pwSpec->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. */ @@ -698,15 +711,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->version >= SSL_LIBRARY_VERSION_TLS_1_2); + isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); rv = ssl3_SignHashes(ss, &hashes, ss->sec.serverCert->serverKeyPair->privKey, &signed_hash); @@ -718,7 +731,7 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss) 1 + pubKey->u.ec.publicValue.len + (isTLS12 ? 2 : 0) + 2 + signed_hash.len; - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length); + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } @@ -857,16 +870,20 @@ ssl_IsDHEEnabled(const sslSocket *ss) } /* Send our Supported Groups extension. */ -SECStatus -ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl_SendSupportedGroupsXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) { + PRInt32 extension_length; + unsigned char enabledGroups[64]; + unsigned int enabledGroupsLen = 0; unsigned int i; PRBool ec; PRBool ff = PR_FALSE; - PRBool found = PR_FALSE; - SECStatus rv; - unsigned int lengthOffset; + + if (!ss) + return 0; /* We only send FF supported groups if we require DH named groups * or if TLS 1.3 is a possibility. */ @@ -875,19 +892,13 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, if (ss->opt.requireDHENamedGroups) { ff = ssl_IsDHEEnabled(ss); } - if (!ec && !ff) { - return SECSuccess; - } + if (!ec && !ff) + return 0; } else { ec = ff = PR_TRUE; } - /* Mark the location of the length. */ - rv = sslBuffer_Skip(buf, 2, &lengthOffset); - if (rv != SECSuccess) { - return SECFailure; - } - + PORT_Assert(sizeof(enabledGroups) > SSL_NAMED_GROUP_COUNT * 2); for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { const sslNamedGroupDef *group = ss->namedGroupPreferences[i]; if (!group) { @@ -900,53 +911,78 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, continue; } - found = PR_TRUE; - rv = sslBuffer_AppendNumber(buf, group->name, 2); - if (rv != SECSuccess) { - return SECFailure; + 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; } } - - 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; + return extension_length; } /* Send our "canned" (precompiled) Supported Point Formats extension, * which says that we only support uncompressed points. */ -SECStatus -ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_SendSupportedPointFormatsXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { - SECStatus rv; + static const PRUint8 ecPtFmt[6] = { + 0, 11, /* Extension type */ + 0, 2, /* octets that follow */ + 1, /* octets that follow */ + 0 /* uncompressed type only */ + }; /* 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 SECSuccess; - } - 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; + (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; + } } - - *added = PR_TRUE; - return SECSuccess; + return sizeof(ecPtFmt); } diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index ade280903..271084cf7 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/lib/ssl/ssl3ext.c @@ -14,20 +14,8 @@ #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. @@ -43,15 +31,16 @@ 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_HandleSigAlgsXtn }, + { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn }, { 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_ServerHandlePskModesXtn }, - { ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn }, - { 0, NULL } + { ssl_tls13_psk_key_exchange_modes_xtn, + &tls13_ServerHandlePskKeyExchangeModesXtn }, + { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn }, + { -1, NULL } }; /* These two tables are used by the client, to handle server hello @@ -70,38 +59,36 @@ 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 }, - { 0, NULL } + { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn }, + { -1, NULL } }; static const ssl3ExtensionHandler helloRetryRequestHandlers[] = { { ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr }, { ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie }, - { 0, NULL } + { -1, NULL } }; static const ssl3ExtensionHandler serverHelloHandlersSSL3[] = { { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, - { 0, NULL } + { -1, NULL } }; static const ssl3ExtensionHandler newSessionTicketHandlers[] = { - { ssl_tls13_early_data_xtn, - &tls13_ClientHandleTicketEarlyDataXtn }, - { 0, NULL } + { ssl_tls13_ticket_early_data_info_xtn, + &tls13_ClientHandleTicketEarlyDataInfoXtn }, + { -1, 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 }, - { 0, NULL } + { -1, NULL } }; static const ssl3ExtensionHandler certificateRequestHandlers[] = { - { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn }, - { ssl_tls13_certificate_authorities_xtn, - &tls13_ClientHandleCertAuthoritiesXtn }, - { 0, NULL } + { -1, NULL } }; /* Tables of functions to format TLS hello extensions, one function per @@ -114,14 +101,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 sslExtensionBuilder clientHelloSendersTLS[] = +static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { - { ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn }, + { ssl_server_name_xtn, &ssl3_SendServerNameXtn }, { 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_ClientSendSessionTicketXtn }, + { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn }, { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn }, @@ -134,155 +121,22 @@ static const sslExtensionBuilder clientHelloSendersTLS[] = * 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_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn }, + { ssl_tls13_short_header_xtn, &tls13_SendShortHeaderXtn }, + { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }, { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn }, - { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn }, + { ssl_tls13_psk_key_exchange_modes_xtn, + &tls13_ClientSendPskKeyExchangeModesXtn }, + { ssl_padding_xtn, &ssl3_ClientSendPaddingExtension }, /* The pre_shared_key extension MUST be last. */ { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn }, - { 0, NULL } + /* 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 const ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = { + { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn } + /* any extra entries will appear as { 0, NULL } */ }; -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) { @@ -302,11 +156,8 @@ 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_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type) +ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type) { const TLSExtensionData *xtnData = &ss->xtnData; return arrayContainsExtension(xtnData->advertised, @@ -389,44 +240,6 @@ 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. @@ -437,46 +250,42 @@ ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage, * right phase. */ SECStatus -ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) +ssl3_HandleParsedExtensions(sslSocket *ss, + SSL3HandshakeType handshakeMessage) { 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) || - (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); + (handshakeMessage == hello_retry_request); PRCList *cursor; - switch (message) { - case ssl_hs_client_hello: + switch (handshakeMessage) { + case client_hello: handlers = clientHelloHandlers; break; - case ssl_hs_new_session_ticket: + case new_session_ticket: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); handlers = newSessionTicketHandlers; break; - case ssl_hs_hello_retry_request: + case hello_retry_request: handlers = helloRetryRequestHandlers; break; - case ssl_hs_encrypted_extensions: + case encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); /* fall through */ - case ssl_hs_server_hello: + case server_hello: if (ss->version > SSL_LIBRARY_VERSION_3_0) { handlers = serverHelloHandlersTLS; } else { handlers = serverHelloHandlersSSL3; } break; - case ssl_hs_certificate: + case certificate: PORT_Assert(!ss->sec.isServer); handlers = serverCertificateHandlers; break; - case ssl_hs_certificate_request: + case certificate_request: PORT_Assert(!ss->sec.isServer); handlers = certificateRequestHandlers; break; @@ -490,39 +299,28 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { TLSExtension *extension = (TLSExtension *)cursor; - SECStatus rv; + const ssl3ExtensionHandler *handler; /* Check whether the server sent an extension which was not advertised - * 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)) { + * in the ClientHello */ + if (!ss->sec.isServer && + !ssl3_ClientExtensionAdvertised(ss, extension->type) && + (handshakeMessage != new_session_ticket) && + (extension->type != ssl_tls13_cookie_xtn)) { (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 && - !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; + if (isTLS13 && !tls13_ExtensionAllowed(extension->type, handshakeMessage)) { + if (handshakeMessage == client_hello) { + /* Skip extensions not used in TLS 1.3 */ + continue; } + tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, + unsupported_extension); + return SECFailure; } /* Special check for this being the last extension if it's @@ -536,9 +334,23 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) return SECFailure; } - rv = ssl_CallExtensionHandler(ss, message, extension, handlers); - if (rv != SECSuccess) { - 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; + } + } } } return SECSuccess; @@ -549,7 +361,7 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) SECStatus ssl3_HandleExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length, - SSLHandshakeType handshakeMessage) + SSL3HandshakeType handshakeMessage) { SECStatus rv; @@ -571,30 +383,21 @@ SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - sslExtensionBuilderFunc cb) + ssl3HelloExtensionSenderFunc cb) { int i; - sslExtensionBuilder *sender; + ssl3HelloExtensionSender *sender; if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { sender = &xtnData->serverHelloSenders[0]; } else { - 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); + if (tls13_ExtensionAllowed(ex_type, server_hello)) { + PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions)); sender = &xtnData->serverHelloSenders[0]; - } 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) { + } else if (tls13_ExtensionAllowed(ex_type, certificate)) { sender = &xtnData->certificateSenders[0]; } else { - PORT_Assert(0); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; + PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions)); + sender = &xtnData->encryptedExtensionsSenders[0]; } } for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) { @@ -615,289 +418,32 @@ ssl3_RegisterExtensionSender(const sslSocket *ss, return SECFailure; } -static SECStatus -ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf, - SSLHandshakeType message) +/* call each of the extension senders and return the accumulated length */ +PRInt32 +ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, + const ssl3HelloExtensionSender *sender) { - sslBuffer tail = SSL_BUFFER_EMPTY; - SECStatus rv; - PRCList *cursor; - - /* 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; - } - - /* 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; - } - } - - 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; - } - } + PRInt32 total_exten_len = 0; + int i; - if (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) { - rv = ssl_CallCustomExtensionSenders(ss, buf, message); - if (rv != SECSuccess) { - goto loser; + if (!sender) { + if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) { + sender = &clientHelloSendersTLS[0]; + } else { + sender = &clientHelloSendersSSL3[0]; } } - 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; + 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; } - 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; + return total_exten_len; } void @@ -914,59 +460,52 @@ ssl3_DestroyRemoteExtensions(PRCList *list) /* Initialize the extension data block. */ void -ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) +ssl3_InitExtensionData(TLSExtensionData *xtnData) { - 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_DestroyExtensionData(TLSExtensionData *xtnData) +ssl3_ResetExtensionData(TLSExtensionData *xtnData) { + /* Clean up. */ ssl3_FreeSniNameArray(xtnData); - PORT_Free(xtnData->sigSchemes); + PORT_Free(xtnData->clientSigSchemes); SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); tls13_DestroyKeyShares(&xtnData->remoteKeyShares); - 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); + + /* Now reinit. */ + ssl3_InitExtensionData(xtnData); } -/* Free everything that has been allocated and then reset back to - * the starting state. */ -void -ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss) +/* Thunks to let extension handlers operate on const sslSocket* objects. */ +SECStatus +ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src, + PRInt32 bytes) { - ssl3_DestroyExtensionData(xtnData); - ssl3_InitExtensionData(xtnData, ss); + 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); +} + +SECStatus +ssl3_ExtAppendHandshakeVariable(const sslSocket *ss, + const PRUint8 *src, PRInt32 bytes, + PRInt32 lenSize) +{ + return ssl3_AppendHandshakeVariable((sslSocket *)ss, src, bytes, lenSize); } -/* 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 d0f75a599..90407375a 100644 --- a/security/nss/lib/ssl/ssl3ext.h +++ b/security/nss/lib/ssl/ssl3ext.h @@ -9,38 +9,54 @@ #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 SECStatus (*sslExtensionBuilderFunc)(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added); +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); /* row in a table of hello extension senders */ typedef struct { PRInt32 ex_type; - sslExtensionBuilderFunc ex_sender; -} sslExtensionBuilder; + ssl3HelloExtensionSenderFunc ex_sender; +} ssl3HelloExtensionSender; + +/* row in a table of hello extension handlers */ +typedef struct { + PRInt32 ex_type; + ssl3ExtensionHandlerFunc ex_handler; +} ssl3ExtensionHandler; struct TLSExtensionDataStr { /* registered callbacks that send server hello extensions */ - sslExtensionBuilder serverHelloSenders[SSL_MAX_EXTENSIONS]; - sslExtensionBuilder encryptedExtensionsSenders[SSL_MAX_EXTENSIONS]; - sslExtensionBuilder certificateSenders[SSL_MAX_EXTENSIONS]; + ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS]; + ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS]; + ssl3HelloExtensionSender certificateSenders[SSL_MAX_EXTENSIONS]; - /* Keep track of the extensions that are advertised or negotiated. */ + /* Keep track of the extensions that are 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; @@ -70,13 +86,10 @@ struct TLSExtensionDataStr { PRBool peerSupportsFfdheGroups; /* if the peer supports named ffdhe groups */ /* clientSigAndHash contains the contents of the signature_algorithms - * 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; + * extension (if any) from the client. This is only valid for TLS 1.2 + * or later. */ + SSLSignatureScheme *clientSigSchemes; + unsigned int numClientSigScheme; /* In a client: if the server supports Next Protocol Negotiation, then * this is the protocol that was negotiated. @@ -86,18 +99,9 @@ struct TLSExtensionDataStr { PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */ - 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; + 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) */ }; typedef struct TLSExtensionStr { @@ -106,44 +110,40 @@ 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, - SSLHandshakeType handshakeMessage); + SSL3HandshakeType handshakeMessage); SECStatus ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length); SECStatus ssl3_HandleParsedExtensions(sslSocket *ss, - SSLHandshakeType handshakeMessage); + SSL3HandshakeType handshakeMessage); TLSExtension *ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type); void ssl3_DestroyRemoteExtensions(PRCList *list); -void ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss); -void ssl3_DestroyExtensionData(TLSExtensionData *xtnData); -void ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss); +void ssl3_InitExtensionData(TLSExtensionData *xtnData); +void ssl3_ResetExtensionData(TLSExtensionData *xtnData); PRBool ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type); -PRBool ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type); +PRBool ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type); SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, - 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); + ssl3HelloExtensionSenderFunc cb); +PRInt32 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, + const ssl3HelloExtensionSender *sender); + +void ssl3_CalculatePaddingExtLen(sslSocket *ss, + unsigned int clientHelloLength); /* 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,10 +156,4 @@ 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 c0fbda7ab..370bd8b3e 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -13,6 +13,7 @@ #include "blapit.h" #include "prinit.h" #include "selfencrypt.h" +#include "ssl3encode.h" #include "ssl3ext.h" #include "ssl3exthandle.h" #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */ @@ -21,48 +22,70 @@ * unless that name is a dotted decimal string. * Used by client and server. */ -SECStatus -ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_SendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { - unsigned int len; - PRNetAddr netAddr; SECStatus rv; - - /* must have a hostname */ - if (!ss->url || !ss->url[0]) { - return SECSuccess; - } - /* 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; + 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; } - /* HostName (length and value) */ - rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)ss->url, len, 2); - if (rv != SECSuccess) { - return SECFailure; + /* 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; } - - *added = PR_TRUE; - return SECSuccess; + return 4; } /* Handle an incoming SNI extension. */ SECStatus -ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECItem *names = NULL; PRUint32 listLenBytes = 0; @@ -171,54 +194,88 @@ ssl3_FreeSniNameArray(TLSExtensionData *xtnData) * sends an empty ticket. Servers always send empty tickets. */ PRInt32 -ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +ssl3_SendSessionTicketXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { + 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 SECSuccess; + return 0; } /* Ignore the SessionTicket extension if processing is disabled. */ - if (!ss->opt.enableSessionTickets) { - return SECSuccess; - } + if (!ss->opt.enableSessionTickets) + return 0; - /* 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. + /* Empty extension length = extension_type (2-bytes) + + * length(extension_data) (2-bytes) */ - session_ticket = &sid->u.ssl3.locked.sessionTicket; - if (session_ticket->ticket.data && - (xtnData->ticketTimestampVerified || - ssl_TicketTimeValid(session_ticket))) { + extension_length = 4; - xtnData->ticketTimestampVerified = PR_FALSE; + /* 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. + */ + 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. + */ - rv = sslBuffer_Append(buf, session_ticket->ticket.data, - session_ticket->ticket.len); - if (rv != SECSuccess) { - return SECFailure; + 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->sentSessionTicketInClientHello = PR_TRUE; + 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); + } + if (rv != SECSuccess) + goto loser; - *added = PR_TRUE; - return SECSuccess; + if (!ss->sec.isServer) { + xtnData->advertised[xtnData->numAdvertised++] = + ssl_session_ticket_xtn; + } + } + return extension_length; + +loser: + xtnData->ticketTimestampVerified = PR_FALSE; + return -1; } PRBool @@ -244,18 +301,16 @@ ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag) /* handle an incoming Next Protocol Negotiation extension. */ SECStatus -ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - if (ss->firstHsDone || data->len != 0) { /* Clients MUST send an empty NPN extension, if any. */ PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ssl_next_proto_nego_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; /* TODO: server side NPN support would require calling * ssl3_RegisterServerHelloExtensionSender here in order to echo the @@ -289,7 +344,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 extension, SECItem *data) + PRUint16 ex_type, SECItem *data) { SECStatus rv; unsigned char resultBuffer[255]; @@ -326,7 +381,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); - if (extension == ssl_app_layer_protocol_xtn && + if (ex_type == 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. */ @@ -335,14 +390,13 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = extension; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result); } /* handle an incoming ALPN extension at the server */ SECStatus -ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { PRUint32 count; SECStatus rv; @@ -369,16 +423,15 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; } - rv = ssl3_SelectAppProtocol(ss, xtnData, ssl_app_layer_protocol_xtn, data); + rv = ssl3_SelectAppProtocol(ss, xtnData, ex_type, 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, - ssl_app_layer_protocol_xtn, - ssl3_ServerSendAppProtoXtn); + rv = ssl3_RegisterExtensionSender( + ss, xtnData, ex_type, ssl3_ServerSendAppProtoXtn); if (rv != SECSuccess) { ssl3_ExtSendAlert(ss, alert_fatal, internal_error); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -389,10 +442,9 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, } SECStatus -ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, 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)) { @@ -418,12 +470,11 @@ ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECFailure; } - return ssl3_SelectAppProtocol(ss, xtnData, ssl_next_proto_nego_xtn, data); + return ssl3_SelectAppProtocol(ss, xtnData, ex_type, data); } SECStatus -ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 list_len; @@ -470,168 +521,265 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED; - xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name); } -SECStatus -ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; + /* Renegotiations do not send this extension. */ if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) { - return SECSuccess; + return 0; } - *added = PR_TRUE; - return SECSuccess; + 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 extension_length; + +loser: + return -1; } -SECStatus -ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - SECStatus rv; - const unsigned int len = ss->opt.nextProtoNego.len; + PRInt32 extension_length; + unsigned char *alpn_protos = NULL; /* Renegotiations do not send this extension. */ if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) { - return SECSuccess; + return 0; } - /* 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. */ + extension_length = 2 /* extension type */ + 2 /* extension length */ + + 2 /* protocol name list length */ + + ss->opt.nextProtoNego.len; - if (len > 0) { - /* Each protocol string is prefixed with a single byte length. */ - unsigned int i; + 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; - rv = sslBuffer_AppendNumber(buf, len, 2); - if (rv != SECSuccess) { + alpn_protos = PORT_Alloc(len); + if (alpn_protos == NULL) { return SECFailure; } - - i = ss->opt.nextProtoNego.data[0] + 1; - if (i <= len) { - rv = sslBuffer_Append(buf, &ss->opt.nextProtoNego.data[i], len - i); - if (rv != SECSuccess) { - return SECFailure; - } - rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, i); - if (rv != SECSuccess) { - return SECFailure; - } - } else { - /* This seems to be invalid data so we'll send as-is. */ - rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len); - if (rv != SECSuccess) { - return SECFailure; + 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; + } + xtnData->advertised[xtnData->numAdvertised++] = + ssl_app_layer_protocol_xtn; } - *added = PR_TRUE; - return SECSuccess; + return extension_length; + +loser: + if (alpn_protos) { + PORT_Free(alpn_protos); + } + return -1; } -SECStatus -ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - SECStatus rv; + PRInt32 extension_length; - /* 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); - rv = sslBuffer_AppendNumber(buf, xtnData->nextProto.len + 1, 2); - if (rv != SECSuccess) { - return SECFailure; + 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_AppendVariable(buf, xtnData->nextProto.data, - xtnData->nextProto.len, 1); - 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; + } } - *added = PR_TRUE; - return SECSuccess; + return extension_length; } SECStatus -ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - sslExtensionBuilderFunc sender; + ssl3HelloExtensionSenderFunc sender; PORT_Assert(ss->sec.isServer); /* remember that we got this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { sender = tls13_ServerSendStatusRequestXtn; } else { sender = ssl3_ServerSendStatusRequestXtn; } - return ssl3_RegisterExtensionSender(ss, xtnData, ssl_cert_status_xtn, sender); + return ssl3_RegisterExtensionSender(ss, xtnData, ex_type, sender); } -SECStatus -ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ServerSendStatusRequestXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; const sslServerCert *serverCert = ss->sec.serverCert; + SECStatus rv; if (!serverCert->certStatusArray || !serverCert->certStatusArray->len) { - return SECSuccess; + return 0; } - *added = PR_TRUE; - return SECSuccess; + 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 extension_length; } /* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the * client side. See RFC 6066 section 8. */ -SECStatus -ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { - SECStatus rv; + PRInt32 extension_length; - if (!ss->opt.enableOCSPStapling) { - return SECSuccess; - } + if (!ss->opt.enableOCSPStapling) + return 0; - rv = sslBuffer_AppendNumber(buf, 1 /* status_type ocsp */, 1); - if (rv != SECSuccess) { - return SECFailure; - } - /* 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; + /* extension_type (2-bytes) + + * length(extension_data) (2-bytes) + + * status_type (1) + + * responder_id_list length (2) + + * request_extensions length (2) + */ + extension_length = 9; + + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; } + if (append) { + SECStatus rv; - *added = PR_TRUE; - return SECSuccess; + /* 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; + } + return extension_length; } SECStatus -ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { /* In TLS 1.3, the extension carries the OCSP response. */ @@ -649,32 +797,36 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ -#define TLS_EX_SESS_TICKET_VERSION (0x010a) +#define TLS_EX_SESS_TICKET_VERSION (0x0105) /* * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket */ SECStatus -ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, - const PRUint8 *appToken, unsigned int appTokenLen, - PK11SymKey *secret, SECItem *ticket_data) +ssl3_EncodeSessionTicket(sslSocket *ss, + const NewSessionTicket *ticket, + SECItem *ticket_data) { SECStatus rv; - sslBuffer plaintext = SSL_BUFFER_EMPTY; + SECItem plaintext; + SECItem plaintext_item = { 0, NULL, 0 }; + PRUint32 plaintext_length; SECItem ticket_buf = { 0, NULL, 0 }; - sslSessionID sid; + PRBool ms_is_wrapped; unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; SECItem ms_item = { 0, NULL, 0 }; - PRTime now; + PRUint32 cert_length = 0; + PRUint32 now; SECItem *srvName = NULL; - CK_MECHANISM_TYPE msWrapMech; + CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, + * must be >= 0 */ + ssl3CipherSpec *spec; SECItem *alpnSelection = NULL; - PRUint32 ticketAgeBaseline; SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake", SSL_GETPID(), ss->fd)); @@ -682,69 +834,107 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - /* Extract the master secret wrapped. */ + if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { + cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len; + } - PORT_Memset(&sid, 0, sizeof(sslSessionID)); + 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_Assert(secret); - rv = ssl3_CacheWrappedSecret(ss, &sid, secret); - if (rv == SECSuccess) { - if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) + 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. */ 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. */ - goto loser; + } + ms_is_wrapped = PR_TRUE; } /* 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 = sslBuffer_AppendNumber(&plaintext, TLS_EX_SESS_TICKET_VERSION, - sizeof(PRUint16)); + rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION, + sizeof(PRUint16)); if (rv != SECSuccess) goto loser; /* ssl_version */ - rv = sslBuffer_AppendNumber(&plaintext, ss->version, - sizeof(SSL3ProtocolVersion)); + rv = ssl3_AppendNumberToItem(&plaintext, ss->version, + sizeof(SSL3ProtocolVersion)); if (rv != SECSuccess) goto loser; /* ciphersuite */ - rv = sslBuffer_AppendNumber(&plaintext, ss->ssl3.hs.cipher_suite, - sizeof(ssl3CipherSuite)); + rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.cipher_suite, + sizeof(ssl3CipherSuite)); if (rv != SECSuccess) goto loser; - /* cipher spec parameters */ - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authType, 1); + /* compression */ + rv = ssl3_AppendNumberToItem(&plaintext, ss->ssl3.hs.compression, 1); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.authKeyBits, 4); + + /* cipher spec parameters */ + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authType, 1); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaType, 1); + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.authKeyBits, 4); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendNumber(&plaintext, ss->sec.keaKeyBits, 4); + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1); if (rv != SECSuccess) goto loser; - 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); + rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4); if (rv != SECSuccess) goto loser; @@ -755,120 +945,102 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, PORT_Assert(cert->namedCurve); /* EC curves only use the second of the two bytes. */ PORT_Assert(cert->namedCurve->name < 256); - rv = sslBuffer_AppendNumber(&plaintext, cert->namedCurve->name, 1); + rv = ssl3_AppendNumberToItem(&plaintext, cert->namedCurve->name, 1); } else { - rv = sslBuffer_AppendNumber(&plaintext, 0, 1); + rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); } if (rv != SECSuccess) goto loser; /* master_secret */ - rv = sslBuffer_AppendNumber(&plaintext, msWrapMech, 4); + rv = ssl3_AppendNumberToItem(&plaintext, ms_is_wrapped, 1); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendNumberToItem(&plaintext, msWrapMech, 4); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendVariable(&plaintext, ms_item.data, ms_item.len, 2); + rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len); if (rv != SECSuccess) goto loser; /* client identity */ if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - rv = sslBuffer_AppendNumber(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); + 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); if (rv != SECSuccess) goto loser; - rv = sslBuffer_AppendVariable(&plaintext, - ss->sec.ci.sid->peerCert->derCert.data, - ss->sec.ci.sid->peerCert->derCert.len, 2); + rv = ssl3_AppendToItem(&plaintext, + ss->sec.ci.sid->peerCert->derCert.data, + ss->sec.ci.sid->peerCert->derCert.len); if (rv != SECSuccess) goto loser; } else { - rv = sslBuffer_AppendNumber(&plaintext, 0, 1); + rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); if (rv != SECSuccess) goto loser; } /* timestamp */ - now = ssl_TimeUsec(); - PORT_Assert(sizeof(now) == 8); - rv = sslBuffer_AppendNumber(&plaintext, now, 8); + now = ssl_Time(); + rv = ssl3_AppendNumberToItem(&plaintext, now, + sizeof(ticket->ticket_lifetime_hint)); if (rv != SECSuccess) goto loser; /* HostName (length and value) */ - rv = sslBuffer_AppendVariable(&plaintext, srvName->data, srvName->len, 2); + rv = ssl3_AppendNumberToItem(&plaintext, 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 = sslBuffer_AppendNumber( + rv = ssl3_AppendNumberToItem( &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1); if (rv != SECSuccess) goto loser; /* Flags */ - rv = sslBuffer_AppendNumber(&plaintext, ticket->flags, - sizeof(ticket->flags)); + rv = ssl3_AppendNumberToItem(&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 = sslBuffer_AppendVariable(&plaintext, alpnSelection->data, - alpnSelection->len, 1); - if (rv != SECSuccess) - goto loser; - - rv = sslBuffer_AppendNumber(&plaintext, ssl_max_early_data_size, 4); - if (rv != SECSuccess) - goto loser; - - /* - * 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); + rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection->len, 1); if (rv != SECSuccess) goto loser; + if (alpnSelection->len) { + rv = ssl3_AppendToItem(&plaintext, alpnSelection->data, + alpnSelection->len); + if (rv != SECSuccess) + goto loser; + } - /* Application token */ - rv = sslBuffer_AppendVariable(&plaintext, appToken, appTokenLen, 2); + rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4); 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; - } + /* Check that we are totally full. */ + PORT_Assert(plaintext.len == 0); - 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) { + /* 128 just gives us enough room for overhead. */ + if (SECITEM_AllocItem(NULL, &ticket_buf, plaintext_length + 128) == NULL) { goto loser; } /* Finally, encrypt the ticket. */ - rv = ssl_SelfEncryptProtect(ss, SSL_BUFFER_BASE(&plaintext), - SSL_BUFFER_LEN(&plaintext), + rv = ssl_SelfEncryptProtect(ss, plaintext_item.data, plaintext_item.len, ticket_buf.data, &ticket_buf.len, ticket_buf.len); if (rv != SECSuccess) { goto loser; @@ -877,11 +1049,13 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, /* Give ownership of memory to caller. */ *ticket_data = ticket_buf; - sslBuffer_Clear(&plaintext); + SECITEM_FreeItem(&plaintext_item, PR_FALSE); return SECSuccess; loser: - sslBuffer_Clear(&plaintext); + if (plaintext_item.data) { + SECITEM_FreeItem(&plaintext_item, PR_FALSE); + } if (ticket_buf.data) { SECITEM_FreeItem(&ticket_buf, PR_FALSE); } @@ -893,22 +1067,18 @@ loser: * message is expected during the handshake. */ SECStatus -ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, 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++] = ssl_session_ticket_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } -PR_STATIC_ASSERT((TLS_EX_SESS_TICKET_VERSION >> 8) == 1); - static SECStatus ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, SessionTicket *parsedTicket) @@ -935,12 +1105,6 @@ 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) { @@ -968,6 +1132,14 @@ 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) { @@ -993,18 +1165,6 @@ 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); @@ -1025,6 +1185,14 @@ 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); @@ -1072,21 +1240,13 @@ ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - - /* 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; + /* Read timestamp. */ rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); if (rv != SECSuccess) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - parsedTicket->timestamp |= (PRTime)temp; + parsedTicket->timestamp = temp; /* Read server name */ rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->srvName, 2, @@ -1127,20 +1287,6 @@ 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) { @@ -1167,15 +1313,13 @@ 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); @@ -1194,6 +1338,7 @@ 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; @@ -1236,12 +1381,10 @@ loser: /* Generic ticket processing code, common to all TLS versions. */ SECStatus -ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, - SECItem *appToken) +ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) { SECItem decryptedTicket = { siBuffer, NULL, 0 }; SessionTicket parsedTicket; - sslSessionID *sid = NULL; SECStatus rv; if (ss->sec.ci.sid != NULL) { @@ -1250,12 +1393,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, ss->sec.ci.sid = NULL; } - if (!SECITEM_AllocItem(NULL, &decryptedTicket, ticket->len)) { + if (!SECITEM_AllocItem(NULL, &decryptedTicket, data->len)) { return SECFailure; } /* Decrypt the ticket. */ - rv = ssl_SelfEncryptUnprotect(ss, ticket->data, ticket->len, + rv = ssl_SelfEncryptUnprotect(ss, data->data, data->len, decryptedTicket.data, &decryptedTicket.len, decryptedTicket.len); @@ -1285,28 +1428,16 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, } /* Use the ticket if it is valid and unexpired. */ - if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC > - ssl_TimeUsec()) { + if (parsedTicket.valid && + parsedTicket.timestamp + ssl_ticket_lifetime > ssl_Time()) { + sslSessionID *sid; - rv = ssl_CreateSIDFromTicket(ss, ticket, &parsedTicket, &sid); + rv = ssl_CreateSIDFromTicket(ss, data, &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); @@ -1314,19 +1445,15 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket, 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, +ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); /* Ignore the SessionTicket extension if processing is disabled. */ if (!ss->opt.enableSessionTickets) { @@ -1339,7 +1466,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; /* Parse the received ticket sent in by the client. We are * lenient about some parse errors, falling back to a fullshake @@ -1350,8 +1477,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } - return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data, - NULL); + return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data); } /* Extension format: @@ -1361,45 +1487,60 @@ 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) */ -SECStatus -ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_SendRenegotiationInfoXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { PRInt32 len = 0; - SECStatus rv; + PRInt32 needed; - /* 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. + /* 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. */ - if (ss->ssl3.hs.sendingSCSV) { + if (!ss || ss->ssl3.hs.sendingSCSV) return 0; - } if (ss->firstHsDone) { len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2 : ss->ssl3.hs.finishedBytes; } - - /* verify_Data from previous Finished message(s) */ - rv = sslBuffer_AppendVariable(buf, - ss->ssl3.hs.finishedMsgs.data, len, 1); - if (rv != SECSuccess) { - return SECFailure; + needed = 5 + len; + if (maxBytes < (PRUint32)needed) { + return 0; } - - *added = PR_TRUE; - return SECSuccess; + 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; + } + } + return needed; } /* This function runs in both the client and server. */ SECStatus -ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, 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; @@ -1417,78 +1558,97 @@ 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++] = ssl_renegotiation_info_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; if (ss->sec.isServer) { /* prepare to send back the appropriate response */ - rv = ssl3_RegisterExtensionSender(ss, xtnData, - ssl_renegotiation_info_xtn, + rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, ssl3_SendRenegotiationInfoXtn); } return rv; } -SECStatus -ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - unsigned int i; + PRUint32 ext_data_len; + PRInt16 i; SECStatus rv; - if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) { - return SECSuccess; /* Not relevant */ - } + if (!ss) + return 0; - /* 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; + if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) + return 0; /* Not relevant */ + + ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1; + + 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; } - } - /* Empty MKI value */ - rv = sslBuffer_AppendNumber(buf, 0, 1); - if (rv != SECSuccess) { - return SECFailure; + /* Empty MKI value */ + ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_use_srtp_xtn; } - *added = PR_TRUE; - return SECSuccess; + return 4 + ext_data_len; } -SECStatus -ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { SECStatus rv; - /* Length of the SRTP cipher list */ - rv = sslBuffer_AppendNumber(buf, 2, 2); - if (rv != SECSuccess) { - return SECFailure; + /* 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; /* The selected cipher */ - rv = sslBuffer_AppendNumber(buf, xtnData->dtlsSRTPCipherSuite, 2); - if (rv != SECSuccess) { - return SECFailure; - } + rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->dtlsSRTPCipherSuite, 2); + if (rv != SECSuccess) + return -1; /* Empty MKI value */ - rv = sslBuffer_AppendNumber(buf, 0, 1); - if (rv != SECSuccess) { - return SECFailure; - } + ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1); - *added = PR_TRUE; - return SECSuccess; + return 9; } SECStatus -ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1558,8 +1718,7 @@ ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, } SECStatus -ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; SECItem ciphers = { siBuffer, NULL, 0 }; @@ -1630,12 +1789,11 @@ ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, ssl3_ServerSendUseSRTPXtn); } -/* 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 */ +/* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension + * from a client. + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ SECStatus -ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -1644,15 +1802,15 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; } - if (xtnData->sigSchemes) { - PORT_Free(xtnData->sigSchemes); - xtnData->sigSchemes = NULL; + if (xtnData->clientSigSchemes) { + PORT_Free(xtnData->clientSigSchemes); + xtnData->clientSigSchemes = NULL; } rv = ssl_ParseSignatureSchemes(ss, NULL, - &xtnData->sigSchemes, - &xtnData->numSigSchemes, + &xtnData->clientSigSchemes, + &xtnData->numClientSigScheme, &data->data, &data->len); - if (rv != SECSuccess || xtnData->numSigSchemes == 0) { + if (rv != SECSuccess || xtnData->numClientSigScheme == 0) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); return SECFailure; @@ -1665,52 +1823,177 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_signature_algorithms_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS * 1.2 ClientHellos. */ -SECStatus -ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { + PRInt32 extension_length; + PRUint8 buf[MAX_SIGNATURE_SCHEMES * 2]; + PRUint32 len; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) { - return SECSuccess; + return 0; } - rv = ssl3_EncodeSigAlgs(ss, buf); + rv = ssl3_EncodeSigAlgs(ss, buf, sizeof(buf), &len); if (rv != SECSuccess) { - return SECFailure; + return -1; } - *added = PR_TRUE; - return SECSuccess; + 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; } -SECStatus -ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +/* 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; + } + + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2); + if (rv != SECSuccess) { + return -1; + } + rv = ssl3_ExtAppendHandshakeVariable(ss, padding, xtnData->paddingLen, 2); + if (rv != SECSuccess) { + return -1; + } + + return extensionLen; +} + +PRInt32 +ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; + if (!ss->opt.enableExtendedMS) { - return SECSuccess; + return 0; } /* 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. */ - *added = PR_TRUE; - return SECSuccess; + 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; } SECStatus -ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) { return SECSuccess; } @@ -1730,34 +2013,54 @@ ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnDat SSL_GETPID(), ss->fd)); /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_extended_master_secret_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; if (ss->sec.isServer) { - return ssl3_RegisterExtensionSender(ss, xtnData, - ssl_extended_master_secret_xtn, - ssl_SendEmptyExtension); + return ssl3_RegisterExtensionSender( + ss, xtnData, ex_type, ssl3_SendExtendedMasterSecretXtn); } return SECSuccess; } /* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp * extension for TLS ClientHellos. */ -SECStatus -ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length = 2 /* extension_type */ + + 2 /* length(extension_data) */; + /* Only send the extension if processing is enabled. */ - if (!ss->opt.enableSignedCertTimestamps) { - return SECSuccess; + 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; } - *added = PR_TRUE; - return SECSuccess; + return extension_length; +loser: + return -1; } SECStatus -ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, +ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { /* We do not yet know whether we'll be resuming a session or creating @@ -1777,34 +2080,54 @@ ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *x } *scts = *data; /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } -SECStatus +PRInt32 ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps; - SECStatus rv; if (!scts->len) { /* No timestamps to send */ - return SECSuccess; + return 0; } - rv = sslBuffer_Append(buf, scts->data, scts->len); - if (rv != SECSuccess) { - return SECFailure; + 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; + } } - *added = PR_TRUE; - return SECSuccess; + return extension_length; } SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data) { if (data->len != 0) { @@ -1813,25 +2136,22 @@ ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; PORT_Assert(ss->sec.isServer); - return ssl3_RegisterExtensionSender(ss, xtnData, - ssl_signed_cert_timestamp_xtn, - ssl3_ServerSendSignedCertTimestampXtn); + return ssl3_RegisterExtensionSender( + ss, xtnData, ex_type, 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, +ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, 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); @@ -1840,9 +2160,10 @@ ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, for (i = data->len; --i > 0;) { if (data->data[i] == 0) { /* indicate that we should send a reply */ - return ssl3_RegisterExtensionSender( - ss, xtnData, ssl_ec_point_formats_xtn, - &ssl3_SendSupportedPointFormatsXtn); + SECStatus rv; + rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, + &ssl3_SendSupportedPointFormatsXtn); + return rv; } } @@ -1927,7 +2248,7 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) */ SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) + PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -1937,7 +2258,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, ssl_supported_groups_xtn, + rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type, &ssl_SendSupportedGroupsXtn); if (rv != SECSuccess) { return SECFailure; /* error already set. */ @@ -1945,7 +2266,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Remember that we negotiated this extension. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } diff --git a/security/nss/lib/ssl/ssl3exthandle.h b/security/nss/lib/ssl/ssl3exthandle.h index b84bd074c..5fdbe9053 100644 --- a/security/nss/lib/ssl/ssl3exthandle.h +++ b/security/nss/lib/ssl/ssl3exthandle.h @@ -9,114 +9,90 @@ #ifndef __ssl3exthandle_h_ #define __ssl3exthandle_h_ -#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, +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, SECItem *data); -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, +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, SECItem *data); -SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added); -SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - SECItem *data); -SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +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, 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_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_ClientSendPaddingExtension(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added); +PRInt32 ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes); -SECStatus ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added); -SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +PRInt32 ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes); +SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data); -SECStatus ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added); -SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +PRInt32 ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes); +SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data); -SECStatus ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added); -SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +PRInt32 ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes); +SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data); -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, +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, TLSExtensionData *xtnData, - 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, + PRBool append, PRUint32 maxBytes); +PRInt32 ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - 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); + PRBool append, PRUint32 maxBytes); #endif diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c index 20404f4da..cf6f4cb33 100644 --- a/security/nss/lib/ssl/ssl3gthr.c +++ b/security/nss/lib/ssl/ssl3gthr.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Gather (Read) entire SSL3 records from socket into buffer. * @@ -99,7 +98,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 = 5; + gs->remainder = ss->ssl3.hs.shortHeaders ? 2 : 5; gs->offset = 0; gs->writeOffset = 0; gs->readOffset = 0; @@ -157,7 +156,19 @@ 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. */ - gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4]; + 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]; + } } else { /* Probably an SSLv2 record header. No need to handle any * security escapes (gs->hdr[0] & 0x40) as we wouldn't get @@ -350,9 +361,6 @@ 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; @@ -386,8 +394,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) SSL3Ciphertext cText; PRBool keepGoing = PR_TRUE; - SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake", - SSL_GETPID(), ss->fd)); + SSL_TRC(30, ("ssl3_GatherCompleteHandshake")); /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake, * which requires the 1stHandshakeLock, which must be acquired before the @@ -398,12 +405,9 @@ 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. @@ -489,12 +493,18 @@ 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. */ - cText.type = (SSL3ContentType)ss->gs.hdr[0]; - cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2]; + 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]; + } 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); @@ -545,22 +555,12 @@ 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 post-handshake timers - * fire. */ - if (IS_DTLS(ss) && (ss->ssl3.hs.ws == idle_handshake)) { + /* Service the DTLS timer so that the holddown timer eventually fires. */ + if (IS_DTLS(ss)) { dtls_CheckTimer(ss); } ss->gs.readOffset = 0; diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index d1f46db97..ac31cf263 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -16,12 +16,13 @@ typedef PRUint16 SSL3ProtocolVersion; /* The TLS 1.3 draft version. Used to avoid negotiating * between incompatible pre-standard TLS 1.3 drafts. * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */ -#define TLS_1_3_DRAFT_VERSION 23 +#define TLS_1_3_DRAFT_VERSION 18 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 @@ -29,6 +30,7 @@ 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 @@ -39,18 +41,47 @@ typedef enum { content_change_cipher_spec = 20, content_alert = 21, content_handshake = 22, - content_application_data = 23, - content_alt_handshake = 24, - content_ack = 25 + content_application_data = 23 } 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 */ @@ -91,13 +122,64 @@ typedef enum { no_alert = 256 } SSL3AlertDescription; -typedef PRUint8 SSL3Random[SSL3_RANDOM_LENGTH]; +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 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 */ @@ -119,6 +201,24 @@ 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 { @@ -135,9 +235,17 @@ 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, @@ -148,8 +256,16 @@ 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 deleted file mode 100644 index 3d5f9d1f1..000000000 --- a/security/nss/lib/ssl/sslbloom.c +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 032c94b0f..000000000 --- a/security/nss/lib/ssl/sslbloom.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- 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 6cd02e402..cc1d3c683 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(const sslSocket *ss) +ssl_SetupCAList(sslSocket *ss) { if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_server_ca_list.setup, &ssl_SetupCAListOnce, @@ -58,11 +58,11 @@ ssl_SetupCAList(const sslSocket *ss) } SECStatus -ssl_GetCertificateRequestCAs(const sslSocket *ss, unsigned int *calen, - const SECItem **names, unsigned int *nnames) +ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calen, + SECItem **names, unsigned int *nnames) { - const SECItem *name; - const CERTDistNames *ca_list; + SECItem *name; + CERTDistNames *ca_list; unsigned int i; *calen = 0; diff --git a/security/nss/lib/ssl/sslencode.c b/security/nss/lib/ssl/sslencode.c deleted file mode 100644 index 2f127fe8f..000000000 --- a/security/nss/lib/ssl/sslencode.c +++ /dev/null @@ -1,296 +0,0 @@ -/* -*- 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 deleted file mode 100644 index a1b04d88f..000000000 --- a/security/nss/lib/ssl/sslencode.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- 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 90815dd79..865077cda 100644 --- a/security/nss/lib/ssl/sslerr.h +++ b/security/nss/lib/ssl/sslerr.h @@ -234,7 +234,6 @@ 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), @@ -247,19 +246,6 @@ 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 deleted file mode 100644 index 569add861..000000000 --- a/security/nss/lib/ssl/sslexp.h +++ /dev/null @@ -1,358 +0,0 @@ -/* - * 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 dee9aa20f..64694b0df 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -19,7 +19,6 @@ #include "secport.h" #include "secerr.h" #include "sslerr.h" -#include "sslexp.h" #include "ssl3prot.h" #include "hasht.h" #include "nssilock.h" @@ -35,11 +34,36 @@ #include "sslt.h" /* for some formerly private types, now public */ typedef struct sslSocketStr sslSocket; -typedef struct sslNamedGroupDefStr sslNamedGroupDef; -#include "sslencode.h" -#include "sslexp.h" +typedef struct ssl3CipherSpecStr ssl3CipherSpec; #include "ssl3ext.h" -#include "sslspec.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 #if defined(DEBUG) || defined(TRACE) #ifdef __cplusplus @@ -136,7 +160,7 @@ typedef enum { ticket_allow_psk_sign_auth = 16 } TLS13SessionTicketFlags; -struct sslNamedGroupDefStr { +typedef struct { /* The name is the value that is encoded on the wire in TLS. */ SSLNamedGroup name; /* The number of bits in the group. */ @@ -148,8 +172,9 @@ struct sslNamedGroupDefStr { 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; @@ -158,6 +183,8 @@ 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; @@ -174,6 +201,9 @@ 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 { @@ -199,9 +229,20 @@ 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 { @@ -241,7 +282,7 @@ typedef struct sslOptionsStr { unsigned int detectRollBack : 1; unsigned int noLocks : 1; unsigned int enableSessionTickets : 1; - unsigned int enableDeflate : 1; /* Deprecated. */ + unsigned int enableDeflate : 1; unsigned int enableRenegotiation : 2; unsigned int requireSafeNegotiation : 1; unsigned int enableFalseStart : 1; @@ -256,7 +297,7 @@ typedef struct sslOptionsStr { unsigned int enableSignedCertTimestamps : 1; unsigned int requireDHENamedGroups : 1; unsigned int enable0RttData : 1; - unsigned int enableTls13CompatMode : 1; + unsigned int enableShortHeaders : 1; } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -341,13 +382,136 @@ 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, @@ -363,7 +527,7 @@ struct sslSessionIDStr { sslSessionID *next; /* chain used for client sockets, only */ Cached cached; int references; - PRTime lastAccessTime; + PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */ /* 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. @@ -381,15 +545,13 @@ struct sslSessionIDStr { SSL3ProtocolVersion version; - PRTime creationTime; - PRTime expirationTime; + PRUint32 creationTime; /* seconds since Jan 1, 1970 */ + PRUint32 expirationTime; /* seconds since Jan 1, 1970 */ SSLAuthType authType; PRUint32 authKeyBits; SSLKEAType keaType; PRUint32 keaKeyBits; - SSLNamedGroup keaGroup; - SSLSignatureScheme sigScheme; union { struct { @@ -398,6 +560,7 @@ struct sslSessionIDStr { PRUint8 sessionID[SSL3_SESSIONID_BYTES]; ssl3CipherSuite cipherSuite; + SSLCompressionMethod compression; int policy; ssl3SidKeys keys; /* mechanism used to wrap master secret */ @@ -464,13 +627,13 @@ struct sslSessionIDStr { } u; }; -struct ssl3CipherSuiteDefStr { +typedef 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. @@ -493,6 +656,37 @@ 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) */ @@ -510,7 +704,6 @@ typedef enum { typedef enum { idle_handshake, wait_client_hello, - wait_end_of_early_data, wait_client_cert, wait_client_key, wait_cert_verify, @@ -567,15 +760,14 @@ typedef enum { handshake_hash_record } SSL3HandshakeHashType; -// A DTLS Timer. -typedef void (*DTLSTimerCb)(sslSocket *); - -typedef struct { - const char *label; - DTLSTimerCb cb; - PRIntervalTime started; - PRUint32 timeout; -} dtlsTimer; +/* 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; /* ** This is the "hs" member of the "ssl3" struct. @@ -599,12 +791,13 @@ 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 */ - SSLHandshakeType msg_type; + SSL3HandshakeType msg_type; unsigned long msg_len; PRBool isResuming; /* we are resuming (not used in TLS 1.3) */ PRBool sendingSCSV; /* instead of empty RI */ @@ -641,25 +834,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. */ - 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 + 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 * with a client. For client - is * always set to NULL.*/ @@ -676,37 +869,22 @@ typedef struct SSL3HandshakeStateStr { PK11SymKey *serverTrafficSecret; /* traffic keys */ PK11SymKey *earlyExporterSecret; /* for 0-RTT exporters */ PK11SymKey *exporterSecret; /* for exporters */ - 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. */ + /* 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. */ } 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: @@ -726,10 +904,6 @@ 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; @@ -750,7 +924,9 @@ 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 */ @@ -819,12 +995,11 @@ 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. */ /* @@ -837,13 +1012,11 @@ typedef struct SessionTicketStr { PRBool extendedMasterSecretUsed; ClientAuthenticationType client_auth_type; SECItem peer_cert; - PRTime timestamp; + PRUint32 timestamp; PRUint32 flags; SECItem srvName; /* negotiated server name */ SECItem alpnSelection; PRUint32 maxEarlyData; - PRUint32 ticketAgeBaseline; - SECItem applicationToken; } SessionTicket; /* @@ -893,7 +1066,6 @@ struct sslSecurityInfoStr { SSLKEAType keaType; PRUint32 keaKeyBits; const sslNamedGroupDef *keaGroup; - const sslNamedGroupDef *originalKeaGroup; /* The selected certificate (for servers only). */ const sslServerCert *serverCert; @@ -979,9 +1151,6 @@ 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 */ @@ -1072,7 +1241,6 @@ 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; @@ -1163,10 +1331,14 @@ 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 SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret, - PRBool derive); +extern void ssl3_InitCipherSpec(ssl3CipherSpec *spec); extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server); extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, const char *urlSvrName); @@ -1191,20 +1363,11 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled); extern SECStatus ssl3_ConstrainRangeByPolicy(void); -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_InitState(sslSocket *ss); 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 @@ -1217,14 +1380,21 @@ extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, const PRUint8 *pIn, PRInt32 nIn, PRInt32 flags); -/* Clear any PRCList, optionally calling f on the value. */ -void ssl_ClearPRCList(PRCList *list, void (*f)(void *)); +#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 /* - * Make sure there is room in the write buffer for padding and - * cryptographic expansions. + * make sure there is room in the write buffer for padding and + * other compression and cryptographic expansions. */ -#define SSL3_BUFFER_FUDGE 100 +#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION #define SSL_LOCK_READER(ss) \ if (ss->recvLock) \ @@ -1377,7 +1547,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, unsigned int length, PRUint8 padding); + sslSocket *ss, unsigned char *buffer, int length, PRUint8 padding); SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type); @@ -1413,7 +1583,7 @@ extern PRBool ssl_HaveEphemeralKeyPair(const sslSocket *ss, const sslNamedGroupDef *groupDef); extern void ssl_FreeEphemeralKeyPairs(sslSocket *ss); -extern SECStatus ssl_AppendPaddedDHKeyShare(sslBuffer *buf, +extern SECStatus ssl_AppendPaddedDHKeyShare(const sslSocket *ss, const SECKEYPublicKey *pubKey, PRBool appendLength); extern const ssl3DHParams *ssl_GetDHEParams(const sslNamedGroupDef *groupDef); @@ -1475,10 +1645,6 @@ 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); @@ -1494,11 +1660,23 @@ 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, @@ -1506,12 +1684,11 @@ 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); @@ -1526,20 +1703,16 @@ 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_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid, - PK11SymKey *secret); +extern SECStatus ssl3_CacheWrappedMasterSecret( + sslSocket *ss, sslSessionID *sid, ssl3CipherSpec *spec); 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, - const PRUint8 *appToken, - unsigned int appTokenLen, - PK11SymKey *secret, SECItem *ticket_data); -SECStatus SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token, - unsigned int tokenLen); + const NewSessionTicket *ticket_input, + SECItem *ticket_data); SECStatus ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair); SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName, @@ -1555,7 +1728,7 @@ extern void ssl_FreePRSocket(PRFileDesc *fd); /* Internal config function so SSL3 can initialize the present state of * various ciphers */ -extern unsigned int ssl3_config_match_init(sslSocket *); +extern int ssl3_config_match_init(sslSocket *); /* calls for accessing wrapping keys across processes. */ extern SECStatus @@ -1585,11 +1758,44 @@ 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); @@ -1601,21 +1807,17 @@ 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, sslBuffer *buf); -SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss, - unsigned int *calenp, - const SECItem **namesp, - unsigned int *nnamesp); +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_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, - PRUint32 *length, CERTDistNames *ca_list); + PRUint32 *length, PLArenaPool *arena, + 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, @@ -1630,9 +1832,10 @@ PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss, PK11SlotInfo *masterSecretSlot, CK_MECHANISM_TYPE masterWrapMech, void *pwArg); -SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, - PK11SymKey *secret); +SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid); 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, @@ -1644,14 +1847,11 @@ SECOidTag ssl3_HashTypeToOID(SSLHashType hashType); SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme); KeyType ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme); -SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes); - -/* Pull in DTLS functions */ -#include "dtlscon.h" +SECStatus ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite, + PRBool initHashes); /* Pull in TLS 1.3 functions */ #include "tls13con.h" -#include "dtls13con.h" /********************** misc calls *********************/ @@ -1661,27 +1861,22 @@ extern void ssl3_CheckCipherSuiteOrderConsistency(); extern int ssl_MapLowLevelError(int hiLevelError); -extern PRUint32 ssl_TimeSec(void); -#ifdef UNSAFE_FUZZER_MODE -#define ssl_TimeUsec() ((PRTime)12345678) -#else -#define ssl_TimeUsec() (PR_Now()) -#endif +extern PRUint32 ssl_Time(void); 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 4e58c5ae7..88162d814 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -2,12 +2,26 @@ /* 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) { @@ -34,58 +48,48 @@ 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; - - 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; + 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; } - inf.resumed = ss->statelessResume || ss->ssl3.hs.isResuming; - if (sid) { unsigned int sidLen; - 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.creationTime = sid->creationTime; + inf.lastAccessTime = sid->lastAccessTime; + inf.expirationTime = sid->expirationTime; inf.extendedMasterSecretUsed = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 || sid->u.ssl3.keys.extendedMasterSecretUsed) @@ -192,17 +196,17 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, #define K_ANY "TLS 1.3", ssl_kea_tls13_any /* record protection cipher */ -#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 +#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 /* "block cipher" sizes */ #define B_256 256, 256, 256 @@ -363,7 +367,8 @@ SSL_GetNegotiatedHostInfo(PRFileDesc *fd) } if (ss->sec.isServer) { - if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* TLS */ + if (ss->version > SSL_LIBRARY_VERSION_3_0 && + ss->ssl3.initialized) { /* TLS */ SECItem *crsName; ssl_GetSpecReadLock(ss); /*********************************/ crsName = &ss->ssl3.hs.srvVirtName; @@ -387,47 +392,22 @@ 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; } - /* 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; + return tls13_HkdfExpandLabelRaw(secret, + tls13_GetHash(ss), + context, contextLen, + label, labelLen, + out, outLen); } SECStatus @@ -477,9 +457,9 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, return SECFailure; } i = 0; - PORT_Memcpy(val + i, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); + PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; - PORT_Memcpy(val + i, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); + PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; if (hasContext) { val[i++] = contextLen >> 8; @@ -493,7 +473,7 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, * secret is available and we have sent ChangeCipherSpec. */ ssl_GetSpecReadLock(ss); - if (!ss->ssl3.cwSpec->masterSecret) { + if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) { 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 228834e3d..7ad1c6bc7 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_TimeSec(); + now = ssl_Time(); LOCK_CACHE; sidp = &cache; while ((sid = *sidp) != 0) { @@ -306,6 +306,8 @@ 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 " @@ -333,6 +335,7 @@ 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)); @@ -342,9 +345,9 @@ CacheSID(sslSessionID *sid) } PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0); if (!sid->creationTime) - sid->lastAccessTime = sid->creationTime = ssl_TimeUsec(); + sid->lastAccessTime = sid->creationTime = ssl_Time(); if (!sid->expirationTime) - sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC; + sid->expirationTime = sid->creationTime + expirationPeriod; /* * Put sid into the cache. Bump reference count to indicate that @@ -435,7 +438,7 @@ SSL_ClearSessionCache(void) /* returns an unsigned int containing the number of seconds in PR_Now() */ PRUint32 -ssl_TimeSec(void) +ssl_Time(void) { #ifdef UNSAFE_FUZZER_MODE return 1234; @@ -468,7 +471,7 @@ ssl_TicketTimeValid(const NewSessionTicket *ticket) endTime = ticket->received_timestamp + (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC); - return endTime > ssl_TimeUsec(); + return endTime > PR_Now(); } void diff --git a/security/nss/lib/ssl/sslreveal.c b/security/nss/lib/ssl/sslreveal.c index cc16f574d..4c124a1dc 100644 --- a/security/nss/lib/ssl/sslreveal.c +++ b/security/nss/lib/ssl/sslreveal.c @@ -92,16 +92,18 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc *socket, /* according to public API SSL_GetChannelInfo, this doesn't need a lock */ if (sslsocket->opt.useSecurity) { - /* 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); + 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); + } } return SECSuccess; diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index 3f7060f22..8bec3d327 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Various SSL functions. * @@ -201,7 +200,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) ssl_Release1stHandshakeLock(ss); ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); - ssl3_ResetExtensionData(&ss->xtnData, ss); + ssl3_ResetExtensionData(&ss->xtnData); if (!ss->TCPconnected) ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr)); @@ -343,6 +342,11 @@ 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 || @@ -431,6 +435,58 @@ 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. @@ -718,7 +774,8 @@ ssl_SecureClose(sslSocket *ss) if (!(ss->shutdownHow & ssl_SHUTDOWN_SEND) && ss->firstHsDone && - !ss->recvdCloseNotify) { + !ss->recvdCloseNotify && + ss->ssl3.initialized) { /* We don't want the final alert to be Nagle delayed. */ if (!ss->delayDisabled) { @@ -748,7 +805,8 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow) if ((sslHow & ssl_SHUTDOWN_SEND) != 0 && !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && ss->firstHsDone && - !ss->recvdCloseNotify) { + !ss->recvdCloseNotify && + ss->ssl3.initialized) { (void)SSL3_SendAlert(ss, alert_warning, close_notify); } @@ -762,55 +820,6 @@ 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) { @@ -850,17 +859,8 @@ 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,19 +942,11 @@ 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. * @@ -1249,7 +1241,14 @@ SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error) } ssl_Get1stHandshakeLock(ss); - rv = ssl3_AuthCertificateComplete(ss, error); + + if (!ss->ssl3.initialized) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; + } else { + 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 279f3c015..3ef11f7a7 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -85,12 +85,11 @@ /* ** Format of a cache entry in the shared memory. */ -PR_STATIC_ASSERT(sizeof(PRTime) == 8); struct sidCacheEntryStr { /* 16 */ PRIPv6Addr addr; /* client's IP address */ - /* 8 */ PRTime creationTime; - /* 8 */ PRTime lastAccessTime; - /* 8 */ PRTime expirationTime; + /* 4 */ PRUint32 creationTime; + /* 4 */ PRUint32 lastAccessTime; + /* 4 */ PRUint32 expirationTime; /* 2 */ PRUint16 version; /* 1 */ PRUint8 valid; /* 1 */ PRUint8 sessionIDLength; @@ -99,25 +98,25 @@ struct sidCacheEntryStr { /* 2 */ PRUint16 authKeyBits; /* 2 */ PRUint16 keaType; /* 2 */ PRUint16 keaKeyBits; - /* 4 */ PRUint32 signatureScheme; - /* 4 */ PRUint32 keaGroup; - /* 92 - common header total */ + /* 72 - common header total */ union { struct { /* 2 */ ssl3CipherSuite cipherSuite; - /* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */ + /* 2 */ PRUint16 compression; /* SSLCompressionMethod */ + + /* 54 */ 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; -/*100 */} ssl3; +/*104 */} ssl3; /* force sizeof(sidCacheEntry) to be a multiple of cache line size */ struct { - /*116 */ PRUint8 filler[116]; /* 92+116==208, a multiple of 16 */ + /*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */ } forceSize; } u; }; @@ -283,7 +282,7 @@ LockSidCacheLock(sidCacheLock *lock, PRUint32 now) if (rv != SECSuccess) return 0; if (!now) - now = ssl_TimeSec(); + now = ssl_Time(); lock->timeStamp = now; lock->pid = myPid; return now; @@ -299,7 +298,7 @@ UnlockSidCacheLock(sidCacheLock *lock) return rv; } -/* returns the value of ssl_TimeSec on success, zero on failure. */ +/* returns the value of ssl_Time on success, zero on failure. */ static PRUint32 LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now) { @@ -433,10 +432,9 @@ 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; @@ -454,10 +452,9 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x " "cipherSuite=%d", - 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)); + 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)); } /* @@ -479,6 +476,7 @@ 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) { @@ -543,8 +541,6 @@ 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; @@ -752,19 +748,17 @@ ServerSessionIDCache(sslSessionID *sid) PORT_Assert(sid->creationTime != 0); if (!sid->creationTime) - sid->lastAccessTime = sid->creationTime = ssl_TimeUsec(); + sid->lastAccessTime = sid->creationTime = ssl_Time(); /* override caller's expiration time, which uses client timeout * duration, not server timeout duration. */ - sid->expirationTime = - sid->creationTime + cache->ssl3Timeout * PR_USEC_PER_SEC; + sid->expirationTime = sid->creationTime + cache->ssl3Timeout; 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 / PR_USEC_PER_SEC, - sid->u.ssl3.cipherSuite)); + sid->creationTime, sid->u.ssl3.cipherSuite)); PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength)); @@ -826,8 +820,7 @@ 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 / PR_USEC_PER_SEC, - sid->u.ssl3.cipherSuite)); + sid->creationTime, sid->u.ssl3.cipherSuite)); PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength)); set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength); now = LockSet(cache, set, 0); @@ -1093,7 +1086,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData); /* initialize the locks */ - init_time = ssl_TimeSec(); + init_time = ssl_Time(); pLock = cache->sidCacheLocks; for (locks_to_initialize = cache->numSIDCacheLocks + 3; locks_initialized < locks_to_initialize; @@ -1141,10 +1134,6 @@ 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, @@ -1156,6 +1145,10 @@ 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; @@ -1526,7 +1519,7 @@ LockPoller(void *arg) if (sharedCache->stopPolling) break; - now = ssl_TimeSec(); + now = ssl_Time(); 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 4893cb9f9..99828c85b 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -11,7 +11,6 @@ #include "cert.h" #include "keyhi.h" #include "ssl.h" -#include "sslexp.h" #include "sslimpl.h" #include "sslproto.h" #include "nspr.h" @@ -80,7 +79,11 @@ static sslOptions ssl_defaults = { PR_FALSE, /* enableSignedCertTimestamps */ PR_FALSE, /* requireDHENamedGroups */ PR_FALSE, /* enable0RttData */ - PR_FALSE /* enableTls13CompatMode */ +#ifdef NSS_ENABLE_TLS13_SHORT_HEADERS + PR_TRUE /* enableShortHeaders */ +#else + PR_FALSE /* enableShortHeaders */ +#endif }; /* @@ -107,6 +110,7 @@ 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 */ @@ -118,7 +122,6 @@ FILE *ssl_trace_iob; #ifdef NSS_ALLOW_SSLKEYLOGFILE FILE *ssl_keylog_iob; -PZLock *ssl_keylog_lock; #endif char lockStatus[] = "Locks are ENABLED. "; @@ -297,7 +300,6 @@ 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)) { @@ -307,6 +309,7 @@ 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)) { @@ -317,18 +320,6 @@ 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. @@ -363,7 +354,6 @@ ssl_DupSocket(sslSocket *os) goto loser; } } - return ss; loser: @@ -432,16 +422,9 @@ 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); } /* @@ -518,7 +501,7 @@ PrepareSocket(sslSocket *ss) } SECStatus -SSL_Enable(PRFileDesc *fd, int which, PRIntn on) +SSL_Enable(PRFileDesc *fd, int which, PRBool on) { return SSL_OptionSet(fd, which, on); } @@ -530,9 +513,9 @@ static PRBool ssl_VersionIsSupportedByPolicy( * ssl.h in the section "SSL version range setting API". */ static void -ssl_EnableTLS(SSLVersionRange *vrange, PRIntn enable) +ssl_EnableTLS(SSLVersionRange *vrange, PRBool on) { - if (enable) { + if (on) { /* don't turn it on if tls1.0 disallowed by by policy */ if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_0)) { @@ -540,14 +523,14 @@ ssl_EnableTLS(SSLVersionRange *vrange, PRIntn enable) } } if (SSL_ALL_VERSIONS_DISABLED(vrange)) { - if (enable) { + if (on) { vrange->min = SSL_LIBRARY_VERSION_TLS_1_0; vrange->max = SSL_LIBRARY_VERSION_TLS_1_0; } /* else don't change anything */ return; } - if (enable) { + if (on) { /* 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); @@ -567,9 +550,9 @@ ssl_EnableTLS(SSLVersionRange *vrange, PRIntn enable) * ssl.h in the section "SSL version range setting API". */ static void -ssl_EnableSSL3(SSLVersionRange *vrange, PRIntn enable) +ssl_EnableSSL3(SSLVersionRange *vrange, PRBool on) { - if (enable) { + if (on) { /* don't turn it on if ssl3 disallowed by by policy */ if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream, SSL_LIBRARY_VERSION_3_0)) { @@ -577,14 +560,14 @@ ssl_EnableSSL3(SSLVersionRange *vrange, PRIntn enable) } } if (SSL_ALL_VERSIONS_DISABLED(vrange)) { - if (enable) { + if (on) { vrange->min = SSL_LIBRARY_VERSION_3_0; vrange->max = SSL_LIBRARY_VERSION_3_0; } /* else don't change anything */ return; } - if (enable) { + if (on) { /* 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. @@ -603,7 +586,7 @@ ssl_EnableSSL3(SSLVersionRange *vrange, PRIntn enable) } SECStatus -SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) +SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) { sslSocket *ss = ssl_FindSocket(fd); SECStatus rv = SECSuccess; @@ -622,63 +605,63 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) case SSL_SOCKS: ss->opt.useSocks = PR_FALSE; rv = PrepareSocket(ss); - if (val) { + if (on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SSL_SECURITY: - ss->opt.useSecurity = val; + ss->opt.useSecurity = on; rv = PrepareSocket(ss); break; case SSL_REQUEST_CERTIFICATE: - ss->opt.requestCertificate = val; + ss->opt.requestCertificate = on; break; case SSL_REQUIRE_CERTIFICATE: - ss->opt.requireCertificate = val; + ss->opt.requireCertificate = on; break; case SSL_HANDSHAKE_AS_CLIENT: - if (ss->opt.handshakeAsServer && val) { + if (ss->opt.handshakeAsServer && on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->opt.handshakeAsClient = val; + ss->opt.handshakeAsClient = on; break; case SSL_HANDSHAKE_AS_SERVER: - if (ss->opt.handshakeAsClient && val) { + if (ss->opt.handshakeAsClient && on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->opt.handshakeAsServer = val; + ss->opt.handshakeAsServer = on; break; case SSL_ENABLE_TLS: if (IS_DTLS(ss)) { - if (val) { + if (on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; /* not allowed */ } break; } - ssl_EnableTLS(&ss->vrange, val); + ssl_EnableTLS(&ss->vrange, on); break; case SSL_ENABLE_SSL3: if (IS_DTLS(ss)) { - if (val) { + if (on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; /* not allowed */ } break; } - ssl_EnableSSL3(&ss->vrange, val); + ssl_EnableSSL3(&ss->vrange, on); break; case SSL_ENABLE_SSL2: @@ -687,26 +670,26 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) * However, if an old application requests to disable SSL v2, * we shouldn't fail. */ - if (val) { + if (on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SSL_NO_CACHE: - ss->opt.noCache = val; + ss->opt.noCache = on; break; case SSL_ENABLE_FDX: - if (val && ss->opt.noLocks) { + if (on && ss->opt.noLocks) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } - ss->opt.fdx = val; + ss->opt.fdx = on; break; case SSL_ROLLBACK_DETECTION: - ss->opt.detectRollBack = val; + ss->opt.detectRollBack = on; break; case SSL_NO_STEP_DOWN: @@ -716,14 +699,14 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) break; case SSL_NO_LOCKS: - if (val && ss->opt.fdx) { + if (on && ss->opt.fdx) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } - if (val && ssl_force_locks) - val = PR_FALSE; /* silent override */ - ss->opt.noLocks = val; - if (val) { + if (on && ssl_force_locks) + on = PR_FALSE; /* silent override */ + ss->opt.noLocks = on; + if (on) { locksEverDisabled = PR_TRUE; strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED."); } else if (!holdingLocks) { @@ -735,75 +718,71 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) break; case SSL_ENABLE_SESSION_TICKETS: - ss->opt.enableSessionTickets = val; + ss->opt.enableSessionTickets = on; break; case SSL_ENABLE_DEFLATE: - ss->opt.enableDeflate = val; + ss->opt.enableDeflate = on; break; case SSL_ENABLE_RENEGOTIATION: - if (IS_DTLS(ss) && val != SSL_RENEGOTIATE_NEVER) { + if (IS_DTLS(ss) && on != SSL_RENEGOTIATE_NEVER) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->opt.enableRenegotiation = val; + ss->opt.enableRenegotiation = on; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - ss->opt.requireSafeNegotiation = val; + ss->opt.requireSafeNegotiation = on; break; case SSL_ENABLE_FALSE_START: - ss->opt.enableFalseStart = val; + ss->opt.enableFalseStart = on; break; case SSL_CBC_RANDOM_IV: - ss->opt.cbcRandomIV = val; + ss->opt.cbcRandomIV = on; break; case SSL_ENABLE_OCSP_STAPLING: - ss->opt.enableOCSPStapling = val; + ss->opt.enableOCSPStapling = on; break; case SSL_ENABLE_NPN: break; case SSL_ENABLE_ALPN: - ss->opt.enableALPN = val; + ss->opt.enableALPN = on; break; case SSL_REUSE_SERVER_ECDHE_KEY: - ss->opt.reuseServerECDHEKey = val; + ss->opt.reuseServerECDHEKey = on; break; case SSL_ENABLE_FALLBACK_SCSV: - ss->opt.enableFallbackSCSV = val; + ss->opt.enableFallbackSCSV = on; break; case SSL_ENABLE_SERVER_DHE: - ss->opt.enableServerDhe = val; + ss->opt.enableServerDhe = on; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - ss->opt.enableExtendedMS = val; + ss->opt.enableExtendedMS = on; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - ss->opt.enableSignedCertTimestamps = val; + ss->opt.enableSignedCertTimestamps = on; break; case SSL_REQUIRE_DH_NAMED_GROUPS: - ss->opt.requireDHENamedGroups = val; + ss->opt.requireDHENamedGroups = on; break; case SSL_ENABLE_0RTT_DATA: - ss->opt.enable0RttData = val; - break; - - case SSL_ENABLE_TLS13_COMPAT_MODE: - ss->opt.enableTls13CompatMode = val; + ss->opt.enable0RttData = on; break; default: @@ -825,19 +804,19 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val) } SECStatus -SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal) +SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) { sslSocket *ss = ssl_FindSocket(fd); SECStatus rv = SECSuccess; - PRIntn val = PR_FALSE; + PRBool on = PR_FALSE; - if (!pVal) { + if (!pOn) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd)); - *pVal = PR_FALSE; + *pOn = PR_FALSE; return SECFailure; } @@ -846,101 +825,98 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal) switch (which) { case SSL_SOCKS: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_SECURITY: - val = ss->opt.useSecurity; + on = ss->opt.useSecurity; break; case SSL_REQUEST_CERTIFICATE: - val = ss->opt.requestCertificate; + on = ss->opt.requestCertificate; break; case SSL_REQUIRE_CERTIFICATE: - val = ss->opt.requireCertificate; + on = ss->opt.requireCertificate; break; case SSL_HANDSHAKE_AS_CLIENT: - val = ss->opt.handshakeAsClient; + on = ss->opt.handshakeAsClient; break; case SSL_HANDSHAKE_AS_SERVER: - val = ss->opt.handshakeAsServer; + on = ss->opt.handshakeAsServer; break; case SSL_ENABLE_TLS: - val = ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_0; + on = ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_0; break; case SSL_ENABLE_SSL3: - val = ss->vrange.min == SSL_LIBRARY_VERSION_3_0; + on = ss->vrange.min == SSL_LIBRARY_VERSION_3_0; break; case SSL_ENABLE_SSL2: case SSL_V2_COMPATIBLE_HELLO: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_NO_CACHE: - val = ss->opt.noCache; + on = ss->opt.noCache; break; case SSL_ENABLE_FDX: - val = ss->opt.fdx; + on = ss->opt.fdx; break; case SSL_ROLLBACK_DETECTION: - val = ss->opt.detectRollBack; + on = ss->opt.detectRollBack; break; case SSL_NO_STEP_DOWN: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_BYPASS_PKCS11: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_NO_LOCKS: - val = ss->opt.noLocks; + on = ss->opt.noLocks; break; case SSL_ENABLE_SESSION_TICKETS: - val = ss->opt.enableSessionTickets; + on = ss->opt.enableSessionTickets; break; case SSL_ENABLE_DEFLATE: - val = ss->opt.enableDeflate; + on = ss->opt.enableDeflate; break; case SSL_ENABLE_RENEGOTIATION: - val = ss->opt.enableRenegotiation; + on = ss->opt.enableRenegotiation; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - val = ss->opt.requireSafeNegotiation; + on = ss->opt.requireSafeNegotiation; break; case SSL_ENABLE_FALSE_START: - val = ss->opt.enableFalseStart; + on = ss->opt.enableFalseStart; break; case SSL_CBC_RANDOM_IV: - val = ss->opt.cbcRandomIV; + on = ss->opt.cbcRandomIV; break; case SSL_ENABLE_OCSP_STAPLING: - val = ss->opt.enableOCSPStapling; + on = ss->opt.enableOCSPStapling; break; case SSL_ENABLE_NPN: - val = ss->opt.enableNPN; + on = ss->opt.enableNPN; break; case SSL_ENABLE_ALPN: - val = ss->opt.enableALPN; + on = ss->opt.enableALPN; break; case SSL_REUSE_SERVER_ECDHE_KEY: - val = ss->opt.reuseServerECDHEKey; + on = ss->opt.reuseServerECDHEKey; break; case SSL_ENABLE_FALLBACK_SCSV: - val = ss->opt.enableFallbackSCSV; + on = ss->opt.enableFallbackSCSV; break; case SSL_ENABLE_SERVER_DHE: - val = ss->opt.enableServerDhe; + on = ss->opt.enableServerDhe; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - val = ss->opt.enableExtendedMS; + on = ss->opt.enableExtendedMS; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - val = ss->opt.enableSignedCertTimestamps; + on = ss->opt.enableSignedCertTimestamps; break; case SSL_REQUIRE_DH_NAMED_GROUPS: - val = ss->opt.requireDHENamedGroups; + on = ss->opt.requireDHENamedGroups; break; case SSL_ENABLE_0RTT_DATA: - val = ss->opt.enable0RttData; - break; - case SSL_ENABLE_TLS13_COMPAT_MODE: - val = ss->opt.enableTls13CompatMode; + on = ss->opt.enable0RttData; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -950,17 +926,17 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal) ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); - *pVal = val; + *pOn = on; return rv; } SECStatus -SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal) +SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) { SECStatus rv = SECSuccess; - PRIntn val = PR_FALSE; + PRBool on = PR_FALSE; - if (!pVal) { + if (!pOn) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } @@ -969,117 +945,114 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal) switch (which) { case SSL_SOCKS: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_SECURITY: - val = ssl_defaults.useSecurity; + on = ssl_defaults.useSecurity; break; case SSL_REQUEST_CERTIFICATE: - val = ssl_defaults.requestCertificate; + on = ssl_defaults.requestCertificate; break; case SSL_REQUIRE_CERTIFICATE: - val = ssl_defaults.requireCertificate; + on = ssl_defaults.requireCertificate; break; case SSL_HANDSHAKE_AS_CLIENT: - val = ssl_defaults.handshakeAsClient; + on = ssl_defaults.handshakeAsClient; break; case SSL_HANDSHAKE_AS_SERVER: - val = ssl_defaults.handshakeAsServer; + on = ssl_defaults.handshakeAsServer; break; case SSL_ENABLE_TLS: - val = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0; + on = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0; break; case SSL_ENABLE_SSL3: - val = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0; + on = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0; break; case SSL_ENABLE_SSL2: case SSL_V2_COMPATIBLE_HELLO: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_NO_CACHE: - val = ssl_defaults.noCache; + on = ssl_defaults.noCache; break; case SSL_ENABLE_FDX: - val = ssl_defaults.fdx; + on = ssl_defaults.fdx; break; case SSL_ROLLBACK_DETECTION: - val = ssl_defaults.detectRollBack; + on = ssl_defaults.detectRollBack; break; case SSL_NO_STEP_DOWN: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_BYPASS_PKCS11: - val = PR_FALSE; + on = PR_FALSE; break; case SSL_NO_LOCKS: - val = ssl_defaults.noLocks; + on = ssl_defaults.noLocks; break; case SSL_ENABLE_SESSION_TICKETS: - val = ssl_defaults.enableSessionTickets; + on = ssl_defaults.enableSessionTickets; break; case SSL_ENABLE_DEFLATE: - val = ssl_defaults.enableDeflate; + on = ssl_defaults.enableDeflate; break; case SSL_ENABLE_RENEGOTIATION: - val = ssl_defaults.enableRenegotiation; + on = ssl_defaults.enableRenegotiation; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - val = ssl_defaults.requireSafeNegotiation; + on = ssl_defaults.requireSafeNegotiation; break; case SSL_ENABLE_FALSE_START: - val = ssl_defaults.enableFalseStart; + on = ssl_defaults.enableFalseStart; break; case SSL_CBC_RANDOM_IV: - val = ssl_defaults.cbcRandomIV; + on = ssl_defaults.cbcRandomIV; break; case SSL_ENABLE_OCSP_STAPLING: - val = ssl_defaults.enableOCSPStapling; + on = ssl_defaults.enableOCSPStapling; break; case SSL_ENABLE_NPN: - val = ssl_defaults.enableNPN; + on = ssl_defaults.enableNPN; break; case SSL_ENABLE_ALPN: - val = ssl_defaults.enableALPN; + on = ssl_defaults.enableALPN; break; case SSL_REUSE_SERVER_ECDHE_KEY: - val = ssl_defaults.reuseServerECDHEKey; + on = ssl_defaults.reuseServerECDHEKey; break; case SSL_ENABLE_FALLBACK_SCSV: - val = ssl_defaults.enableFallbackSCSV; + on = ssl_defaults.enableFallbackSCSV; break; case SSL_ENABLE_SERVER_DHE: - val = ssl_defaults.enableServerDhe; + on = ssl_defaults.enableServerDhe; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - val = ssl_defaults.enableExtendedMS; + on = ssl_defaults.enableExtendedMS; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - val = ssl_defaults.enableSignedCertTimestamps; + on = ssl_defaults.enableSignedCertTimestamps; break; case SSL_ENABLE_0RTT_DATA: - val = ssl_defaults.enable0RttData; - break; - case SSL_ENABLE_TLS13_COMPAT_MODE: - val = ssl_defaults.enableTls13CompatMode; + on = ssl_defaults.enable0RttData; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } - *pVal = val; + *pOn = on; return rv; } /* XXX Use Global Lock to protect this stuff. */ SECStatus -SSL_EnableDefault(int which, PRIntn val) +SSL_EnableDefault(int which, PRBool on) { - return SSL_OptionSetDefault(which, val); + return SSL_OptionSetDefault(which, on); } SECStatus -SSL_OptionSetDefault(PRInt32 which, PRIntn val) +SSL_OptionSetDefault(PRInt32 which, PRBool on) { SECStatus status = ssl_Init(); @@ -1092,46 +1065,46 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val) switch (which) { case SSL_SOCKS: ssl_defaults.useSocks = PR_FALSE; - if (val) { + if (on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } break; case SSL_SECURITY: - ssl_defaults.useSecurity = val; + ssl_defaults.useSecurity = on; break; case SSL_REQUEST_CERTIFICATE: - ssl_defaults.requestCertificate = val; + ssl_defaults.requestCertificate = on; break; case SSL_REQUIRE_CERTIFICATE: - ssl_defaults.requireCertificate = val; + ssl_defaults.requireCertificate = on; break; case SSL_HANDSHAKE_AS_CLIENT: - if (ssl_defaults.handshakeAsServer && val) { + if (ssl_defaults.handshakeAsServer && on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - ssl_defaults.handshakeAsClient = val; + ssl_defaults.handshakeAsClient = on; break; case SSL_HANDSHAKE_AS_SERVER: - if (ssl_defaults.handshakeAsClient && val) { + if (ssl_defaults.handshakeAsClient && on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - ssl_defaults.handshakeAsServer = val; + ssl_defaults.handshakeAsServer = on; break; case SSL_ENABLE_TLS: - ssl_EnableTLS(&versions_defaults_stream, val); + ssl_EnableTLS(&versions_defaults_stream, on); break; case SSL_ENABLE_SSL3: - ssl_EnableSSL3(&versions_defaults_stream, val); + ssl_EnableSSL3(&versions_defaults_stream, on); break; case SSL_ENABLE_SSL2: @@ -1140,26 +1113,26 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val) * However, if an old application requests to disable SSL v2, * we shouldn't fail. */ - if (val) { + if (on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } break; case SSL_NO_CACHE: - ssl_defaults.noCache = val; + ssl_defaults.noCache = on; break; case SSL_ENABLE_FDX: - if (val && ssl_defaults.noLocks) { + if (on && ssl_defaults.noLocks) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - ssl_defaults.fdx = val; + ssl_defaults.fdx = on; break; case SSL_ROLLBACK_DETECTION: - ssl_defaults.detectRollBack = val; + ssl_defaults.detectRollBack = on; break; case SSL_NO_STEP_DOWN: @@ -1169,80 +1142,76 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val) break; case SSL_NO_LOCKS: - if (val && ssl_defaults.fdx) { + if (on && ssl_defaults.fdx) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - if (val && ssl_force_locks) - val = PR_FALSE; /* silent override */ - ssl_defaults.noLocks = val; - if (val) { + if (on && ssl_force_locks) + on = PR_FALSE; /* silent override */ + ssl_defaults.noLocks = on; + if (on) { locksEverDisabled = PR_TRUE; strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED."); } break; case SSL_ENABLE_SESSION_TICKETS: - ssl_defaults.enableSessionTickets = val; + ssl_defaults.enableSessionTickets = on; break; case SSL_ENABLE_DEFLATE: - ssl_defaults.enableDeflate = val; + ssl_defaults.enableDeflate = on; break; case SSL_ENABLE_RENEGOTIATION: - ssl_defaults.enableRenegotiation = val; + ssl_defaults.enableRenegotiation = on; break; case SSL_REQUIRE_SAFE_NEGOTIATION: - ssl_defaults.requireSafeNegotiation = val; + ssl_defaults.requireSafeNegotiation = on; break; case SSL_ENABLE_FALSE_START: - ssl_defaults.enableFalseStart = val; + ssl_defaults.enableFalseStart = on; break; case SSL_CBC_RANDOM_IV: - ssl_defaults.cbcRandomIV = val; + ssl_defaults.cbcRandomIV = on; break; case SSL_ENABLE_OCSP_STAPLING: - ssl_defaults.enableOCSPStapling = val; + ssl_defaults.enableOCSPStapling = on; break; case SSL_ENABLE_NPN: break; case SSL_ENABLE_ALPN: - ssl_defaults.enableALPN = val; + ssl_defaults.enableALPN = on; break; case SSL_REUSE_SERVER_ECDHE_KEY: - ssl_defaults.reuseServerECDHEKey = val; + ssl_defaults.reuseServerECDHEKey = on; break; case SSL_ENABLE_FALLBACK_SCSV: - ssl_defaults.enableFallbackSCSV = val; + ssl_defaults.enableFallbackSCSV = on; break; case SSL_ENABLE_SERVER_DHE: - ssl_defaults.enableServerDhe = val; + ssl_defaults.enableServerDhe = on; break; case SSL_ENABLE_EXTENDED_MASTER_SECRET: - ssl_defaults.enableExtendedMS = val; + ssl_defaults.enableExtendedMS = on; break; case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: - ssl_defaults.enableSignedCertTimestamps = val; + ssl_defaults.enableSignedCertTimestamps = on; break; case SSL_ENABLE_0RTT_DATA: - ssl_defaults.enable0RttData = val; - break; - - case SSL_ENABLE_TLS13_COMPAT_MODE: - ssl_defaults.enableTls13CompatMode = val; + ssl_defaults.enable0RttData = on; break; default: @@ -2155,25 +2124,6 @@ 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)); @@ -2264,7 +2214,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. @@ -3174,7 +3124,7 @@ ssl_WriteV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 vectors, } blocking = ssl_FdIsBlocking(fd); -#define K16 ((int)sizeof(buf)) +#define K16 sizeof(buf) #define KILL_VECTORS \ while (vectors && !iov->iov_len) { \ ++iov; \ @@ -3461,6 +3411,7 @@ ssl_InitIOLayer(void) { ssl_layer_id = PR_GetUniqueIdentity("SSL"); ssl_SetupIOMethods(); + ssl_inited = PR_TRUE; return PR_SUCCESS; } @@ -3470,13 +3421,15 @@ ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, PRDescIdentity id) PRFileDesc *layer = NULL; PRStatus status; - status = PR_CallOnce(&initIoLayerOnce, &ssl_InitIOLayer); - if (status != PR_SUCCESS) { - goto loser; + if (!ssl_inited) { + 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; @@ -3589,12 +3542,6 @@ 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 @@ -3799,6 +3746,7 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) SECStatus rv; sslSocket *ss; int i; + ssl_SetDefaultsFromEnvironment(); if (ssl_force_locks) @@ -3829,7 +3777,6 @@ 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(); @@ -3857,11 +3804,7 @@ 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, ss); - PR_INIT_CLIST(&ss->ssl3.hs.dtlsSentHandshake); - PR_INIT_CLIST(&ss->ssl3.hs.dtlsRcvdHandshake); - dtls_InitTimers(ss); - + ssl3_InitExtensionData(&ss->xtnData); if (makeLocks) { rv = ssl_MakeLocks(ss); if (rv != SECSuccess) @@ -3873,10 +3816,6 @@ 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: @@ -3901,69 +3840,3 @@ 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 deleted file mode 100644 index 26c3eb546..000000000 --- a/security/nss/lib/ssl/sslspec.c +++ /dev/null @@ -1,273 +0,0 @@ -/* -*- 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 deleted file mode 100644 index 729ac1006..000000000 --- a/security/nss/lib/ssl/sslspec.h +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- 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 ce8f6e281..bd9a2ae88 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/lib/ssl/sslt.h @@ -13,28 +13,6 @@ #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; @@ -297,14 +275,6 @@ 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; @@ -425,19 +395,16 @@ typedef enum { ssl_padding_xtn = 21, ssl_extended_master_secret_xtn = 23, ssl_session_ticket_xtn = 35, - /* 40 was used in draft versions of TLS 1.3; it is now reserved. */ + ssl_tls13_key_share_xtn = 40, 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, /* 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_tls13_ticket_early_data_info_xtn = 46, + ssl_next_proto_nego_xtn = 13172, ssl_renegotiation_info_xtn = 0xff01, - ssl_tls13_short_header_xtn = 0xff03 /* Deprecated. */ + ssl_tls13_short_header_xtn = 0xff03 } 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 1fecaf3f8..560493848 100644 --- a/security/nss/lib/ssl/tls13con.c +++ b/security/nss/lib/ssl/tls13con.c @@ -17,14 +17,23 @@ #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" -static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, +typedef enum { + TrafficKeyClearText = 0, + TrafficKeyEarlyApplicationData = 1, + TrafficKeyHandshake = 2, + TrafficKeyApplicationData = 3 +} TrafficKeyType; + +typedef enum { + CipherSpecRead, + CipherSpecWrite, +} CipherSpecDirection; + +static SECStatus tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, CipherSpecDirection install, PRBool deleteSecret); static SECStatus tls13_AESGCM( @@ -44,9 +53,8 @@ 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, - const PRUint8 *token, unsigned int tokenLen); +static SECStatus tls13_SendHelloRetryRequest(sslSocket *ss, + const sslNamedGroupDef *selectedGroup); static SECStatus tls13_HandleServerKeyShare(sslSocket *ss); static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, @@ -54,46 +62,40 @@ 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); + sslSocket *ss, PRUint8 *b, PRUint32 length, + SSL3Hashes *hashes); 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 *label, - unsigned int labelLen, + const char *prefix, + const char *suffix, 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 int prefix, +static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, + unsigned long prefixLength, SSL3Hashes *hashes); -static SECStatus tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message, +static SECStatus tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, PK11SymKey *secret, PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes); static SECStatus tls13_ClientHandleFinished(sslSocket *ss, - PRUint8 *b, PRUint32 length); + PRUint8 *b, PRUint32 length, + const SSL3Hashes *hashes); static SECStatus tls13_ServerHandleFinished(sslSocket *ss, - PRUint8 *b, PRUint32 length); -static SECStatus tls13_SendNewSessionTicket(sslSocket *ss, - const PRUint8 *appToken, - unsigned int appTokenLen); + PRUint8 *b, PRUint32 length, + const SSL3Hashes *hashes); 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); @@ -105,28 +107,26 @@ static SECStatus tls13_ComputeFinished( static SECStatus tls13_SendClientSecondRound(sslSocket *ss); static SECStatus tls13_FinishHandshake(sslSocket *ss); -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 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 kHkdfLabelFinishedSecret[] = "finished"; -const char kHkdfLabelResumptionMasterSecret[] = "res master"; -const char kHkdfLabelExporterMasterSecret[] = "exp master"; -const char kHkdfLabelResumption[] = "resumption"; +const char kHkdfLabelResumptionMasterSecret[] = "resumption master secret"; +const char kHkdfLabelExporterMasterSecret[] = "exporter master secret"; const char kHkdfPurposeKey[] = "key"; const char kHkdfPurposeIv[] = "iv"; -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"; +#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; /* Belt and suspenders in case we ever add a TLS 1.4. */ PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <= @@ -165,7 +165,6 @@ 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); @@ -337,23 +336,6 @@ 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; @@ -468,8 +450,7 @@ tls13_SetupClientHello(sslSocket *ss) return SECFailure; } - ss->ssl3.hs.cipher_suite = ss->sec.ci.sid->u.ssl3.cipherSuite; - rv = ssl3_SetupCipherSuite(ss, PR_FALSE); + rv = ssl3_SetCipherSuite(ss, ss->sec.ci.sid->u.ssl3.cipherSuite, PR_FALSE); if (rv != SECSuccess) { FATAL_ERROR(ss, PORT_GetError(), internal_error); return SECFailure; @@ -577,241 +558,9 @@ 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) +tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, + PRUint32 length, SSL3Hashes *hashesPtr) { if (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) { SSL_TRC(3, ("%d: TLS13[%d]: %s successfully decrypted handshake after" @@ -822,34 +571,36 @@ tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length /* TODO(ekr@rtfm.com): Would it be better to check all the states here? */ switch (ss->ssl3.hs.msg_type) { - case ssl_hs_certificate: + case certificate: return tls13_HandleCertificate(ss, b, length); - case ssl_hs_certificate_request: + case certificate_request: return tls13_HandleCertificateRequest(ss, b, length); - case ssl_hs_certificate_verify: - return tls13_HandleCertificateVerify(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_encrypted_extensions: + case encrypted_extensions: return tls13_HandleEncryptedExtensions(ss, b, length); - case ssl_hs_new_session_ticket: + case new_session_ticket: return tls13_HandleNewSessionTicket(ss, b, length); - case ssl_hs_finished: + case finished: + if (!hashesPtr) { + FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, unexpected_message); + return SECFailure; + } if (ss->sec.isServer) { - return tls13_ServerHandleFinished(ss, b, length); + return tls13_ServerHandleFinished(ss, b, length, hashesPtr); } else { - return tls13_ClientHandleFinished(ss, b, length); + return tls13_ClientHandleFinished(ss, b, length, hashesPtr); } - 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; @@ -868,6 +619,10 @@ 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); @@ -918,55 +673,53 @@ 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 = Early Secret + * PSK -> 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 - * Derive-Secret(., "derived", "") + * Early Secret ---> Derive-Secret(., "client early traffic secret", + * | ClientHello) + * | = client_early_traffic_secret + * v + * (EC)DHE -> HKDF-Extract * | * v - *(EC)DHE -> HKDF-Extract = Handshake Secret + * Handshake Secret * | - * +-----> Derive-Secret(., "c hs traffic", - * | ClientHello...ServerHello) - * | = client_handshake_traffic_secret + * +---------> Derive-Secret(., "client handshake traffic secret", + * | ClientHello...ServerHello) + * | = client_handshake_traffic_secret + * | + * +---------> Derive-Secret(., "server handshake traffic secret", + * | ClientHello...ServerHello) + * | = server_handshake_traffic_secret * | - * +-----> Derive-Secret(., "s hs traffic", - * | ClientHello...ServerHello) - * | = server_handshake_traffic_secret * v - * Derive-Secret(., "derived", "") + * 0 -> HKDF-Extract * | * v - * 0 -> HKDF-Extract = Master Secret + * Master Secret * | - * +-----> Derive-Secret(., "c ap traffic", - * | ClientHello...Server Finished) - * | = client_traffic_secret_0 + * +---------> Derive-Secret(., "client application traffic secret", + * | ClientHello...Server Finished) + * | = client_traffic_secret_0 * | - * +-----> Derive-Secret(., "s ap traffic", - * | ClientHello...Server Finished) - * | = server_traffic_secret_0 + * +---------> Derive-Secret(., "server application traffic secret", + * | ClientHello...Server Finished) + * | = server_traffic_secret_0 * | - * +-----> Derive-Secret(., "exp master", - * | ClientHello...Server Finished) - * | = exporter_secret + * +---------> Derive-Secret(., "exporter master secret", + * | ClientHello...Client Finished) + * | = exporter_secret * | - * +-----> Derive-Secret(., "res master", - * ClientHello...Client Finished) - * = resumption_master_secret + * +---------> Derive-Secret(., "resumption master secret", + * ClientHello...Client Finished) + * = resumption_secret * */ @@ -989,43 +742,35 @@ 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 = tls13_DeriveSecretNullHash(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelPskBinderKey, - strlen(kHkdfLabelPskBinderKey), - &ss->ssl3.hs.pskBinderKey); + rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)), + hashes.u.raw, buf, 0); if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return SECFailure; } - } - PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret); - - return SECSuccess; -} + hashes.len = tls13_GetHashSize(ss); -/* 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, + NULL, kHkdfLabelPskBinderKey, &hashes, + &ss->ssl3.hs.pskBinderKey); + if (rv != SECSuccess) { + return SECFailure; + } - rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, NULL, kHkdfLabelEarlyExporterSecret, - keylogLabelEarlyExporterSecret, - &ss->ssl3.hs.earlyExporterSecret); - if (rv != SECSuccess) { - return SECFailure; + &hashes, &ss->ssl3.hs.earlyExporterSecret); + if (rv != SECSuccess) { + return SECFailure; + } + } else { + PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret); } return SECSuccess; @@ -1035,7 +780,6 @@ static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss) { SECStatus rv; - PK11SymKey *derivedSecret = NULL; PK11SymKey *newSecret = NULL; SSL_TRC(5, ("%d: TLS13[%d]: compute handshake secrets (%s)", @@ -1044,21 +788,8 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss) /* First update |currentSecret| to add |dheSecret|, if any. */ PORT_Assert(ss->ssl3.hs.currentSecret); PORT_Assert(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, + rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret, ss->ssl3.hs.dheSecret, tls13_GetHash(ss), &newSecret); - PK11_FreeSymKey(derivedSecret); - if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return rv; @@ -1069,20 +800,18 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss) ss->ssl3.hs.currentSecret = newSecret; /* Now compute |*HsTrafficSecret| */ - rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelClient, - kHkdfLabelHandshakeTrafficSecret, - keylogLabelClientHsTrafficSecret, - &ss->ssl3.hs.clientHsTrafficSecret); + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelClient, + kHkdfLabelHandshakeTrafficSecret, NULL, + &ss->ssl3.hs.clientHsTrafficSecret); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return rv; } - rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelServer, - kHkdfLabelHandshakeTrafficSecret, - keylogLabelServerHsTrafficSecret, - &ss->ssl3.hs.serverHsTrafficSecret); + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelServer, + kHkdfLabelHandshakeTrafficSecret, NULL, + &ss->ssl3.hs.serverHsTrafficSecret); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return rv; @@ -1093,19 +822,11 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss) /* Crank HKDF forward to make master secret, which we * stuff in current secret. */ - 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, + rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret, NULL, tls13_GetHash(ss), &newSecret); - PK11_FreeSymKey(derivedSecret); + if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; @@ -1121,27 +842,26 @@ tls13_ComputeApplicationSecrets(sslSocket *ss) { SECStatus rv; - rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelClient, - kHkdfLabelApplicationTrafficSecret, - keylogLabelClientTrafficSecret, - &ss->ssl3.hs.clientTrafficSecret); + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelClient, + kHkdfLabelApplicationTrafficSecret, + NULL, + &ss->ssl3.hs.clientTrafficSecret); if (rv != SECSuccess) { return SECFailure; } - rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, - kHkdfLabelServer, - kHkdfLabelApplicationTrafficSecret, - keylogLabelServerTrafficSecret, - &ss->ssl3.hs.serverTrafficSecret); + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelServer, + kHkdfLabelApplicationTrafficSecret, + NULL, + &ss->ssl3.hs.serverTrafficSecret); if (rv != SECSuccess) { return SECFailure; } - rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, - NULL, kHkdfLabelExporterMasterSecret, - keylogLabelExporterSecret, - &ss->ssl3.hs.exporterSecret); + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + NULL, kHkdfLabelExporterMasterSecret, + NULL, &ss->ssl3.hs.exporterSecret); if (rv != SECSuccess) { return SECFailure; } @@ -1153,20 +873,30 @@ static SECStatus tls13_ComputeFinalSecrets(sslSocket *ss) { SECStatus rv; + PK11SymKey *resumptionMasterSecret = NULL; - PORT_Assert(!ss->ssl3.crSpec->masterSecret); - PORT_Assert(!ss->ssl3.cwSpec->masterSecret); + PORT_Assert(!ss->ssl3.crSpec->master_secret); + PORT_Assert(!ss->ssl3.cwSpec->master_secret); - rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret, - NULL, kHkdfLabelResumptionMasterSecret, - NULL, - &ss->ssl3.hs.resumptionMasterSecret); + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + NULL, kHkdfLabelResumptionMasterSecret, + NULL, &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; } @@ -1179,8 +909,6 @@ 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. */ @@ -1233,10 +961,6 @@ 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; } @@ -1322,9 +1046,7 @@ tls13_FindKeyShareEntry(sslSocket *ss, const sslNamedGroupDef *group) } static SECStatus -tls13_NegotiateKeyExchange(sslSocket *ss, - const sslNamedGroupDef **requestedGroup, - TLS13KeyShareEntry **clientShare) +tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare) { unsigned int index; TLS13KeyShareEntry *entry = NULL; @@ -1404,16 +1126,13 @@ tls13_NegotiateKeyExchange(sslSocket *ss, SSL_TRC(3, ("%d: TLS13[%d]: group = %d", SSL_GETPID(), ss->fd, preferredGroup->name)); - /* 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; + if (!entry) { + return tls13_SendHelloRetryRequest(ss, preferredGroup); } + + PORT_Assert(preferredGroup == entry->group); + *clientShare = entry; + return SECSuccess; } @@ -1471,8 +1190,8 @@ tls13_SelectServerCert(sslSocket *ss) rv = ssl_PickSignatureScheme(ss, cert->serverKeyPair->pubKey, cert->serverKeyPair->privKey, - ss->xtnData.sigSchemes, - ss->xtnData.numSigSchemes, + ss->xtnData.clientSigSchemes, + ss->xtnData.numClientSigScheme, PR_FALSE); if (rv == SECSuccess) { /* Found one. */ @@ -1489,62 +1208,6 @@ 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) { @@ -1574,19 +1237,13 @@ tls13_NegotiateAuthentication(sslSocket *ss) SECStatus tls13_HandleClientHelloPart2(sslSocket *ss, const SECItem *suites, - sslSessionID *sid, - const PRUint8 *msg, - unsigned int len) + sslSessionID *sid) { SECStatus rv; SSL3Statistics *ssl3stats = SSL_GetStatistics(); - const sslNamedGroupDef *requestedGroup = NULL; TLS13KeyShareEntry *clientShare = NULL; - ssl3CipherSuite previousCipherSuite = 0; - const sslNamedGroupDef *previousGroup = NULL; - PRBool hrr = PR_FALSE; - - ss->ssl3.hs.endOfFlight = PR_TRUE; + int j; + ssl3CipherSuite previousCipherSuite; if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) { ss->ssl3.hs.zeroRttState = ssl_0rtt_sent; @@ -1594,59 +1251,24 @@ tls13_HandleClientHelloPart2(sslSocket *ss, #ifndef PARANOID /* Look for a matching cipher suite. */ - if (ssl3_config_match_init(ss) == 0) { /* no ciphers are working/supported by PK11 */ + j = ssl3_config_match_init(ss); + if (j <= 0) { /* no ciphers are working/supported by PK11 */ FATAL_ERROR(ss, PORT_GetError(), internal_error); goto loser; } #endif - /* Negotiate cipher suite. */ + previousCipherSuite = ss->ssl3.hs.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) { - - /* 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); + if (ss->ssl3.hs.helloRetry && + ss->ssl3.hs.cipher_suite != previousCipherSuite) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, handshake_failure); goto loser; } @@ -1674,50 +1296,13 @@ tls13_HandleClientHelloPart2(sslSocket *ss, } /* Select key exchange. */ - rv = tls13_NegotiateKeyExchange(ss, &requestedGroup, &clientShare); + rv = tls13_NegotiateKeyExchange(ss, &clientShare); if (rv != SECSuccess) { goto loser; } - /* We should get either one of these, but not both. */ - PORT_Assert((requestedGroup && !clientShare) || - (!requestedGroup && 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 we didn't find a client key share, we have to retry. */ + if (!clientShare) { if (sid) { /* Free the sid. */ ss->sec.uncache(sid); ssl_FreeSID(sid); @@ -1788,17 +1373,14 @@ tls13_HandleClientHelloPart2(sslSocket *ss, if (ss->statelessResume) { SSL3Hashes hashes; - PORT_Assert(ss->ssl3.hs.messages.len > ss->xtnData.pskBindersLen); - rv = tls13_ComputePskBinderHash( - ss, - ss->ssl3.hs.messages.len - ss->xtnData.pskBindersLen, - &hashes); + rv = tls13_ComputePskBinderHash(ss, ss->xtnData.pskBinderPrefixLen, + &hashes); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } - rv = tls13_VerifyFinished(ss, ssl_hs_client_hello, + rv = tls13_VerifyFinished(ss, client_hello, ss->ssl3.hs.pskBinderKey, ss->xtnData.pskBinder.data, ss->xtnData.pskBinder.len, @@ -1847,7 +1429,11 @@ tls13_HandleClientHelloPart2(sslSocket *ss, sid = NULL; if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { - rv = tls13_DeriveEarlySecrets(ss); + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelClient, + kHkdfLabelEarlyTrafficSecret, + NULL, /* Current running hash. */ + &ss->ssl3.hs.clientEarlyTrafficSecret); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return SECFailure; @@ -1872,143 +1458,70 @@ loser: return SECFailure; } -SECStatus -SSLExp_HelloRetryRequestCallback(PRFileDesc *fd, - SSLHelloRetryRequestCallback cb, void *arg) +static SECStatus +tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup) { - sslSocket *ss = ssl_FindSocket(fd); - if (!ss) { - return SECFailure; /* Code already set. */ - } + SECStatus rv; - ss->hrrCallback = cb; - ss->hrrCallbackArg = arg; - return SECSuccess; -} + SSL_TRC(3, ("%d: TLS13[%d]: send hello retry request handshake", + SSL_GETPID(), ss->fd)); -/* - * 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); + 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; + } + + 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 */); 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); - /* 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); + rv = ssl3_AppendHandshakeNumber( + ss, tls13_EncodeDraftVersion(ss->version), 2); 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; - 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)); + /* Length of extensions. */ + rv = ssl3_AppendHandshakeNumber(ss, 2 + 2 + 2, 2); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; + goto loser; } - /* Now build the body of the message. */ - rv = tls13_ConstructHelloRetryRequest(ss, ss->ssl3.hs.cipher_suite, - requestedGroup, - cookie, cookieLen, &messageBuf); + /* Key share extension - currently the only reason we send this. */ + rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); - return SECFailure; + goto loser; } - - /* And send it. */ - ssl_GetXmitBufLock(ss); - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello, - SSL_BUFFER_LEN(&messageBuf)); + /* Key share extension length. */ + rv = ssl3_AppendHandshakeNumber(ss, 2, 2); if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } - rv = ssl3_AppendBufferToHandshake(ss, &messageBuf); + rv = ssl3_AppendHandshakeNumber(ss, selectedGroup->name, 2); if (rv != SECSuccess) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); goto loser; } - sslBuffer_Clear(&messageBuf); /* Done with messageBuf */ - - 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 */ - } + 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; @@ -2022,7 +1535,6 @@ tls13_SendHelloRetryRequest(sslSocket *ss, return SECSuccess; loser: - sslBuffer_Clear(&messageBuf); ssl_ReleaseXmitBufLock(ss); return SECFailure; } @@ -2094,96 +1606,67 @@ static SECStatus tls13_SendCertificateRequest(sslSocket *ss) { SECStatus rv; - sslBuffer extensionBuf = SSL_BUFFER_EMPTY; + unsigned int calen; + SECItem *names; + unsigned int nnames; + SECItem *name; + int i; + PRUint8 sigSchemes[MAX_SIGNATURE_SCHEMES * 2]; + unsigned int sigSchemesLength = 0; + int length; SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request", SSL_GETPID(), ss->fd)); - rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request); + rv = ssl3_EncodeSigAlgs(ss, sigSchemes, sizeof(sigSchemes), + &sigSchemesLength); if (rv != SECSuccess) { - return SECFailure; /* Code already set. */ + return rv; } - /* We should always have at least one of these. */ - PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0); - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request, - 1 + 0 + /* empty request context */ - 2 + /* extension length */ - SSL_BUFFER_LEN(&extensionBuf)); + rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + return rv; } + length = 1 + 0 /* length byte for empty request context */ + + 2 + sigSchemesLength + 2 + calen + 2; - /* Context. */ + rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length); + if (rv != SECSuccess) { + return rv; /* err set by AppendHandshake. */ + } rv = ssl3_AppendHandshakeNumber(ss, 0, 1); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + return rv; /* err set by AppendHandshake. */ } - /* Extensions. */ - rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2); + rv = ssl3_AppendHandshakeVariable(ss, sigSchemes, sigSchemesLength, 2); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + return rv; /* err set by AppendHandshake. */ } - - 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); + rv = ssl3_AppendHandshakeNumber(ss, calen, 2); if (rv != SECSuccess) { - return SECFailure; + return rv; /* err set by AppendHandshake. */ } - - // 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); + 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. */ + } + } + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); if (rv != SECSuccess) { - return SECFailure; + return rv; /* err set by AppendHandshake. */ } 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, const PRUint8 *savedMsg, - PRUint32 savedLength) +tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; + PRUint32 tmp; + SSL3ProtocolVersion version; SSL_TRC(3, ("%d: TLS13[%d]: handle hello retry request", SSL_GETPID(), ss->fd)); @@ -2196,77 +1679,84 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg, unexpected_message); return SECFailure; } - PORT_Assert(ss->ssl3.hs.ws == wait_server_hello); + + /* 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; + } 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); - ssl_CipherSpecRelease(ss->ssl3.cwSpec); - ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecWrite, - TrafficKeyClearText); - PORT_Assert(ss->ssl3.cwSpec); + tls13_CipherSpecRelease(ss->ssl3.cwSpec); + ss->ssl3.cwSpec = ss->ssl3.crSpec; + PORT_Assert(ss->ssl3.cwSpec->cipher_def->cipher == cipher_null); ssl_ReleaseSpecWriteLock(ss); } else { PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none); } - /* 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) { + /* 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, - decode_error); + protocol_version); return SECFailure; } - rv = ssl3_HandleParsedExtensions(ss, ssl_hs_hello_retry_request); - ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); + /* Extensions. */ + rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, &b, &length); if (rv != SECSuccess) { - return SECFailure; /* Error code set below */ + return SECFailure; /* error code already set */ } - - ss->ssl3.hs.helloRetry = PR_TRUE; - rv = tls13_ReinjectHandshakeTranscript(ss); - if (rv != SECSuccess) { - return rv; + /* 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) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST, + decode_error); + return SECFailure; } - rv = ssl_HashHandshakeMessage(ss, ssl_hs_server_hello, - savedMsg, savedLength); + rv = ssl3_HandleExtensions(ss, &b, &length, hello_retry_request); if (rv != SECSuccess) { - return SECFailure; + return SECFailure; /* Error code set below */ } + ss->ssl3.hs.helloRetry = PR_TRUE; + 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) { - goto loser; + return SECFailure; } - 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", @@ -2285,51 +1775,71 @@ 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.clientCertRequested); + PORT_Assert(ss->ssl3.hs.certificateRequest == NULL); - rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length); - if (rv != SECSuccess) { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); 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 empty. */ + * context must always be null. */ if (context.len > 0) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter); - return SECFailure; + goto loser; } - rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length); - if (rv != SECSuccess) { - return SECFailure; + 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; } - if (length) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, decode_error); - return SECFailure; - } + rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, + &certRequest->ca_list); + if (rv != SECSuccess) + goto loser; /* alert already sent */ - /* Process all the extensions. */ - rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len, - ssl_hs_certificate_request); + /* Verify that the extensions are sane. */ + rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length); if (rv != SECSuccess) { - return SECFailure; - } - - if (!ss->xtnData.numSigSchemes) { - FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION, - missing_extension); - return SECFailure; + goto loser; } - rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &context); + /* Process all the extensions (note: currently a no-op). */ + rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len, + certificate_request); if (rv != SECSuccess) { - return SECFailure; + goto loser; } - ss->ssl3.hs.clientCertRequested = PR_TRUE; + rv = SECITEM_CopyItem(arena, &certRequest->context, &context); + if (rv != SECSuccess) + goto loser; + TLS13_SET_HS_STATE(ss, wait_server_cert); + ss->ssl3.hs.certificateRequest = certRequest; + return SECSuccess; + +loser: + PORT_FreeArena(arena, PR_FALSE); + return SECFailure; } static SECStatus @@ -2349,10 +1859,12 @@ 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, - ssl_SendEmptyExtension); + rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_early_data_xtn, + tls13_ServerSendEarlyDataXtn); if (rv != SECSuccess) { return SECFailure; /* Error code set already. */ } @@ -2405,29 +1917,11 @@ 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(); @@ -2459,18 +1953,14 @@ 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); @@ -2482,12 +1972,11 @@ 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); } - ss->ssl3.hs.serverHelloTime = ssl_TimeUsec(); + TLS13_SET_HS_STATE(ss, + ss->opt.requestCertificate ? wait_client_cert + : wait_finished); return SECSuccess; } @@ -2534,7 +2023,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss) SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_stateless_resumes); } else { /* !PSK */ - if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) { + if (ssl3_ClientExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) { SSL_AtomicIncrementLong(&ssl3stats->hsh_sid_cache_misses); } if (sid->cached == in_client_cache) { @@ -2579,12 +2068,8 @@ tls13_HandleServerHelloPart2(sslSocket *ss) return SECFailure; /* error code is set. */ } - 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); - } + ss->ssl3.hs.shortHeaders = ssl3_ExtensionNegotiated( + ss, ssl_tls13_short_header_xtn); rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, CipherSpecRead, PR_FALSE); @@ -2686,7 +2171,8 @@ tls13_SendCertificate(sslSocket *ss) int certChainLen = 0; int i; SECItem context = { siBuffer, NULL, 0 }; - sslBuffer extensionBuf = SSL_BUFFER_EMPTY; + PRInt32 extensionsLen = 0; + PRUint32 maxBytes = 65535; SSL_TRC(3, ("%d: TLS1.3[%d]: send certificate handshake", SSL_GETPID(), ss->fd)); @@ -2709,28 +2195,26 @@ 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.clientCertRequested); - context = ss->xtnData.certReqContext; + PORT_Assert(ss->ssl3.hs.certificateRequest); + context = ss->ssl3.hs.certificateRequest->context; } if (certChain) { for (i = 0; i < certChain->len; i++) { - /* 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 */ + certChainLen += + 3 + certChain->certs[i].len + /* cert length + cert */ + 2 + (!i ? extensionsLen : 0); /* extensions length + extensions */ } - /* extensionBuf.len is only added once, for the leaf cert. */ - certChainLen += SSL_BUFFER_LEN(&extensionBuf); } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate, - 1 + context.len + 3 + certChainLen); + rv = ssl3_AppendHandshakeHeader(ss, certificate, + 1 + context.len + + 3 + certChainLen); if (rv != SECSuccess) { return SECFailure; /* err set by AppendHandshake. */ } @@ -2738,44 +2222,50 @@ tls13_SendCertificate(sslSocket *ss) rv = ssl3_AppendHandshakeVariable(ss, context.data, context.len, 1); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + return SECFailure; /* err set by AppendHandshake. */ } rv = ssl3_AppendHandshakeNumber(ss, certChainLen, 3); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + return SECFailure; /* 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) { - goto loser; /* err set by AppendHandshake. */ + return SECFailure; /* err set by AppendHandshake. */ } if (i) { /* Not end-entity. */ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + return SECFailure; /* err set by AppendHandshake. */ } continue; } /* End-entity, send extensions. */ - rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2); + rv = ssl3_AppendHandshakeNumber(ss, extensionsLen, 2); if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ + 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; } } } - sslBuffer_Clear(&extensionBuf); return SECSuccess; - -loser: - sslBuffer_Clear(&extensionBuf); - return SECFailure; } static SECStatus @@ -2803,7 +2293,7 @@ tls13_HandleCertificateEntry(sslSocket *ss, SECItem *data, PRBool first, if (first && !ss->sec.isServer) { rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len, - ssl_hs_certificate); + certificate); if (rv != SECSuccess) { return SECFailure; } @@ -2861,11 +2351,6 @@ 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) @@ -2960,6 +2445,32 @@ 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 @@ -3028,56 +2539,15 @@ loser: * HKDF-Expand-Label(Secret, Label, * Hash(Messages) + Hash(resumption_context), L)) */ -SECStatus +static SECStatus tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, - const char *label, - unsigned int labelLen, + const char *prefix, + const char *suffix, const SSL3Hashes *hashes, PK11SymKey **dest) { SECStatus rv; - - 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; + SSL3Hashes hashesTmp; char buf[100]; const char *label; @@ -3096,22 +2566,25 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key, SSL_TRC(3, ("%d: TLS13[%d]: deriving secret '%s'", SSL_GETPID(), ss->fd, label)); - rv = tls13_ComputeHandshakeHashes(ss, &hashes); - if (rv != SECSuccess) { - PORT_Assert(0); /* Should never fail */ - ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; + 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_DeriveSecret(ss, key, label, strlen(label), - &hashes, dest); + rv = tls13_HkdfExpandLabel(key, tls13_GetHash(ss), + hashes->u.raw, hashes->len, + label, strlen(label), + tls13_GetHkdfMechanism(ss), + tls13_GetHashSize(ss), dest); if (rv != SECSuccess) { + LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - - if (keylogLabel) { - ssl3_RecordKeyLog(ss, keylogLabel, *dest); - } return SECSuccess; } @@ -3119,41 +2592,49 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key, static SECStatus tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, TrafficKeyType type, + CipherSpecDirection direction, PRBool deleteSecret) { - 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); + 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); PK11SymKey **prkp = NULL; PK11SymKey *prk = NULL; - PRBool clientSecret; + PRBool clientKey; + ssl3KeyMaterial *target; + const char *phase; 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(clientSecret); + PORT_Assert(clientKey); + phase = kHkdfPhaseEarlyApplicationDataKeys; prkp = &ss->ssl3.hs.clientEarlyTrafficSecret; - spec->phase = kHkdfPhaseEarlyApplicationDataKeys; break; case TrafficKeyHandshake: - prkp = clientSecret ? &ss->ssl3.hs.clientHsTrafficSecret - : &ss->ssl3.hs.serverHsTrafficSecret; - spec->phase = kHkdfPhaseHandshakeKeys; + phase = kHkdfPhaseHandshakeKeys; + prkp = clientKey ? &ss->ssl3.hs.clientHsTrafficSecret : &ss->ssl3.hs.serverHsTrafficSecret; break; case TrafficKeyApplicationData: - prkp = clientSecret ? &ss->ssl3.hs.clientTrafficSecret - : &ss->ssl3.hs.serverTrafficSecret; - spec->phase = kHkdfPhaseApplicationDataKeys; + phase = kHkdfPhaseApplicationDataKeys; + prkp = clientKey ? &ss->ssl3.hs.clientTrafficSecret : &ss->ssl3.hs.serverTrafficSecret; break; default: LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); @@ -3163,15 +2644,17 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, PORT_Assert(prkp != NULL); prk = *prkp; - SSL_TRC(3, ("%d: TLS13[%d]: deriving %s traffic keys epoch=%d (%s)", - SSL_GETPID(), ss->fd, SPEC_DIR(spec), - spec->epoch, spec->phase)); + 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; rv = tls13_HkdfExpandLabel(prk, tls13_GetHash(ss), NULL, 0, kHkdfPurposeKey, strlen(kHkdfPurposeKey), bulkAlgorithm, keySize, - &spec->keyMaterial.key); + &target->write_key); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); @@ -3181,7 +2664,7 @@ tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec, rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss), NULL, 0, kHkdfPurposeIv, strlen(kHkdfPurposeIv), - spec->keyMaterial.iv, ivSize); + target->write_iv, ivSize); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); @@ -3198,111 +2681,38 @@ 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, ssl3CipherSpec *spec) +tls13_SetupPendingCipherSpec(sslSocket *ss) { + 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); - /* Version isn't set when we send 0-RTT data. */ - spec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version); + ssl_GetSpecWriteLock(ss); /*******************************/ - 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); - } + 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); SSL_TRC(3, ("%d: TLS13[%d]: Set Pending Cipher Suite to 0x%04x", SSL_GETPID(), ss->fd, suite)); + pSpec->cipher_def = bulk; - 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; - } + ssl_ReleaseSpecWriteLock(ss); /*******************************/ return SECSuccess; } -/* 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. - */ +/* Install a new cipher spec for this direction. */ static SECStatus -tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, +tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, CipherSpecDirection direction, PRBool deleteSecret) { - TrafficKeyType type; SECStatus rv; ssl3CipherSpec *spec = NULL; - ssl3CipherSpec **specp; - + ssl3CipherSpec **specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec; /* Flush out old handshake data. */ ssl_GetXmitBufLock(ss); rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); @@ -3312,52 +2722,81 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch, } /* Create the new spec. */ - spec = ssl_CreateCipherSpec(ss, direction); + spec = PORT_ZNew(ssl3CipherSpec); if (!spec) { + PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } - spec->epoch = epoch; - spec->seqNum = 0; - if (IS_DTLS(ss)) { - dtls_InitRecvdRecords(&spec->recvdRecords); + 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; } - /* This depends on spec having a valid direction and epoch. */ - rv = tls13_SetupPendingCipherSpec(ss, spec); + rv = tls13_DeriveTrafficKeys(ss, spec, type, direction, + deleteSecret); if (rv != SECSuccess) { - goto loser; + return SECFailure; } - type = (TrafficKeyType)PR_MIN(TrafficKeyApplicationData, epoch); - rv = tls13_DeriveTrafficKeys(ss, spec, type, deleteSecret); - if (rv != SECSuccess) { - goto loser; + /* 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); + } + + if (type == TrafficKeyEarlyApplicationData) { + spec->earlyDataRemaining = + ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size; } /* Now that we've set almost everything up, finally cut over. */ - specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec; ssl_GetSpecWriteLock(ss); - ssl_CipherSpecRelease(*specp); /* May delete old cipher. */ - *specp = spec; /* Overwrite. */ + tls13_CipherSpecRelease(*specp); /* May delete old cipher. */ + *specp = spec; /* Overwrite. */ ssl_ReleaseSpecWriteLock(ss); - 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))); + 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")); if (ss->ssl3.changedCipherSpecFunc) { ss->ssl3.changedCipherSpecFunc(ss->ssl3.changedCipherSpecArg, direction == CipherSpecWrite, spec); } return SECSuccess; - -loser: - ssl_CipherSpecRelease(spec); - return SECFailure; } -SECStatus -tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes) +static SECStatus +tls13_ComputeHandshakeHashes(sslSocket *ss, + SSL3Hashes *hashes) { SECStatus rv; PK11Context *ctx = NULL; @@ -3377,7 +2816,7 @@ tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes) goto loser; } - PRINT_BUF(10, (ss, "Handshake hash computed over saved messages", + PRINT_BUF(10, (NULL, "Handshake hash computed over saved messages", ss->ssl3.hs.messages.buf, ss->ssl3.hs.messages.len)); @@ -3402,8 +2841,6 @@ tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes) 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); @@ -3453,6 +2890,19 @@ 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: * @@ -3482,7 +2932,7 @@ tls13_WriteNonce(ssl3KeyMaterial *keys, size_t i; PORT_Assert(nonceLen == 12); - memcpy(nonce, keys->iv, 12); + memcpy(nonce, keys->write_iv, 12); /* XOR the last 8 bytes of the IV with the sequence number. */ PORT_Assert(seqNumLen == 8); @@ -3512,10 +2962,10 @@ tls13_AEAD(ssl3KeyMaterial *keys, PRBool doDecrypt, }; if (doDecrypt) { - rv = PK11_Decrypt(keys->key, mechanism, ¶m, + rv = PK11_Decrypt(keys->write_key, mechanism, ¶m, out, &uOutLen, maxout, in, inlen); } else { - rv = PK11_Encrypt(keys->key, mechanism, ¶m, + rv = PK11_Encrypt(keys->write_key, mechanism, ¶m, out, &uOutLen, maxout, in, inlen); } *outlen = (int)uOutLen; @@ -3612,7 +3062,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, ssl_hs_encrypted_extensions); + rv = ssl3_HandleExtensions(ss, &b, &length, encrypted_extensions); if (rv != SECSuccess) { return SECFailure; /* Error code set below */ } @@ -3664,8 +3114,10 @@ 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)); @@ -3673,28 +3125,31 @@ tls13_SendEncryptedExtensions(sslSocket *ss) PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - rv = ssl_ConstructExtensions(ss, &extensions, ssl_hs_encrypted_extensions); + extensions_len = ssl3_CallHelloExtensionSenders( + ss, PR_FALSE, maxBytes, &ss->xtnData.encryptedExtensionsSenders[0]); + + rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions, + extensions_len + 2); if (rv != SECSuccess) { + LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_encrypted_extensions, - SSL_BUFFER_LEN(&extensions) + 2); + rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); if (rv != SECSuccess) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); - goto loser; + return SECFailure; } - rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensions, 2); - if (rv != SECSuccess) { + sent_len = ssl3_CallHelloExtensionSenders( + ss, PR_TRUE, extensions_len, + &ss->xtnData.encryptedExtensionsSenders[0]); + PORT_Assert(sent_len == extensions_len); + if (sent_len != extensions_len) { LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE); - goto loser; + PORT_Assert(sent_len == 0); + return SECFailure; } - sslBuffer_Clear(&extensions); - return SECSuccess; -loser: - sslBuffer_Clear(&extensions); - return SECFailure; + return SECSuccess; } SECStatus @@ -3755,7 +3210,7 @@ tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey) len = buf.len + 2 + 2; - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len); + rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len); if (rv != SECSuccess) { goto done; /* error code set by AppendHandshake */ } @@ -3783,14 +3238,14 @@ done: * Caller must hold Handshake and RecvBuf locks. */ SECStatus -tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) +tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, + SSL3Hashes *hashes) { 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)); @@ -3802,17 +3257,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) if (rv != SECSuccess) { return SECFailure; } - - 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; - } + PORT_Assert(hashes); rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); if (rv != SECSuccess) { @@ -3827,7 +3272,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; @@ -3856,11 +3301,13 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) } /* Request a client certificate now if one was requested. */ - if (ss->ssl3.hs.clientCertRequested) { + if (ss->ssl3.hs.certificateRequest) { + TLS13CertificateRequest *req = ss->ssl3.hs.certificateRequest; + PORT_Assert(!ss->sec.isServer); - rv = ssl3_CompleteHandleCertificateRequest( - ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes, - &ss->xtnData.certReqAuthorities); + rv = ssl3_CompleteHandleCertificateRequest(ss, req->signatureSchemes, + req->signatureSchemeCount, + &req->ca_list); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return rv; @@ -3873,7 +3320,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length) } static SECStatus -tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength, +tls13_ComputePskBinderHash(sslSocket *ss, unsigned long prefixLength, SSL3Hashes *hashes) { SECStatus rv; @@ -3885,75 +3332,38 @@ tls13_ComputePskBinderHash(sslSocket *ss, unsigned int 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); - return SECFailure; + goto loser; } - hashes->len = tls13_GetHashSize(ss); - PRINT_BUF(10, (NULL, "PSK Binder hash", hashes->u.raw, hashes->len)); + + PRINT_BUF(10, (NULL, "PSK Binder hash", + hashes->u.raw, hashes->len)); return SECSuccess; -} -/* 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. */ +loser: + return SECFailure; +} +/* Compute the PSK Binder This is kind of sneaky.*/ SECStatus -tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions) +tls13_ComputePskBinder(sslSocket *ss, PRBool sending, + unsigned int prefixLength, + PRUint8 *output, unsigned int *outputLen, + unsigned int maxOutputLen) { SSL3Hashes hashes; SECStatus rv; - unsigned int size = tls13_GetHashSize(ss); - unsigned int prefixLen = extensions->len - size - 3; - unsigned int finishedLen; - PORT_Assert(extensions->len >= size + 3); - - rv = ssl3_AppendHandshakeNumber(ss, extensions->len, 2); - if (rv != SECSuccess) { - return SECFailure; - } - - /* 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) { + rv = tls13_ComputePskBinderHash(ss, prefixLength, &hashes); + if (rv != SECSuccess) return SECFailure; - } - return SECSuccess; + return tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes, + sending, output, outputLen, maxOutputLen); } static SECStatus @@ -4052,7 +3462,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey) return SECFailure; } - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, finishedLen); + rv = ssl3_AppendHandshakeHeader(ss, finished, finishedLen); if (rv != SECSuccess) { return SECFailure; /* Error code already set. */ } @@ -4067,7 +3477,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey) } static SECStatus -tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message, +tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, PK11SymKey *secret, PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes) @@ -4090,7 +3500,7 @@ tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message, if (length != finishedLen) { #ifndef UNSAFE_FUZZER_MODE - FATAL_ERROR(ss, message == ssl_hs_finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); + FATAL_ERROR(ss, message == finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); return SECFailure; #endif } @@ -4107,37 +3517,8 @@ tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message, } static SECStatus -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) +tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, + const SSL3Hashes *hashes) { SECStatus rv; @@ -4147,19 +3528,27 @@ tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) SSL_TRC(3, ("%d: TLS13[%d]: client handle finished handshake", SSL_GETPID(), ss->fd)); - rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.serverHsTrafficSecret, - b, length); + rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, + wait_finished); 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) +tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, + const SSL3Hashes *hashes) { SECStatus rv; + PK11SymKey *secret; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -4167,68 +3556,61 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length) SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake", SSL_GETPID(), ss->fd)); - rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.clientHsTrafficSecret, - b, length); + rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, wait_finished); if (rv != SECSuccess) { return SECFailure; } - if (!ss->opt.requestCertificate && - (ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) { - dtls_ReceivedFirstMessageInFlight(ss); + if (TLS13_IN_HS_STATE(ss, wait_finished)) { + secret = ss->ssl3.hs.clientHsTrafficSecret; + } else { + secret = ss->ssl3.hs.clientEarlyTrafficSecret; } + rv = tls13_VerifyFinished(ss, finished, secret, b, length, hashes); + if (rv != SECSuccess) + return SECFailure; + rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData, - CipherSpecRead, PR_FALSE); + CipherSpecRead, PR_TRUE); if (rv != SECSuccess) { FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); return SECFailure; } - 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); + rv = tls13_FinishHandshake(ss); if (rv != SECSuccess) { - return SECFailure; + return SECFailure; /* Error code and alerts handled below */ } - ssl_GetXmitBufLock(ss); if (ss->opt.enableSessionTickets) { - rv = tls13_SendNewSessionTicket(ss, NULL, 0); + rv = tls13_SendNewSessionTicket(ss); if (rv != SECSuccess) { - goto loser; + ssl_ReleaseXmitBufLock(ss); + return SECFailure; /* Error code and alerts handled below */ } rv = ssl3_FlushHandshake(ss, 0); - if (rv != SECSuccess) { - goto loser; - } } ssl_ReleaseXmitBufLock(ss); + if (rv != SECSuccess) + return SECFailure; - return tls13_FinishHandshake(ss); - -loser: - ssl_ReleaseXmitBufLock(ss); - return SECFailure; + return SECSuccess; } 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; @@ -4270,15 +3652,9 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert, return SECFailure; /* error code is set. */ } } - 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 (ss->ssl3.hs.certificateRequest) { + PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE); + ss->ssl3.hs.certificateRequest = NULL; } if (sendClientCert) { @@ -4294,7 +3670,7 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert, if (rv != SECSuccess) { return SECFailure; /* err code was set. */ } - rv = ssl3_FlushHandshake(ss, 0); + rv = ssl3_FlushHandshake(ss, IS_DTLS(ss) ? ssl_SEND_FLAG_NO_RETRANSMIT : 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. */ @@ -4302,6 +3678,11 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert, return SECFailure; } + rv = dtls_StartHolddownTimer(ss); + if (rv != SECSuccess) { + return SECFailure; /* err code was set. */ + } + return SECSuccess; } @@ -4336,28 +3717,11 @@ 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, @@ -4367,6 +3731,12 @@ 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) { @@ -4386,17 +3756,12 @@ tls13_SendClientSecondRound(sslSocket *ss) return SECFailure; } rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData, - CipherSpecWrite, PR_FALSE); + CipherSpecWrite, PR_TRUE); 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); } @@ -4412,7 +3777,6 @@ 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; @@ -4420,22 +3784,14 @@ tls13_SendClientSecondRound(sslSocket *ss) PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */ -static SECStatus -tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, - unsigned int appTokenLen) +SECStatus +tls13_SendNewSessionTicket(sslSocket *ss) { 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; @@ -4443,44 +3799,18 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, } ticket.ticket_lifetime_hint = ssl_ticket_lifetime; - /* 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); + rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data); 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, ssl_hs_new_session_ticket, + rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, message_length); if (rv != SECSuccess) goto loser; @@ -4490,12 +3820,13 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, if (rv != SECSuccess) goto loser; - rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_age_add, 4); + /* The ticket age obfuscator. */ + rv = PK11_GenerateRandom((PRUint8 *)&ticket.ticket_age_add, + sizeof(ticket.ticket_age_add)); if (rv != SECSuccess) goto loser; - /* The ticket nonce. */ - rv = ssl3_AppendHandshakeVariable(ss, ticketNonce, sizeof(ticketNonce), 1); + rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_age_add, 4); if (rv != SECSuccess) goto loser; @@ -4512,7 +3843,7 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken, if (max_early_data_size_len) { rv = ssl3_AppendHandshakeNumber( - ss, ssl_tls13_early_data_xtn, 2); + ss, ssl_tls13_ticket_early_data_info_xtn, 2); if (rv != SECSuccess) goto loser; @@ -4536,42 +3867,6 @@ 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) { @@ -4579,7 +3874,6 @@ 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", @@ -4596,7 +3890,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECFailure; } - ticket.received_timestamp = ssl_TimeUsec(); + ticket.received_timestamp = PR_Now(); rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b, &length); if (rv != SECSuccess) { @@ -4614,14 +3908,6 @@ 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) { @@ -4632,14 +3918,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) /* Parse extensions. */ rv = ssl3_ConsumeHandshakeVariable(ss, &data, 2, &b, &length); - if (rv != SECSuccess || length) { + if (rv != SECSuccess) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, decode_error); return SECFailure; } rv = ssl3_HandleExtensions(ss, &data.data, - &data.len, ssl_hs_new_session_ticket); + &data.len, new_session_ticket); if (rv != SECSuccess) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, decode_error); @@ -4650,9 +3936,13 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) ticket.max_early_data_size = ss->xtnData.max_early_data_size; } - if (!ss->opt.noCache) { - PK11SymKey *secret; + if (length != 0) { + FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, + decode_error); + return SECFailure; + } + if (!ss->opt.noCache) { PORT_Assert(ss->sec.ci.sid); rv = SECITEM_CopyItem(NULL, &ticket.ticket, &ticket_data); if (rv != SECSuccess) { @@ -4689,22 +3979,9 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ticket); PORT_Assert(!ticket.ticket.data); - 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) { + rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid); + 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); @@ -4713,103 +3990,111 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) return SECSuccess; } -#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)) +typedef enum { + ExtensionNotUsed, + ExtensionClientOnly, + ExtensionSendClear, + ExtensionSendClearOrHrr, + ExtensionSendHrr, + ExtensionSendEncrypted, + ExtensionSendCertificate, + ExtensionNewSessionTicket +} Tls13ExtensionStatus; static const struct { PRUint16 ex_value; - PRUint32 messages; + Tls13ExtensionStatus status; } KnownExtensions[] = { - { 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) } + { 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 } }; -tls13ExtensionStatus -tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message) +PRBool +tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message) { unsigned int i; - 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)); + PORT_Assert((message == client_hello) || + (message == server_hello) || + (message == hello_retry_request) || + (message == encrypted_extensions) || + (message == new_session_ticket) || + (message == certificate) || + (message == certificate_request)); for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) { - /* Hacky check for message numbers > 30. */ - PORT_Assert(!(KnownExtensions[i].messages & (1U << 31))); - if (KnownExtensions[i].ex_value == extension) { + if (KnownExtensions[i].ex_value == extension) break; - } } - if (i >= PR_ARRAY_SIZE(KnownExtensions)) { - return tls13_extension_unknown; + 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; } - /* 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)); - - return tls13_extension_disallowed; - } + PORT_Assert(0); - return tls13_extension_allowed; + /* Not reached */ + return PR_TRUE; } -#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 SECStatus -tls13_FormatAdditionalData(sslSocket *ss, PRUint8 *aad, unsigned int length, - DTLSEpoch epoch, sslSequenceNumber seqNum) +static void +tls13_FormatAdditionalData(PRUint8 *aad, unsigned int length, + sslSequenceNumber seqNum) { - SECStatus rv; - sslBuffer buf = SSL_BUFFER_FIXED(aad, length); + PRUint8 *ptr = aad; PORT_Assert(length == 8); - 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; + ptr = ssl_EncodeUintX(seqNum, 8, ptr); + PORT_Assert((ptr - aad) == length); } PRInt32 @@ -4842,14 +4127,13 @@ tls13_ProtectRecord(sslSocket *ss, PRUint32 contentLen, sslBuffer *wrBuf) { - const ssl3BulkCipherDef *cipher_def = cwSpec->cipherDef; + const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def; const int tagLen = cipher_def->tag_size; SECStatus rv; - 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)); + 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)); if (contentLen + 1 + tagLen > wrBuf->space) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -4870,18 +4154,15 @@ tls13_ProtectRecord(sslSocket *ss, /* Add the content type at the end. */ wrBuf->buf[contentLen] = type; - 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)); + 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)); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); return SECFailure; @@ -4901,27 +4182,19 @@ tls13_ProtectRecord(sslSocket *ss, * 2. Call PORT_SetError() witn an appropriate code. */ SECStatus -tls13_UnprotectRecord(sslSocket *ss, - ssl3CipherSpec *spec, - SSL3Ciphertext *cText, sslBuffer *plaintext, +tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, SSL3AlertDescription *alert) { - const ssl3BulkCipherDef *cipher_def = spec->cipherDef; - sslSequenceNumber seqNum; + ssl3CipherSpec *crSpec = ss->ssl3.crSpec; + const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def; PRUint8 aad[8]; SECStatus rv; *alert = bad_record_mac; /* Default alert for most issues. */ - PORT_Assert(spec->direction == CipherSpecRead); - if (IS_DTLS(ss)) { - seqNum = cText->seq_num & RECORD_SEQ_MASK; - } else { - seqNum = spec->seqNum; - } - SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) unprotect 0x%0llx len=%u", - SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase, seqNum, - cText->buf->len)); + SSL_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)); /* We can perform this test in variable time because the record's total * length and the ciphersuite are both public knowledge. */ @@ -4943,8 +4216,9 @@ tls13_UnprotectRecord(sslSocket *ss, return SECFailure; } - /* Check the version number in the record. */ - if (cText->version != spec->recordVersion) { + /* Check the version number in the record */ + if ((IS_DTLS(ss) && cText->version != kDtlsRecordVersion) || + (!IS_DTLS(ss) && cText->version != kTlsRecordVersion)) { /* Do we need a better error here? */ SSL_TRC(3, ("%d: TLS13[%d]: record has bogus version", @@ -4954,18 +4228,18 @@ tls13_UnprotectRecord(sslSocket *ss, /* Decrypt */ PORT_Assert(cipher_def->type == type_aead); - 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)); + 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)); if (rv != SECSuccess) { SSL_TRC(3, ("%d: TLS13[%d]: record has bogus MAC", @@ -4997,14 +4271,14 @@ tls13_UnprotectRecord(sslSocket *ss, --plaintext->len; /* Check that we haven't received too much 0-RTT data. */ - if (spec->epoch == TrafficKeyEarlyApplicationData && + if (crSpec->epoch == TrafficKeyEarlyApplicationData && cText->type == content_application_data) { - if (plaintext->len > spec->earlyDataRemaining) { + if (plaintext->len > crSpec->earlyDataRemaining) { *alert = unexpected_message; PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA); return SECFailure; } - spec->earlyDataRemaining -= plaintext->len; + crSpec->earlyDataRemaining -= plaintext->len; } SSL_TRC(10, @@ -5052,7 +4326,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_ExtensionAdvertised(ss, ssl_tls13_early_data_xtn)) { + if (!ssl3_ClientExtensionAdvertised(ss, ssl_tls13_early_data_xtn)) { return SECSuccess; } @@ -5067,41 +4341,25 @@ 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 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; - } + if (rv != SECSuccess) + return rv; } /* Cipher suite already set in tls13_SetupClientHello. */ ss->ssl3.hs.preliminaryInfo = 0; - rv = tls13_DeriveEarlySecrets(ss); - if (rv != SECSuccess) { + rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, + kHkdfLabelClient, + kHkdfLabelEarlyTrafficSecret, + NULL, + &ss->ssl3.hs.clientEarlyTrafficSecret); + 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 SECFailure; + return rv; } return SECSuccess; @@ -5134,45 +4392,32 @@ tls13_SendEndOfEarlyData(sslSocket *ss) { SECStatus rv; - SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd)); - PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + SSL_TRC(3, ("%d: TLS13[%d]: send end_of_early_data extension", + SSL_GETPID(), ss->fd)); - rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0); + rv = SSL3_SendAlert(ss, alert_warning, end_of_early_data); if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ + FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error); + return SECFailure; } ss->ssl3.hs.zeroRttState = ssl_0rtt_done; return SECSuccess; } -static SECStatus -tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length) +SECStatus +tls13_HandleEndOfEarlyData(sslSocket *ss) { SECStatus rv; - 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) { + 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); return SECFailure; } - /* 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; - } + PORT_Assert(TLS13_IN_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert : wait_finished)); rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, CipherSpecRead, PR_FALSE); @@ -5182,9 +4427,6 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length) } ss->ssl3.hs.zeroRttState = ssl_0rtt_done; - TLS13_SET_HS_STATE(ss, - ss->opt.requestCertificate ? wait_client_cert - : wait_finished); return SECSuccess; } @@ -5235,11 +4477,11 @@ tls13_EncodeDraftVersion(SSL3ProtocolVersion version) /* Pick the highest version we support that is also advertised. */ SECStatus -tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions) +tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions) { PRUint16 version; - /* Make a copy so we're nondestructive. */ - SECItem data = supportedVersions->data; + /* Make a copy so we're nondestructive*/ + SECItem data = supported_versions->data; SECItem versions; SECStatus rv; @@ -5269,22 +4511,3 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supportedVersions) 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 1aaffb651..92eb545b0 100644 --- a/security/nss/lib/ssl/tls13con.h +++ b/security/nss/lib/ssl/tls13con.h @@ -9,25 +9,15 @@ #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 { - update_not_requested = 0, - update_requested = 1 -} tls13KeyUpdateRequest; + StaticSharedSecret, + EphemeralSharedSecret +} SharedSecretType; #define TLS13_MAX_FINISHED_SIZE 64 SECStatus tls13_UnprotectRecord( - sslSocket *ss, ssl3CipherSpec *spec, - SSL3Ciphertext *cText, sslBuffer *plaintext, + sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, SSL3AlertDescription *alert); #if defined(WIN32) @@ -51,14 +41,6 @@ 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); @@ -67,30 +49,27 @@ 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_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions); +SECStatus tls13_ComputePskBinder(sslSocket *ss, PRBool sending, + unsigned int prefixLength, + PRUint8 *output, unsigned int *outputLen, + unsigned int maxOutputLen); SECStatus tls13_HandleClientHelloPart2(sslSocket *ss, const SECItem *suites, - sslSessionID *sid, - const PRUint8 *msg, - unsigned int len); + sslSessionID *sid); SECStatus tls13_HandleServerHelloPart2(sslSocket *ss); SECStatus tls13_HandlePostHelloHandshakeMessage(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, + SSL3Hashes *hashesPtr); +SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, 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); -SECStatus tls13_SetAlertCipherSpec(sslSocket *ss); -tls13ExtensionStatus tls13_ExtensionStatus(PRUint16 extension, - SSLHandshakeType message); +void tls13_CipherSpecAddRef(ssl3CipherSpec *spec); +void tls13_CipherSpecRelease(ssl3CipherSpec *spec); +void tls13_DestroyCipherSpecs(PRCList *list); +PRBool tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message); SECStatus tls13_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, @@ -98,25 +77,13 @@ 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); - -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); +SECStatus tls13_SendNewSessionTicket(sslSocket *ss); #endif /* __tls13con_h_ */ diff --git a/security/nss/lib/ssl/tls13err.h b/security/nss/lib/ssl/tls13err.h deleted file mode 100644 index 8cdeb12eb..000000000 --- a/security/nss/lib/ssl/tls13err.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- 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 899f23827..c2ce390ff 100644 --- a/security/nss/lib/ssl/tls13exthandle.c +++ b/security/nss/lib/ssl/tls13exthandle.c @@ -14,35 +14,50 @@ #include "ssl3exthandle.h" #include "tls13exthandle.h" -SECStatus -tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ServerSendStatusRequestXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; const sslServerCert *serverCert = ss->sec.serverCert; const SECItem *item; SECStatus rv; if (!serverCert->certStatusArray || !serverCert->certStatusArray->len) { - return SECSuccess; + return 0; } item = &serverCert->certStatusArray->items[0]; /* Only send the first entry. */ - /* status_type == ocsp */ - rv = sslBuffer_AppendNumber(buf, 1 /*ocsp*/, 1); - if (rv != SECSuccess) { - return SECFailure; + extension_length = 2 + 2 + 1 /* status_type */ + 3 + item->len; + if (maxBytes < (PRUint32)extension_length) { + return 0; } - /* opaque OCSPResponse<1..2^24-1> */ - rv = sslBuffer_AppendVariable(buf, item->data, item->len, 3); - 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. */ } - *added = PR_TRUE; - return SECSuccess; + return extension_length; } /* @@ -86,27 +101,41 @@ 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(sslBuffer *buf, const sslEphemeralKeyPair *keyPair) +tls13_EncodeKeyShareEntry(const sslSocket *ss, const sslEphemeralKeyPair *keyPair) { SECStatus rv; SECKEYPublicKey *pubKey = keyPair->keys->pubKey; unsigned int size = tls13_SizeOfKeyShareEntry(pubKey); - rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2); + rv = ssl3_ExtAppendHandshakeNumber(ss, keyPair->group->name, 2); if (rv != SECSuccess) return rv; - rv = sslBuffer_AppendNumber(buf, size - 4, 2); + rv = ssl3_ExtAppendHandshakeNumber(ss, size - 4, 2); if (rv != SECSuccess) return rv; switch (pubKey->keyType) { case ecKey: - rv = sslBuffer_Append(buf, pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len); + rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey); break; case dhKey: - rv = ssl_AppendPaddedDHKeyShare(buf, pubKey, PR_FALSE); + rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_FALSE); break; default: PORT_Assert(0); @@ -117,16 +146,14 @@ tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair) return rv; } -SECStatus -tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { - SECStatus rv; - PRCList *cursor; - unsigned int lengthOffset; + PRUint32 extension_length; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; + return 0; } /* Optimistically try to send an ECDHE key using the @@ -134,28 +161,47 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn", SSL_GETPID(), ss->fd)); - /* Save the offset to the length. */ - rv = sslBuffer_Skip(buf, 2, &lengthOffset); - if (rv != SECSuccess) { - return SECFailure; + extension_length = tls13_SizeOfClientKeyShareExtension(ss); + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; } - 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; + 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; } - } - rv = sslBuffer_InsertLength(buf, lengthOffset, 2); - if (rv != SECSuccess) { - return SECFailure; + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_key_share_xtn; } - *added = PR_TRUE; - return SECSuccess; + return extension_length; + +loser: + return -1; } static SECStatus @@ -204,8 +250,7 @@ loser: * |xtnData->remoteKeyShares| for future use. The key * share is processed in tls13_HandleServerKeyShare(). */ SECStatus -tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); @@ -236,8 +281,7 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, } SECStatus -tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 tmp; @@ -287,8 +331,7 @@ 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, - SECItem *data) +tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 length; @@ -321,6 +364,16 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, 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: @@ -328,10 +381,12 @@ loser: return SECFailure; } -SECStatus -tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRUint32 extension_length; + PRUint32 entry_length; SECStatus rv; sslEphemeralKeyPair *keyPair; @@ -342,13 +397,31 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); - rv = tls13_EncodeKeyShareEntry(buf, keyPair); - if (rv != SECSuccess) { - return SECFailure; + 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; } - *added = PR_TRUE; - return SECSuccess; + 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; + } + + return extension_length; + +loser: + return -1; } /* Called by clients. @@ -375,83 +448,113 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, * 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. */ -SECStatus +PRInt32 tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { + 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 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; + if (!ss->statelessResume) + return 0; PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); - /* Send a single ticket identity. */ + /* The length computations are simplified by the fact that there + * is just one ticket at most. */ session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket; - 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; + 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; - /* 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; + /* 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; - /* 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; + /* 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; - 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; - *added = PR_TRUE; - return SECSuccess; + xtnData->sentSessionTicketInClientHello = PR_TRUE; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_pre_shared_key_xtn; + } + return extension_length; loser: xtnData->ticketTimestampVerified = PR_FALSE; - return SECFailure; + return -1; } /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs * that contain session tickets. */ SECStatus -tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, +tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, 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)); @@ -461,26 +564,16 @@ 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 obfuscatedAge; + PRUint32 utmp; rv = ssl3_ExtConsumeHandshakeVariable(ss, &label, 2, &inner.data, &inner.len); @@ -490,8 +583,9 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData goto alert_loser; } - rv = ssl3_ExtConsumeHandshakeNumber(ss, &obfuscatedAge, 4, - &inner.data, &inner.len); + /* Read and discard session ticket age. Bug 1295163 */ + rv = ssl3_ExtConsumeHandshake(ss, &utmp, 4, + &inner.data, &inner.len); if (rv != SECSuccess) return rv; @@ -499,29 +593,17 @@ 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, appToken); + CONST_CAST(sslSocket, ss), &label); /* 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->pskBindersLen = data->len; + xtnData->pskBinderPrefixLen = ss->ssl3.hs.messages.len - data->len; /* Parse the binders list. */ rv = ssl3_ExtConsumeHandshakeVariable(ss, @@ -553,7 +635,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++] = ssl_tls13_pre_shared_key_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; @@ -563,27 +645,43 @@ alert_loser: return SECFailure; } -SECStatus +PRInt32 tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length = + 2 + 2 + 2; /* type + len + index */ SECStatus rv; - /* 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; + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; } - *added = PR_TRUE; - return SECSuccess; + 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; + } + + return extension_length; } /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs * that contain session tickets. */ SECStatus -tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, +tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { PRUint32 index; @@ -615,7 +713,7 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } @@ -623,20 +721,43 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData /* * struct { } EarlyDataIndication; */ -SECStatus +PRInt32 tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { - if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid)) { - return SECSuccess; + 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; } - *added = PR_TRUE; - return SECSuccess; + 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; + } + + return extension_length; } SECStatus -tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, +tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", @@ -658,14 +779,44 @@ tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; 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, +tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", @@ -683,19 +834,19 @@ tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } SECStatus -tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, + SECItem *data) { PRUint32 utmp; SECStatus rv; - SSL_TRC(3, ("%d: TLS13[%d]: handle ticket early_data extension", + SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension", SSL_GETPID(), ss->fd)); /* The server must not send this extension when negotiating < TLS 1.3. */ @@ -722,71 +873,59 @@ tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnD /* * struct { - * select (Handshake.msg_type) { - * case client_hello: * ProtocolVersion versions<2..254>; - * case server_hello: - * ProtocolVersion version; - * }; * } SupportedVersions; */ -SECStatus -tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extensions_len; PRUint16 version; - unsigned int lengthOffset; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; + return 0; } - SSL_TRC(3, ("%d: TLS13[%d]: client send supported_versions extension", + SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension", SSL_GETPID(), ss->fd)); - rv = sslBuffer_Skip(buf, 1, &lengthOffset); - if (rv != SECSuccess) { - return SECFailure; - } + /* 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); - for (version = ss->vrange.max; version >= ss->vrange.min; --version) { - rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2); - if (rv != SECSuccess) { - return SECFailure; - } + if (maxBytes < (PRUint32)extensions_len) { + PORT_Assert(0); + return 0; } - rv = sslBuffer_InsertLength(buf, lengthOffset, 1); - if (rv != SECSuccess) { - return SECFailure; - } - - *added = PR_TRUE; - return SECSuccess; -} + if (append) { + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2); + if (rv != SECSuccess) + return -1; -SECStatus -tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) -{ - SECStatus rv; + rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 4, 2); + if (rv != SECSuccess) + return -1; - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; - } + rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 5, 1); + if (rv != SECSuccess) + return -1; - SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension", - SSL_GETPID(), ss->fd)); + for (version = ss->vrange.max; version >= ss->vrange.min; --version) { + rv = ssl3_ExtAppendHandshakeNumber( + ss, tls13_EncodeDraftVersion(version), 2); + if (rv != SECSuccess) + return -1; + } - rv = sslBuffer_AppendNumber( - buf, tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2); - if (rv != SECSuccess) { - return SECFailure; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_supported_versions_xtn; } - *added = PR_TRUE; - return SECSuccess; + return extensions_len; } /* @@ -795,8 +934,7 @@ tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD * } Cookie; */ SECStatus -tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -822,57 +960,41 @@ tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; } -SECStatus -tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - SECStatus rv; + PRInt32 extension_len; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || !ss->ssl3.hs.cookie.len) { - return SECSuccess; + return 0; } 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; - } - - *added = PR_TRUE; - return SECSuccess; -} -SECStatus -tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) -{ - SECStatus rv; + /* Extension type, length, cookie length, cookie value. */ + extension_len = 2 + 2 + 2 + ss->ssl3.hs.cookie.len; - SSL_TRC(3, ("%d: TLS13[%d]: handle cookie extension", - SSL_GETPID(), ss->fd)); - - rv = ssl3_ExtConsumeHandshakeVariable(ss, &xtnData->cookie, 2, - &data->data, &data->len); - if (rv != SECSuccess) { - return SECFailure; - } - - if (xtnData->cookie.len == 0) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); - return SECFailure; + if (maxBytes < (PRUint32)extension_len) { + PORT_Assert(0); + return 0; } - if (data->len) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); - return SECFailure; - } + if (append) { + SECStatus rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_cookie_xtn, 2); + if (rv != SECSuccess) + return -1; - /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_cookie_xtn; + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2); + if (rv != SECSuccess) + return -1; - return SECSuccess; + rv = ssl3_ExtAppendHandshakeVariable(ss, ss->ssl3.hs.cookie.data, + ss->ssl3.hs.cookie.len, 2); + if (rv != SECSuccess) + return -1; + } + return extension_len; } /* @@ -882,33 +1004,54 @@ tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, * PskKeyExchangeMode ke_modes<1..255>; * } PskKeyExchangeModes; */ -SECStatus -tls13_ClientSendPskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) { static const PRUint8 ke_modes[] = { tls13_psk_dh_ke }; - SECStatus rv; + static const unsigned long ke_modes_len = sizeof(ke_modes); + PRInt32 extension_len; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || ss->opt.noCache) { - return SECSuccess; + return 0; } + 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)); - rv = sslBuffer_AppendVariable(buf, ke_modes, sizeof(ke_modes), 1); - if (rv != SECSuccess) { - return SECFailure; + if (maxBytes < (PRUint32)extension_len) { + PORT_Assert(0); + return 0; } - *added = PR_TRUE; - return SECSuccess; + 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; } SECStatus -tls13_ServerHandlePskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -933,126 +1076,112 @@ tls13_ServerHandlePskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = - ssl_tls13_psk_key_exchange_modes_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } -SECStatus -tls13_SendCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_SendShortHeaderXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) { - unsigned int calen; - const SECItem *name; - unsigned int nnames; - SECStatus rv; + PRUint32 extension_len = 2 + 2; /* Type + length (0). */ - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - - rv = ssl_GetCertificateRequestCAs(ss, &calen, &name, &nnames); - if (rv != SECSuccess) { - return SECFailure; + if (!ss->opt.enableShortHeaders) { + return 0; } - if (!calen) { - return SECSuccess; + /* Presently this is incompatible with 0-RTT. We will fix if + * it becomes more than an experiment. */ + if (ss->opt.enable0RttData) { + return 0; } - rv = sslBuffer_AppendNumber(buf, calen, 2); - if (rv != SECSuccess) { - return SECFailure; + if (IS_DTLS(ss)) { + return 0; } - while (nnames) { - rv = sslBuffer_AppendVariable(buf, name->data, name->len, 2); - if (rv != SECSuccess) { - return SECFailure; - } - ++name; - --nnames; + /* 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; } - *added = PR_TRUE; - return SECSuccess; -} - -SECStatus -tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - SECItem *data) -{ - SECStatus rv; - PLArenaPool *arena; + SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension", + SSL_GETPID(), ss->fd)); - if (!data->len) { - ssl3_ExtSendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST); - return SECFailure; + if (maxBytes < extension_len) { + PORT_Assert(0); + return 0; } - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (!arena) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } + if (append) { + SECStatus rv; - 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; + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_short_header_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_short_header_xtn; } - return SECSuccess; -loser: - PORT_FreeArena(arena, PR_FALSE); - xtnData->certReqAuthorities.arena = NULL; - return SECFailure; + return extension_len; } SECStatus -tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +tls13_HandleShortHeaderXtn( + const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, + SECItem *data) { - SECStatus rv; + SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension", + SSL_GETPID(), ss->fd)); - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + /* 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; + } - if (!xtnData->selectedGroup) { + /* Presently this is incompatible with 0-RTT. We will fix if + * it becomes more than an experiment. */ + if (ss->opt.enable0RttData) { return SECSuccess; } - rv = sslBuffer_AppendNumber(buf, xtnData->selectedGroup->name, 2); - if (rv != SECSuccess) { + if (IS_DTLS(ss)) { + PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); return SECFailure; } - *added = PR_TRUE; - return SECSuccess; -} + if (data->len) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); + return SECFailure; + } -SECStatus -tls13_ServerSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) -{ - SECStatus rv; + if (!ss->opt.enableShortHeaders) { + /* Ignore. */ + return SECSuccess; + } - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - PORT_Assert(xtnData->cookie.len > 0); + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; - rv = sslBuffer_AppendVariable(buf, - xtnData->cookie.data, xtnData->cookie.len, 2); - if (rv != SECSuccess) { - return SECFailure; + if (ss->sec.isServer) { + SECStatus rv; + + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_tls13_short_header_xtn, + tls13_SendShortHeaderXtn); + 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 edce94d83..b798c6b55 100644 --- a/security/nss/lib/ssl/tls13exthandle.h +++ b/security/nss/lib/ssl/tls13exthandle.h @@ -9,80 +9,66 @@ #ifndef __tls13exthandle_h_ #define __tls13exthandle_h_ -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, +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, SECItem *data); -SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, - TLSExtensionData *xtnData, +SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data); -SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data); -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, +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, SECItem *data); -SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data); -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, +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, SECItem *data); -SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, - TLSExtensionData *xtnData, +SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data); -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, +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, SECItem *data); -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, +PRInt32 tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes); +PRInt32 tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - 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); + 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); #endif diff --git a/security/nss/lib/ssl/tls13hashstate.c b/security/nss/lib/ssl/tls13hashstate.c deleted file mode 100644 index e3232f524..000000000 --- a/security/nss/lib/ssl/tls13hashstate.c +++ /dev/null @@ -1,181 +0,0 @@ -/* -*- 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 deleted file mode 100644 index e9a4aa84f..000000000 --- a/security/nss/lib/ssl/tls13hashstate.h +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- 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 8fa3375c6..7e69bb882 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]; - sslBuffer infoBuf = SSL_BUFFER(info); + PRUint8 *ptr = info; + unsigned int infoLen; PK11SymKey *derived; - SECStatus rv; - const char *kLabelPrefix = "tls13 "; + const char *kLabelPrefix = "TLS 1.3, "; const unsigned int kLabelPrefixLen = strlen(kLabelPrefix); if (handshakeHash) { @@ -170,31 +170,29 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, * - HkdfLabel.label is "TLS 1.3, " + Label * */ - rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2); - if (rv != SECSuccess) { - return SECFailure; - } - 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; + infoLen = 2 + 1 + kLabelPrefixLen + labelLen + 1 + handshakeHashLen; + if (infoLen > sizeof(info)) { + PORT_Assert(0); + goto abort; } - rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1); - 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; } + PORT_Assert((ptr - info) == infoLen); params.bExtract = CK_FALSE; params.bExpand = CK_TRUE; - params.pInfo = SSL_BUFFER_BASE(&infoBuf); - params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf); + params.pInfo = info; + params.ulInfoLen = infoLen; paramsi.data = (unsigned char *)¶ms; paramsi.len = sizeof(params); @@ -213,17 +211,20 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash, char labelStr[100]; PORT_Memcpy(labelStr, label, labelLen); labelStr[labelLen] = 0; - SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d", + SSL_TRC(50, ("HKDF Expand: label=[TLS 1.3, ] + '%s',requested length=%d", labelStr, keySize)); } PRINT_KEY(50, (NULL, "PRK", prk)); PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen)); - PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf), - SSL_BUFFER_LEN(&infoBuf))); + PRINT_BUF(50, (NULL, "Info", info, infoLen)); 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 deleted file mode 100644 index b090f9bca..000000000 --- a/security/nss/lib/ssl/tls13replay.c +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- 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; -} |