Update NSS to 3.35-RTM

This commit is contained in:
wolfbeast 2018-02-23 11:04:39 +01:00 • committed by Roy Tam
commit 66dd670b60
388 changed files with 39075 additions and 20752 deletions

View file

@ -473,8 +473,7 @@ ER3(SSL_ERROR_RX_MALFORMED_PRE_SHARED_KEY, (SSL_ERROR_BASE + 147),
ER3(SSL_ERROR_RX_MALFORMED_EARLY_DATA, (SSL_ERROR_BASE + 148),
"SSL received an invalid EarlyData extension.")
ER3(SSL_ERROR_END_OF_EARLY_DATA_ALERT, (SSL_ERROR_BASE + 149),
"SSL received an unexpected end of early data alert.")
UNUSED_ERROR(149)
ER3(SSL_ERROR_MISSING_ALPN_EXTENSION, (SSL_ERROR_BASE + 150),
"SSL didn't receive an expected ALPN extension.")
@ -511,3 +510,33 @@ ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160),
ER3(SSL_ERROR_TOO_MUCH_EARLY_DATA, (SSL_ERROR_BASE + 161),
"SSL received more early data than permitted.")
ER3(SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA, (SSL_ERROR_BASE + 162),
"SSL received an unexpected End of Early Data message.")
ER3(SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA, (SSL_ERROR_BASE + 163),
"SSL received a malformed End of Early Data message.")
ER3(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, (SSL_ERROR_BASE + 164),
"An experimental API was called, but not supported.")
ER3(SSL_ERROR_APPLICATION_ABORT, (SSL_ERROR_BASE + 165),
"SSL handshake aborted by the application.")
ER3(SSL_ERROR_APP_CALLBACK_ERROR, (SSL_ERROR_BASE + 166),
"An application callback produced an invalid response.")
ER3(SSL_ERROR_NO_TIMERS_ERROR, (SSL_ERROR_BASE + 167),
"No timers are currently running.")
ER3(SSL_ERROR_MISSING_COOKIE_EXTENSION, (SSL_ERROR_BASE + 168),
"A second ClientHello was received without a cookie extension.")
ER3(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE, (SSL_ERROR_BASE + 169),
"SSL received an unexpected key update message.")
ER3(SSL_ERROR_RX_MALFORMED_KEY_UPDATE, (SSL_ERROR_BASE + 170),
"SSL received a malformed key update message.")
ER3(SSL_ERROR_TOO_MANY_KEY_UPDATES, (SSL_ERROR_BASE + 171),
"SSL attempted too many key updates.")

View file

@ -17,6 +17,7 @@
#include "nss.h"
#include "ssl.h"
#include "pk11func.h" /* for PK11_ function calls */
#include "sslimpl.h"
/*
* This callback used by SSL to pull client sertificate upon
@ -63,7 +64,7 @@ NSS_GetClientAuthData(void *arg,
if (!cert)
continue;
/* Only check unexpired certs */
if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) !=
if (CERT_CheckCertValidTimes(cert, ssl_TimeUsec(), PR_TRUE) !=
secCertTimeValid) {
CERT_DestroyCertificate(cert);
continue;

View file

@ -57,11 +57,6 @@ endif
endif
ifdef NSS_SSL_ENABLE_ZLIB
DEFINES += -DNSS_SSL_ENABLE_ZLIB
include $(CORE_DEPTH)/coreconf/zlib.mk
endif
ifdef NSS_DISABLE_TLS_1_3
DEFINES += -DNSS_DISABLE_TLS_1_3
endif

View file

@ -0,0 +1,457 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* DTLS 1.3 Protocol
*/
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
/* DTLS 1.3 Record map for ACK processing.
* This represents a single fragment, so a record which includes
* multiple fragments will have one entry for each fragment on the
* sender. We use the same structure on the receiver for convenience
* but the only value we actually use is |record|.
*/
typedef struct DTLSHandshakeRecordEntryStr {
PRCList link;
PRUint16 messageSeq; /* The handshake message sequence number. */
PRUint32 offset; /* The offset into the handshake message. */
PRUint32 length; /* The length of the fragment. */
sslSequenceNumber record; /* The record (includes epoch). */
PRBool acked; /* Has this packet been acked. */
} DTLSHandshakeRecordEntry;
/* Combine the epoch and sequence number into a single value. */
static inline sslSequenceNumber
dtls_CombineSequenceNumber(DTLSEpoch epoch, sslSequenceNumber seqNum)
{
PORT_Assert(seqNum <= RECORD_SEQ_MAX);
return ((sslSequenceNumber)epoch << 48) | seqNum;
}
SECStatus
dtls13_RememberFragment(sslSocket *ss,
PRCList *list,
PRUint32 sequence,
PRUint32 offset,
PRUint32 length,
DTLSEpoch epoch,
sslSequenceNumber record)
{
DTLSHandshakeRecordEntry *entry;
PORT_Assert(IS_DTLS(ss));
/* We should never send an empty fragment with offset > 0. */
PORT_Assert(length || !offset);
if (!tls13_MaybeTls13(ss)) {
return SECSuccess;
}
SSL_TRC(20, ("%d: SSL3[%d]: %s remembering %s record=%llx msg=%d offset=%d",
SSL_GETPID(), ss->fd,
SSL_ROLE(ss),
list == &ss->ssl3.hs.dtlsSentHandshake ? "sent" : "received",
dtls_CombineSequenceNumber(epoch, record), sequence, offset));
entry = PORT_ZAlloc(sizeof(DTLSHandshakeRecordEntry));
if (!entry) {
return SECFailure;
}
entry->messageSeq = sequence;
entry->offset = offset;
entry->length = length;
entry->record = dtls_CombineSequenceNumber(epoch, record);
entry->acked = PR_FALSE;
PR_APPEND_LINK(&entry->link, list);
return SECSuccess;
}
SECStatus
dtls13_SendAck(sslSocket *ss)
{
sslBuffer buf = SSL_BUFFER_EMPTY;
SECStatus rv = SECSuccess;
PRCList *cursor;
PRInt32 sent;
SSL_TRC(10, ("%d: SSL3[%d]: Sending ACK",
SSL_GETPID(), ss->fd));
for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsRcvdHandshake);
cursor != &ss->ssl3.hs.dtlsRcvdHandshake;
cursor = PR_NEXT_LINK(cursor)) {
DTLSHandshakeRecordEntry *entry = (DTLSHandshakeRecordEntry *)cursor;
SSL_TRC(10, ("%d: SSL3[%d]: ACK for record=%llx",
SSL_GETPID(), ss->fd, entry->record));
rv = sslBuffer_AppendNumber(&buf, entry->record, 8);
if (rv != SECSuccess) {
goto loser;
}
}
ssl_GetXmitBufLock(ss);
sent = ssl3_SendRecord(ss, NULL, content_ack,
buf.buf, buf.len, 0);
ssl_ReleaseXmitBufLock(ss);
if (sent != buf.len) {
rv = SECFailure;
if (sent != -1) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
}
}
loser:
sslBuffer_Clear(&buf);
return rv;
}
void
dtls13_SendAckCb(sslSocket *ss)
{
if (!IS_DTLS(ss)) {
return;
}
(void)dtls13_SendAck(ss);
}
/* Zero length messages are very simple to check. */
static PRBool
dtls_IsEmptyMessageAcknowledged(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset)
{
PRCList *cursor;
for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsSentHandshake);
cursor != &ss->ssl3.hs.dtlsSentHandshake;
cursor = PR_NEXT_LINK(cursor)) {
DTLSHandshakeRecordEntry *entry = (DTLSHandshakeRecordEntry *)cursor;
if (!entry->acked || msgSeq != entry->messageSeq) {
continue;
}
/* Empty fragments are always offset 0. */
if (entry->length == 0) {
PORT_Assert(!entry->offset);
return PR_TRUE;
}
}
return PR_FALSE;
}
/* Take a range starting at |*start| and that start forwards based on the
* contents of the acknowedgement in |entry|. Only move if the acknowledged
* range overlaps |*start|. Return PR_TRUE if it moves. */
static PRBool
dtls_MoveUnackedStartForward(DTLSHandshakeRecordEntry *entry, PRUint32 *start)
{
/* This entry starts too late. */
if (*start < entry->offset) {
return PR_FALSE;
}
/* This entry ends too early. */
if (*start >= entry->offset + entry->length) {
return PR_FALSE;
}
*start = entry->offset + entry->length;
return PR_TRUE;
}
/* Take a range ending at |*end| and move that end backwards based on the
* contents of the acknowedgement in |entry|. Only move if the acknowledged
* range overlaps |*end|. Return PR_TRUE if it moves. */
static PRBool
dtls_MoveUnackedEndBackward(DTLSHandshakeRecordEntry *entry, PRUint32 *end)
{
/* This entry ends too early. */
if (*end > entry->offset + entry->length) {
return PR_FALSE;
}
/* This entry starts too late. */
if (*end <= entry->offset) {
return PR_FALSE;
}
*end = entry->offset;
return PR_TRUE;
}
/* Get the next contiguous range of unacknowledged bytes from the handshake
* message identified by |msgSeq|. The search starts at the offset in |offset|.
* |len| contains the full length of the message.
*
* Returns PR_TRUE if there is an unacknowledged range. In this case, values at
* |start| and |end| are modified to contain the range.
*
* Returns PR_FALSE if the message is entirely acknowledged from |offset|
* onwards.
*/
PRBool
dtls_NextUnackedRange(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset,
PRUint32 len, PRUint32 *startOut, PRUint32 *endOut)
{
PRCList *cur_p;
PRBool done = PR_FALSE;
DTLSHandshakeRecordEntry *entry;
PRUint32 start;
PRUint32 end;
PORT_Assert(IS_DTLS(ss));
*startOut = offset;
*endOut = len;
if (!tls13_MaybeTls13(ss)) {
return PR_TRUE;
}
/* The message is empty. Use a simple search. */
if (!len) {
PORT_Assert(!offset);
return !dtls_IsEmptyMessageAcknowledged(ss, msgSeq, offset);
}
/* This iterates multiple times over the acknowledgments and only terminates
* when an entire iteration happens without start or end moving. If that
* happens without start and end crossing each other, then there is a range
* of unacknowledged data. If they meet, then the message is fully
* acknowledged. */
start = offset;
end = len;
while (!done) {
done = PR_TRUE;
for (cur_p = PR_LIST_HEAD(&ss->ssl3.hs.dtlsSentHandshake);
cur_p != &ss->ssl3.hs.dtlsSentHandshake;
cur_p = PR_NEXT_LINK(cur_p)) {
entry = (DTLSHandshakeRecordEntry *)cur_p;
if (!entry->acked || msgSeq != entry->messageSeq) {
continue;
}
if (dtls_MoveUnackedStartForward(entry, &start) ||
dtls_MoveUnackedEndBackward(entry, &end)) {
if (start >= end) {
/* The message is all acknowledged. */
return PR_FALSE;
}
/* Start over again and keep going until we don't move either
* start or end. */
done = PR_FALSE;
break;
}
}
}
PORT_Assert(start < end);
*startOut = start;
*endOut = end;
return PR_TRUE;
}
SECStatus
dtls13_SetupAcks(sslSocket *ss)
{
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return SECSuccess;
}
if (ss->ssl3.hs.endOfFlight) {
dtls_CancelTimer(ss, ss->ssl3.hs.ackTimer);
if (ss->ssl3.hs.ws == idle_handshake && ss->sec.isServer) {
SSL_TRC(10, ("%d: SSL3[%d]: dtls_HandleHandshake, sending ACK",
SSL_GETPID(), ss->fd));
return dtls13_SendAck(ss);
}
return SECSuccess;
}
/* We need to send an ACK. */
if (!ss->ssl3.hs.ackTimer->cb) {
/* We're not armed, so arm. */
SSL_TRC(10, ("%d: SSL3[%d]: dtls_HandleHandshake, arming ack timer",
SSL_GETPID(), ss->fd));
return dtls_StartTimer(ss, ss->ssl3.hs.ackTimer,
DTLS_RETRANSMIT_INITIAL_MS / 4,
dtls13_SendAckCb);
}
/* The ack timer is already armed, so just return. */
return SECSuccess;
}
/*
* Special case processing for out-of-epoch records.
* This can only handle ACKs for now and everything else generates
* an error. In future, may also handle KeyUpdate.
*
* The error checking here is as follows:
*
* - If it's not encrypted, out of epoch stuff is just discarded.
* - If it's encrypted, out of epoch stuff causes an error.
*/
SECStatus
dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
SSL3ContentType rType,
sslBuffer *databuf)
{
SECStatus rv;
sslBuffer buf = *databuf;
databuf->len = 0; /* Discard data whatever happens. */
PORT_Assert(IS_DTLS(ss));
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
/* Can't happen, but double check. */
if (!IS_DTLS(ss) || (ss->version < SSL_LIBRARY_VERSION_TLS_1_3)) {
tls13_FatalError(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
return SECFailure;
}
SSL_TRC(10, ("%d: DTLS13[%d]: handle out of epoch record: type=%d", SSL_GETPID(),
ss->fd, rType));
if (rType == content_ack) {
ssl_GetSSL3HandshakeLock(ss);
rv = dtls13_HandleAck(ss, &buf);
ssl_ReleaseSSL3HandshakeLock(ss);
PORT_Assert(databuf->len == 0);
return rv;
}
switch (spec->epoch) {
case TrafficKeyClearText:
/* Drop. */
return SECSuccess;
case TrafficKeyHandshake:
/* Drop out of order handshake messages, but if we are the
* server, we might have processed the client's Finished and
* moved on to application data keys, but the client has
* retransmitted Finished (e.g., because our ACK got lost.)
* We just retransmit the previous Finished to let the client
* complete. */
if (rType == content_handshake) {
if ((ss->sec.isServer) &&
(ss->ssl3.hs.ws == idle_handshake)) {
PORT_Assert(dtls_TimerActive(ss, ss->ssl3.hs.hdTimer));
return dtls13_SendAck(ss);
}
return SECSuccess;
}
/* This isn't a handshake record, so shouldn't be encrypted
* under the handshake key. */
break;
default:
/* Any other epoch is forbidden. */
break;
}
SSL_TRC(10, ("%d: SSL3[%d]: unexpected out of epoch record type %d", SSL_GETPID(),
ss->fd, rType));
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE);
return SECFailure;
}
SECStatus
dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
{
PRUint8 *b = databuf->buf;
PRUint32 l = databuf->len;
SECStatus rv;
/* Ensure we don't loop. */
databuf->len = 0;
PORT_Assert(IS_DTLS(ss));
if (!tls13_MaybeTls13(ss)) {
tls13_FatalError(ss, SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, illegal_parameter);
return SECSuccess;
}
SSL_TRC(10, ("%d: SSL3[%d]: Handling ACK", SSL_GETPID(), ss->fd));
while (l > 0) {
PRUint64 seq;
PRCList *cursor;
rv = ssl3_ConsumeHandshakeNumber64(ss, &seq, 8, &b, &l);
if (rv != SECSuccess) {
return SECFailure;
}
for (cursor = PR_LIST_HEAD(&ss->ssl3.hs.dtlsSentHandshake);
cursor != &ss->ssl3.hs.dtlsSentHandshake;
cursor = PR_NEXT_LINK(cursor)) {
DTLSHandshakeRecordEntry *entry = (DTLSHandshakeRecordEntry *)cursor;
if (entry->record == seq) {
SSL_TRC(10, (
"%d: SSL3[%d]: Marking record=%llx message %d offset %d length=%d as ACKed",
SSL_GETPID(), ss->fd,
seq, entry->messageSeq, entry->offset, entry->length));
entry->acked = PR_TRUE;
}
}
}
/* Try to flush. */
rv = dtls_TransmitMessageFlight(ss);
if (rv != SECSuccess) {
return SECFailure;
}
/* Reset the retransmit timer. */
if (ss->ssl3.hs.rtTimer->cb) {
(void)dtls_RestartTimer(ss, ss->ssl3.hs.rtTimer);
}
/* If there are no more messages to send, cleanup. */
if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.lastMessageFlight)) {
SSL_TRC(10, ("%d: SSL3[%d]: No more unacked handshake messages",
SSL_GETPID(), ss->fd));
dtls_CancelTimer(ss, ss->ssl3.hs.rtTimer);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL);
/* If the handshake is finished, and we're the client then
* also clean up the handshake read cipher spec. Any ACKs
* we receive will be with the application data cipher spec.
* The server needs to keep the handshake cipher spec around
* for the holddown period to process retransmitted Finisheds.
*/
if (!ss->sec.isServer && (ss->ssl3.hs.ws == idle_handshake)) {
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead,
TrafficKeyHandshake);
}
}
return SECSuccess;
}
/* Clean up the read timer for the handshake cipher suites on the
* server.
*
* In DTLS 1.3, the client speaks last (Finished), and will retransmit
* until the server ACKs that message (using application data cipher
* suites). I.e.,
*
* - The client uses the retransmit timer and retransmits using the
* saved write handshake cipher suite.
* - The server keeps the saved read handshake cipher suite around
* for the holddown period in case it needs to read the Finished.
*
* After the holddown period, the server assumes the client is happy
* and discards the handshake read cipher suite.
*/
void
dtls13_HolddownTimerCb(sslSocket *ss)
{
SSL_TRC(10, ("%d: SSL3[%d]: holddown timer fired",
SSL_GETPID(), ss->fd));
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyHandshake);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
}

View file

@ -0,0 +1,29 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __dtls13con_h_
#define __dtls13con_h_
SECStatus dtls13_RememberFragment(sslSocket *ss, PRCList *list,
PRUint32 sequence, PRUint32 offset,
PRUint32 length, DTLSEpoch epoch,
sslSequenceNumber record);
PRBool dtls_NextUnackedRange(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset,
PRUint32 len, PRUint32 *startOut, PRUint32 *endOut);
SECStatus dtls13_SetupAcks(sslSocket *ss);
SECStatus dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
SSL3ContentType rType,
sslBuffer *databuf);
SECStatus dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf);
SECStatus dtls13_SendAck(sslSocket *ss);
void dtls13_SendAckCb(sslSocket *ss);
void dtls13_HolddownTimerCb(sslSocket *ss);
void dtls_ReceivedFirstMessageInFlight(sslSocket *ss);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,48 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __dtlscon_h_
#define __dtlscon_h_
extern void dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg);
extern void dtls_FreeHandshakeMessages(PRCList *lst);
SECStatus dtls_TransmitMessageFlight(sslSocket *ss);
void dtls_InitTimers(sslSocket *ss);
SECStatus dtls_StartTimer(sslSocket *ss, dtlsTimer *timer,
PRUint32 time, DTLSTimerCb cb);
SECStatus dtls_RestartTimer(sslSocket *ss, dtlsTimer *timer);
PRBool dtls_TimerActive(sslSocket *ss, dtlsTimer *timer);
extern SECStatus dtls_HandleHandshake(sslSocket *ss, DTLSEpoch epoch,
sslSequenceNumber seqNum,
sslBuffer *origBuf);
extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss,
PRUint8 *b, PRUint32 length);
extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss);
extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
const PRUint8 *pIn, PRInt32 nIn);
extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss);
extern SECStatus dtls_StartHolddownTimer(sslSocket *ss);
extern void dtls_CheckTimer(sslSocket *ss);
extern void dtls_CancelTimer(sslSocket *ss, dtlsTimer *timer);
extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised);
extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records);
extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records,
sslSequenceNumber seq);
extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records,
sslSequenceNumber seq);
extern void dtls_RehandshakeCleanup(sslSocket *ss);
extern SSL3ProtocolVersion
dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv);
extern SSL3ProtocolVersion
dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv);
extern PRBool dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *spec,
const SSL3Ciphertext *cText,
sslSequenceNumber *seqNum);
void dtls_ReceivedFirstMessageInFlight(sslSocket *ss);
#endif

View file

@ -15,6 +15,7 @@
'preenc.h',
'ssl.h',
'sslerr.h',
'sslexp.h',
'sslproto.h',
'sslt.h'
],

View file

@ -10,6 +10,7 @@ EXPORTS = \
ssl.h \
sslt.h \
sslerr.h \
sslexp.h \
sslproto.h \
preenc.h \
$(NULL)
@ -19,13 +20,15 @@ MAPFILE = $(OBJDIR)/ssl.def
CSRCS = \
dtlscon.c \
dtls13con.c \
prelib.c \
ssl3con.c \
ssl3gthr.c \
sslauth.c \
sslbloom.c \
sslcon.c \
ssldef.c \
ssl3encode.c \
sslencode.c \
sslenum.c \
sslerr.c \
sslerrstrs.c \
@ -38,6 +41,7 @@ CSRCS = \
sslsecur.c \
sslsnce.c \
sslsock.c \
sslspec.c \
ssltrace.c \
sslver.c \
authcert.c \
@ -47,7 +51,9 @@ CSRCS = \
ssl3ecc.c \
tls13con.c \
tls13exthandle.c \
tls13hashstate.c \
tls13hkdf.c \
tls13replay.c \
sslcert.c \
sslgrp.c \
$(NULL)

View file

@ -11,7 +11,6 @@
#include "pk11func.h"
#include "ssl.h"
#include "sslt.h"
#include "ssl3encode.h"
#include "sslimpl.h"
#include "selfencrypt.h"
@ -121,12 +120,11 @@ ssl_SelfEncryptProtectInt(
PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
{
unsigned int len;
unsigned int lenOffset;
unsigned char iv[AES_BLOCK_SIZE];
SECItem ivItem = { siBuffer, iv, sizeof(iv) };
unsigned char mac[SHA256_LENGTH]; /* SHA-256 */
unsigned int macLen;
SECItem outItem = { siBuffer, out, maxOutLen };
SECItem lengthBytesItem;
/* Write directly to out. */
sslBuffer buf = SSL_BUFFER_FIXED(out, maxOutLen);
SECStatus rv;
/* Generate a random IV */
@ -137,52 +135,54 @@ ssl_SelfEncryptProtectInt(
}
/* Add header. */
rv = ssl3_AppendToItem(&outItem, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
rv = sslBuffer_Append(&buf, keyName, SELF_ENCRYPT_KEY_NAME_LEN);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_AppendToItem(&outItem, iv, sizeof(iv));
rv = sslBuffer_Append(&buf, iv, sizeof(iv));
if (rv != SECSuccess) {
return SECFailure;
}
/* Skip forward by two so we can encode the ciphertext in place. */
lengthBytesItem = outItem;
rv = ssl3_AppendNumberToItem(&outItem, 0, 2);
/* Leave space for the length of the ciphertext. */
rv = sslBuffer_Skip(&buf, 2, &lenOffset);
if (rv != SECSuccess) {
return SECFailure;
}
/* Encode the ciphertext in place. */
rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
outItem.data, &len, outItem.len, in, inLen);
SSL_BUFFER_NEXT(&buf), &len,
SSL_BUFFER_SPACE(&buf), in, inLen);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Skip(&buf, len, NULL);
if (rv != SECSuccess) {
return SECFailure;
}
outItem.data += len;
outItem.len -= len;
/* Now encode the ciphertext length. */
rv = ssl3_AppendNumberToItem(&lengthBytesItem, len, 2);
rv = sslBuffer_InsertLength(&buf, lenOffset, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* MAC the entire output buffer and append the MAC to the end. */
/* MAC the entire output buffer into the output. */
PORT_Assert(buf.space - buf.len >= SHA256_LENGTH);
rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC,
out, outItem.data - out,
mac, &macLen, sizeof(mac));
SSL_BUFFER_BASE(&buf), /* input */
SSL_BUFFER_LEN(&buf),
SSL_BUFFER_NEXT(&buf), &len, /* output */
SHA256_LENGTH);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Assert(macLen == sizeof(mac));
rv = ssl3_AppendToItem(&outItem, mac, macLen);
rv = sslBuffer_Skip(&buf, len, NULL);
if (rv != SECSuccess) {
return SECFailure;
}
*outLen = outItem.data - out;
*outLen = SSL_BUFFER_LEN(&buf);
return SECSuccess;
}
@ -269,6 +269,17 @@ ssl_SelfEncryptUnprotectInt(
}
#endif
/* Predict the size of the encrypted data, including padding */
unsigned int
ssl_SelfEncryptGetProtectedSize(unsigned int inLen)
{
return SELF_ENCRYPT_KEY_NAME_LEN +
AES_BLOCK_SIZE +
2 +
((inLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE + /* Padded */
SHA256_LENGTH;
}
SECStatus
ssl_SelfEncryptProtect(
sslSocket *ss, const PRUint8 *in, unsigned int inLen,

View file

@ -11,6 +11,7 @@
#include "secmodt.h"
unsigned int ssl_SelfEncryptGetProtectedSize(unsigned int inLen);
SECStatus ssl_SelfEncryptProtect(
sslSocket *ss, const PRUint8 *in, unsigned int inLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen);

View file

@ -234,3 +234,9 @@ SSL_AlertSentCallback;
;+ local:
;+*;
;+};
;+NSS_3.33 { # NSS 3.33 release
;+ global:
SSL_GetExperimentalAPI;
;+ local:
;+*;
;+};

View file

@ -13,18 +13,20 @@
'authcert.c',
'cmpcert.c',
'dtlscon.c',
'dtls13con.c',
'prelib.c',
'selfencrypt.c',
'ssl3con.c',
'ssl3ecc.c',
'ssl3encode.c',
'ssl3ext.c',
'ssl3exthandle.c',
'ssl3gthr.c',
'sslauth.c',
'sslbloom.c',
'sslcert.c',
'sslcon.c',
'ssldef.c',
'sslencode.c',
'sslenum.c',
'sslerr.c',
'sslerrstrs.c',
@ -37,11 +39,14 @@
'sslsecur.c',
'sslsnce.c',
'sslsock.c',
'sslspec.c',
'ssltrace.c',
'sslver.c',
'tls13con.c',
'tls13exthandle.c',
'tls13hashstate.c',
'tls13hkdf.c',
'tls13replay.c',
],
'conditions': [
[ 'OS=="win"', {
@ -57,14 +62,6 @@
'unix_err.c'
],
}],
[ 'ssl_enable_zlib==1', {
'dependencies': [
'<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib'
],
'defines': [
'NSS_SSL_ENABLE_ZLIB',
],
}],
[ 'fuzz_tls==1', {
'defines': [
'UNSAFE_FUZZER_MODE',

View file

@ -107,8 +107,7 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
#define SSL_NO_LOCKS 17 /* Don't use locks for protection */
#define SSL_ENABLE_SESSION_TICKETS 18 /* Enable TLS SessionTicket */
/* extension (off by default) */
#define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */
/* DEFLATE (off by default) */
#define SSL_ENABLE_DEFLATE 19 /* (unsupported, deprecated, off) */
#define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */
#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signaling */
/* Cipher Suite Value (SCSV) or */
@ -231,25 +230,46 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
* parameters.
*
* The transition between the 0-RTT and 1-RTT modes is marked by the
* handshake callback.
* handshake callback. However, it is possible to force the completion
* of the handshake (and cause the handshake callback to be called)
* prior to reading all 0-RTT data using SSL_ForceHandshake(). To
* ensure that all early data is read before the handshake callback, any
* time that SSL_ForceHandshake() returns a PR_WOULD_BLOCK_ERROR, use
* PR_Read() to read all available data. If PR_Read() is called
* multiple times, this will result in the handshake completing, but the
* handshake callback will occur after early data has all been read.
*
* WARNING: 0-RTT data has different anti-replay and PFS properties than
* the rest of the TLS data. See [draft-ietf-tls-tls13; Section 6.2.3]
* the rest of the TLS data. See [draft-ietf-tls-tls13; Section 8]
* for more details.
*
* Note: when DTLS 1.3 is in use, any 0-RTT data received after EndOfEarlyData
* (e.g., because of reordering) is discarded.
*/
#define SSL_ENABLE_0RTT_DATA 33
/* Enables TLS 1.3 compatibility mode. In this mode, the client includes a fake
* session ID in the handshake and sends a ChangeCipherSpec. A server will
* always use the setting chosen by the client, so the value of this option has
* no effect for a server. This setting is ignored for DTLS. */
#define SSL_ENABLE_TLS13_COMPAT_MODE 35
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on);
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRIntn on);
#endif
/* New function names */
SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRBool on);
SSL_IMPORT SECStatus SSL_OptionGet(PRFileDesc *fd, PRInt32 option, PRBool *on);
SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRBool on);
SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRBool *on);
/* Set (and get) options for sockets and defaults for newly created sockets.
*
* While the |val| parameter of these methods is PRIntn, options only support
* two values by default: PR_TRUE or PR_FALSE. The documentation of specific
* options will explain if other values are permitted.
*/
SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRIntn val);
SSL_IMPORT SECStatus SSL_OptionGet(PRFileDesc *fd, PRInt32 option, PRIntn *val);
SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRIntn val);
SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRIntn *val);
SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle);
/* SSLNextProtoCallback is called during the handshake for the client, when a
@ -1374,6 +1394,13 @@ extern const char *NSSSSL_GetVersion(void);
*/
SSL_IMPORT SECStatus SSL_AuthCertificateComplete(PRFileDesc *fd,
PRErrorCode error);
/*
* This is used to access experimental APIs. Don't call this directly. This is
* used to enable the experimental APIs that are defined in "sslexp.h".
*/
SSL_IMPORT void *SSL_GetExperimentalAPI(const char *name);
SEC_END_PROTOS
#endif /* __ssl_h_ */

File diff suppressed because it is too large Load diff

View file

@ -111,7 +111,7 @@ ssl_ECPubKey2NamedGroup(const SECKEYPublicKey *pubKey)
static SECStatus
ssl3_ComputeECDHKeyHash(SSLHashType hashAlg,
SECItem ec_params, SECItem server_ecpoint,
SSL3Random *client_rand, SSL3Random *server_rand,
PRUint8 *client_rand, PRUint8 *server_rand,
SSL3Hashes *hashes)
{
PRUint8 *hashBuf;
@ -175,8 +175,8 @@ ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2);
/* Generate ephemeral EC keypair */
if (svrPubKey->keyType != ecKey) {
@ -219,7 +219,7 @@ ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
goto loser;
}
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange,
pubKey->u.ec.publicValue.len + 1);
if (rv != SECSuccess) {
goto loser; /* err set by ssl3_AppendHandshake* */
@ -232,7 +232,7 @@ ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
goto loser; /* err set by ssl3_AppendHandshake* */
}
rv = ssl3_InitPendingCipherSpec(ss, pms);
rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
goto loser;
@ -250,19 +250,6 @@ loser:
return SECFailure;
}
/* This function encodes the key_exchange field in
* the KeyShareEntry structure. */
SECStatus
tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss, const SECKEYPublicKey *pubKey)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(pubKey->keyType == ecKey);
return ssl3_ExtAppendHandshake(ss, pubKey->u.ec.publicValue.data,
pubKey->u.ec.publicValue.len);
}
/*
** Called from ssl3_HandleClientKeyExchange()
*/
@ -326,7 +313,7 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b,
return SECFailure;
}
rv = ssl3_InitPendingCipherSpec(ss, pms);
rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE);
PK11_FreeSymKey(pms);
if (rv != SECSuccess) {
/* error code set by ssl3_InitPendingCipherSpec */
@ -597,8 +584,8 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length)
* check to make sure the hash is signed by right guy
*/
rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, ec_point,
&ss->ssl3.hs.client_random,
&ss->ssl3.hs.server_random,
ss->ssl3.hs.client_random,
ss->ssl3.hs.server_random,
&hashes);
if (rv != SECSuccess) {
@ -703,7 +690,7 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss)
ec_params.data[2] = keyPair->group->name & 0xff;
pubKey = keyPair->keys->pubKey;
if (ss->ssl3.pwSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) {
if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) {
hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme);
} else {
/* Use ssl_hash_none to represent the MD5+SHA1 combo. */
@ -711,15 +698,15 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss)
}
rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params,
pubKey->u.ec.publicValue,
&ss->ssl3.hs.client_random,
&ss->ssl3.hs.server_random,
ss->ssl3.hs.client_random,
ss->ssl3.hs.server_random,
&hashes);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
goto loser;
}
isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2);
rv = ssl3_SignHashes(ss, &hashes,
ss->sec.serverCert->serverKeyPair->privKey, &signed_hash);
@ -731,7 +718,7 @@ ssl3_SendECDHServerKeyExchange(sslSocket *ss)
1 + pubKey->u.ec.publicValue.len +
(isTLS12 ? 2 : 0) + 2 + signed_hash.len;
rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
@ -870,20 +857,16 @@ ssl_IsDHEEnabled(const sslSocket *ss)
}
/* Send our Supported Groups extension. */
PRInt32
ssl_SendSupportedGroupsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes)
SECStatus
ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
PRInt32 extension_length;
unsigned char enabledGroups[64];
unsigned int enabledGroupsLen = 0;
unsigned int i;
PRBool ec;
PRBool ff = PR_FALSE;
if (!ss)
return 0;
PRBool found = PR_FALSE;
SECStatus rv;
unsigned int lengthOffset;
/* We only send FF supported groups if we require DH named groups
* or if TLS 1.3 is a possibility. */
@ -892,13 +875,19 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss,
if (ss->opt.requireDHENamedGroups) {
ff = ssl_IsDHEEnabled(ss);
}
if (!ec && !ff)
return 0;
if (!ec && !ff) {
return SECSuccess;
}
} else {
ec = ff = PR_TRUE;
}
PORT_Assert(sizeof(enabledGroups) > SSL_NAMED_GROUP_COUNT * 2);
/* Mark the location of the length. */
rv = sslBuffer_Skip(buf, 2, &lengthOffset);
if (rv != SECSuccess) {
return SECFailure;
}
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
const sslNamedGroupDef *group = ss->namedGroupPreferences[i];
if (!group) {
@ -911,78 +900,53 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss,
continue;
}
if (append) {
(void)ssl_EncodeUintX(group->name, 2, &enabledGroups[enabledGroupsLen]);
}
enabledGroupsLen += 2;
}
if (enabledGroupsLen == 0) {
return 0;
}
extension_length =
2 /* extension type */ +
2 /* extension length */ +
2 /* enabled groups length */ +
enabledGroupsLen;
if (maxBytes < (PRUint32)extension_length) {
return 0;
}
if (append) {
SECStatus rv;
rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_supported_groups_xtn, 2);
if (rv != SECSuccess)
return -1;
rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
if (rv != SECSuccess)
return -1;
rv = ssl3_ExtAppendHandshakeVariable(ss, enabledGroups,
enabledGroupsLen, 2);
if (rv != SECSuccess)
return -1;
if (!ss->sec.isServer) {
xtnData->advertised[xtnData->numAdvertised++] =
ssl_supported_groups_xtn;
found = PR_TRUE;
rv = sslBuffer_AppendNumber(buf, group->name, 2);
if (rv != SECSuccess) {
return SECFailure;
}
}
return extension_length;
if (!found) {
/* We added nothing, don't send the extension. */
return SECSuccess;
}
rv = sslBuffer_InsertLength(buf, lengthOffset, 2);
if (rv != SECSuccess) {
return SECFailure;
}
*added = PR_TRUE;
return SECSuccess;
}
/* Send our "canned" (precompiled) Supported Point Formats extension,
* which says that we only support uncompressed points.
*/
PRInt32
ssl3_SendSupportedPointFormatsXtn(
const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes)
SECStatus
ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added)
{
static const PRUint8 ecPtFmt[6] = {
0, 11, /* Extension type */
0, 2, /* octets that follow */
1, /* octets that follow */
0 /* uncompressed type only */
};
SECStatus rv;
/* No point in doing this unless we have a socket that supports ECC.
* Similarly, no point if we are going to do TLS 1.3 only or we have already
* picked TLS 1.3 (server) given that it doesn't use point formats. */
if (!ss || !ssl_IsECCEnabled(ss) ||
ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_3 ||
(ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3))
return 0;
if (append && maxBytes >= (sizeof ecPtFmt)) {
SECStatus rv = ssl3_ExtAppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt));
if (rv != SECSuccess)
return -1;
if (!ss->sec.isServer) {
xtnData->advertised[xtnData->numAdvertised++] =
ssl_ec_point_formats_xtn;
}
(ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)) {
return SECSuccess;
}
return sizeof(ecPtFmt);
rv = sslBuffer_AppendNumber(buf, 1, 1); /* length */
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(buf, 0, 1); /* uncompressed type only */
if (rv != SECSuccess) {
return SECFailure;
}
*added = PR_TRUE;
return SECSuccess;
}

View file

@ -14,8 +14,20 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "ssl3exthandle.h"
#include "tls13err.h"
#include "tls13exthandle.h"
/* Callback function that handles a received extension. */
typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
/* Row in a table of hello extension handlers. */
typedef struct {
SSLExtensionType ex_type;
ssl3ExtensionHandlerFunc ex_handler;
} ssl3ExtensionHandler;
/* Table of handlers for received TLS hello extensions, one per extension.
* In the second generation, this table will be dynamic, and functions
* will be registered here.
@ -31,16 +43,15 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
{ ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
{ ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
{ ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
{ ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
{ ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
{ ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
{ ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
{ ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn,
&tls13_ServerHandlePskKeyExchangeModesXtn },
{ ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn },
{ -1, NULL }
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
{ ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
{ 0, NULL }
};
/* These two tables are used by the client, to handle server hello
@ -59,36 +70,38 @@ static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
{ ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
{ ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
{ ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn },
{ -1, NULL }
{ 0, NULL }
};
static const ssl3ExtensionHandler helloRetryRequestHandlers[] = {
{ ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr },
{ ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie },
{ -1, NULL }
{ 0, NULL }
};
static const ssl3ExtensionHandler serverHelloHandlersSSL3[] = {
{ ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
{ -1, NULL }
{ 0, NULL }
};
static const ssl3ExtensionHandler newSessionTicketHandlers[] = {
{ ssl_tls13_ticket_early_data_info_xtn,
&tls13_ClientHandleTicketEarlyDataInfoXtn },
{ -1, NULL }
{ ssl_tls13_early_data_xtn,
&tls13_ClientHandleTicketEarlyDataXtn },
{ 0, NULL }
};
/* This table is used by the client to handle server certificates in TLS 1.3 */
static const ssl3ExtensionHandler serverCertificateHandlers[] = {
{ ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
{ ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
{ -1, NULL }
{ 0, NULL }
};
static const ssl3ExtensionHandler certificateRequestHandlers[] = {
{ -1, NULL }
{ ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
{ ssl_tls13_certificate_authorities_xtn,
&tls13_ClientHandleCertAuthoritiesXtn },
{ 0, NULL }
};
/* Tables of functions to format TLS hello extensions, one function per
@ -101,14 +114,14 @@ static const ssl3ExtensionHandler certificateRequestHandlers[] = {
* the client hello is empty (for example, the extended master secret
* extension, if it were listed last). See bug 1243641.
*/
static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] =
static const sslExtensionBuilder clientHelloSendersTLS[] =
{
{ ssl_server_name_xtn, &ssl3_SendServerNameXtn },
{ ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn },
{ ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
{ ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
{ ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
{ ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
{ ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
{ ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn },
{ ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
{ ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
{ ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
@ -121,22 +134,155 @@ static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS]
* client hello is empty. They are not intolerant of TLS 1.2, so list
* signature_algorithms at the end. See bug 1243641. */
{ ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn },
{ ssl_tls13_short_header_xtn, &tls13_SendShortHeaderXtn },
{ ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn },
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
{ ssl_tls13_psk_key_exchange_modes_xtn,
&tls13_ClientSendPskKeyExchangeModesXtn },
{ ssl_padding_xtn, &ssl3_ClientSendPaddingExtension },
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
/* The pre_shared_key extension MUST be last. */
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
/* any extra entries will appear as { 0, NULL } */
{ 0, NULL }
};
static const ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = {
{ ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn }
/* any extra entries will appear as { 0, NULL } */
static const sslExtensionBuilder clientHelloSendersSSL3[] = {
{ ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
{ 0, NULL }
};
static const sslExtensionBuilder tls13_cert_req_senders[] = {
{ ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
{ ssl_tls13_certificate_authorities_xtn, &tls13_SendCertAuthoritiesXtn },
{ 0, NULL }
};
static const sslExtensionBuilder tls13_hrr_senders[] = {
{ ssl_tls13_key_share_xtn, &tls13_ServerSendHrrKeyShareXtn },
{ ssl_tls13_cookie_xtn, &tls13_ServerSendHrrCookieXtn },
{ ssl_tls13_supported_versions_xtn, &tls13_ServerSendSupportedVersionsXtn },
{ 0, NULL }
};
static const struct {
SSLExtensionType type;
SSLExtensionSupport support;
} ssl_supported_extensions[] = {
{ ssl_server_name_xtn, ssl_ext_native_only },
{ ssl_cert_status_xtn, ssl_ext_native },
{ ssl_supported_groups_xtn, ssl_ext_native_only },
{ ssl_ec_point_formats_xtn, ssl_ext_native },
{ ssl_signature_algorithms_xtn, ssl_ext_native_only },
{ ssl_use_srtp_xtn, ssl_ext_native },
{ ssl_app_layer_protocol_xtn, ssl_ext_native_only },
{ ssl_signed_cert_timestamp_xtn, ssl_ext_native },
{ ssl_padding_xtn, ssl_ext_native },
{ ssl_extended_master_secret_xtn, ssl_ext_native_only },
{ ssl_session_ticket_xtn, ssl_ext_native_only },
{ ssl_tls13_key_share_xtn, ssl_ext_native_only },
{ ssl_tls13_pre_shared_key_xtn, ssl_ext_native_only },
{ ssl_tls13_early_data_xtn, ssl_ext_native_only },
{ ssl_tls13_supported_versions_xtn, ssl_ext_native_only },
{ ssl_tls13_cookie_xtn, ssl_ext_native_only },
{ ssl_tls13_psk_key_exchange_modes_xtn, ssl_ext_native_only },
{ ssl_tls13_ticket_early_data_info_xtn, ssl_ext_native_only },
{ ssl_tls13_certificate_authorities_xtn, ssl_ext_native },
{ ssl_next_proto_nego_xtn, ssl_ext_none },
{ ssl_renegotiation_info_xtn, ssl_ext_native }
};
static SSLExtensionSupport
ssl_GetExtensionSupport(PRUint16 type)
{
unsigned int i;
for (i = 0; i < PR_ARRAY_SIZE(ssl_supported_extensions); ++i) {
if (type == ssl_supported_extensions[i].type) {
return ssl_supported_extensions[i].support;
}
}
return ssl_ext_none;
}
SECStatus
SSLExp_GetExtensionSupport(PRUint16 type, SSLExtensionSupport *support)
{
*support = ssl_GetExtensionSupport(type);
return SECSuccess;
}
SECStatus
SSLExp_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension,
SSLExtensionWriter writer, void *writerArg,
SSLExtensionHandler handler, void *handlerArg)
{
sslSocket *ss = ssl_FindSocket(fd);
PRCList *cursor;
sslCustomExtensionHooks *hook;
if (!ss) {
return SECFailure; /* Code already set. */
}
/* Need to specify both or neither, but not just one. */
if ((writer && !handler) || (!writer && handler)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (ssl_GetExtensionSupport(extension) == ssl_ext_native_only) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (ss->firstHsDone || ((ss->ssl3.hs.ws != idle_handshake) &&
(ss->ssl3.hs.ws != wait_client_hello))) {
PORT_SetError(PR_INVALID_STATE_ERROR);
return SECFailure;
}
/* Remove any old handler. */
for (cursor = PR_NEXT_LINK(&ss->extensionHooks);
cursor != &ss->extensionHooks;
cursor = PR_NEXT_LINK(cursor)) {
hook = (sslCustomExtensionHooks *)cursor;
if (hook->type == extension) {
PR_REMOVE_LINK(&hook->link);
PORT_Free(hook);
break;
}
}
if (!writer && !handler) {
return SECSuccess;
}
hook = PORT_ZNew(sslCustomExtensionHooks);
if (!hook) {
return SECFailure; /* This removed the old one, oh well. */
}
hook->type = extension;
hook->writer = writer;
hook->writerArg = writerArg;
hook->handler = handler;
hook->handlerArg = handlerArg;
PR_APPEND_LINK(&hook->link, &ss->extensionHooks);
return SECSuccess;
}
static sslCustomExtensionHooks *
ssl_FindCustomExtensionHooks(sslSocket *ss, PRUint16 extension)
{
PRCList *cursor;
for (cursor = PR_NEXT_LINK(&ss->extensionHooks);
cursor != &ss->extensionHooks;
cursor = PR_NEXT_LINK(cursor)) {
sslCustomExtensionHooks *hook = (sslCustomExtensionHooks *)cursor;
if (hook->type == extension) {
return hook;
}
}
return NULL;
}
static PRBool
arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type)
{
@ -156,8 +302,11 @@ ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type)
xtnData->numNegotiated, ex_type);
}
/* This checks for whether an extension was advertised. On the client, this
* covers extensions that are sent in ClientHello; on the server, extensions
* sent in CertificateRequest (TLS 1.3 only). */
PRBool
ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type)
ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type)
{
const TLSExtensionData *xtnData = &ss->xtnData;
return arrayContainsExtension(xtnData->advertised,
@ -240,6 +389,44 @@ ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type)
return NULL;
}
static SECStatus
ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage,
TLSExtension *extension,
const ssl3ExtensionHandler *handler)
{
SECStatus rv = SECSuccess;
SSLAlertDescription alert = handshake_failure;
sslCustomExtensionHooks *customHooks;
customHooks = ssl_FindCustomExtensionHooks(ss, extension->type);
if (customHooks) {
if (customHooks->handler) {
rv = customHooks->handler(ss->fd, handshakeMessage,
extension->data.data,
extension->data.len,
&alert, customHooks->handlerArg);
}
} else {
/* Find extension_type in table of Hello Extension Handlers. */
for (; handler->ex_handler != NULL; ++handler) {
if (handler->ex_type == extension->type) {
rv = (*handler->ex_handler)(ss, &ss->xtnData, &extension->data);
break;
}
}
}
if (rv != SECSuccess) {
if (!ss->ssl3.fatalAlertSent) {
/* Send an alert if the handler didn't already. */
(void)SSL3_SendAlert(ss, alert_fatal, alert);
}
return SECFailure;
}
return SECSuccess;
}
/* Go through the hello extensions in |ss->ssl3.hs.remoteExtensions|.
* For each one, find the extension handler in the table, and
* if present, invoke that handler.
@ -250,42 +437,46 @@ ssl3_FindExtension(sslSocket *ss, SSLExtensionType extension_type)
* right phase.
*/
SECStatus
ssl3_HandleParsedExtensions(sslSocket *ss,
SSL3HandshakeType handshakeMessage)
ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message)
{
const ssl3ExtensionHandler *handlers;
/* HelloRetryRequest doesn't set ss->version. It might be safe to
* do so, but we weren't entirely sure. TODO(ekr@rtfm.com). */
PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) ||
(handshakeMessage == hello_retry_request);
(message == ssl_hs_hello_retry_request);
/* The following messages can include extensions that were not included in
* the original ClientHello. */
PRBool allowNotOffered = (message == ssl_hs_client_hello) ||
(message == ssl_hs_certificate_request) ||
(message == ssl_hs_new_session_ticket);
PRCList *cursor;
switch (handshakeMessage) {
case client_hello:
switch (message) {
case ssl_hs_client_hello:
handlers = clientHelloHandlers;
break;
case new_session_ticket:
case ssl_hs_new_session_ticket:
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
handlers = newSessionTicketHandlers;
break;
case hello_retry_request:
case ssl_hs_hello_retry_request:
handlers = helloRetryRequestHandlers;
break;
case encrypted_extensions:
case ssl_hs_encrypted_extensions:
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
/* fall through */
case server_hello:
case ssl_hs_server_hello:
if (ss->version > SSL_LIBRARY_VERSION_3_0) {
handlers = serverHelloHandlersTLS;
} else {
handlers = serverHelloHandlersSSL3;
}
break;
case certificate:
case ssl_hs_certificate:
PORT_Assert(!ss->sec.isServer);
handlers = serverCertificateHandlers;
break;
case certificate_request:
case ssl_hs_certificate_request:
PORT_Assert(!ss->sec.isServer);
handlers = certificateRequestHandlers;
break;
@ -299,28 +490,39 @@ ssl3_HandleParsedExtensions(sslSocket *ss,
cursor != &ss->ssl3.hs.remoteExtensions;
cursor = PR_NEXT_LINK(cursor)) {
TLSExtension *extension = (TLSExtension *)cursor;
const ssl3ExtensionHandler *handler;
SECStatus rv;
/* Check whether the server sent an extension which was not advertised
* in the ClientHello */
if (!ss->sec.isServer &&
!ssl3_ClientExtensionAdvertised(ss, extension->type) &&
(handshakeMessage != new_session_ticket) &&
(extension->type != ssl_tls13_cookie_xtn)) {
* in the ClientHello.
*
* Note that a TLS 1.3 server should check if CertificateRequest
* extensions were sent. But the extensions used for CertificateRequest
* do not have any response, so we rely on
* ssl3_ExtensionAdvertised to return false on the server. That
* results in the server only rejecting any extension. */
if (!allowNotOffered && (extension->type != ssl_tls13_cookie_xtn) &&
!ssl3_ExtensionAdvertised(ss, extension->type)) {
(void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION);
return SECFailure;
}
/* Check that this is a legal extension in TLS 1.3 */
if (isTLS13 && !tls13_ExtensionAllowed(extension->type, handshakeMessage)) {
if (handshakeMessage == client_hello) {
/* Skip extensions not used in TLS 1.3 */
continue;
if (isTLS13 &&
!ssl_FindCustomExtensionHooks(ss, extension->type)) {
switch (tls13_ExtensionStatus(extension->type, message)) {
case tls13_extension_allowed:
break;
case tls13_extension_unknown:
if (allowNotOffered) {
continue; /* Skip over unknown extensions. */
}
/* Fall through. */
case tls13_extension_disallowed:
tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
unsupported_extension);
return SECFailure;
}
tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
unsupported_extension);
return SECFailure;
}
/* Special check for this being the last extension if it's
@ -334,23 +536,9 @@ ssl3_HandleParsedExtensions(sslSocket *ss,
return SECFailure;
}
/* find extension_type in table of Hello Extension Handlers */
for (handler = handlers; handler->ex_type >= 0; handler++) {
/* if found, call this handler */
if (handler->ex_type == extension->type) {
SECStatus rv;
rv = (*handler->ex_handler)(ss, &ss->xtnData,
(PRUint16)extension->type,
&extension->data);
if (rv != SECSuccess) {
if (!ss->ssl3.fatalAlertSent) {
/* send a generic alert if the handler didn't already */
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
}
return SECFailure;
}
}
rv = ssl_CallExtensionHandler(ss, message, extension, handlers);
if (rv != SECSuccess) {
return SECFailure;
}
}
return SECSuccess;
@ -361,7 +549,7 @@ ssl3_HandleParsedExtensions(sslSocket *ss,
SECStatus
ssl3_HandleExtensions(sslSocket *ss,
PRUint8 **b, PRUint32 *length,
SSL3HandshakeType handshakeMessage)
SSLHandshakeType handshakeMessage)
{
SECStatus rv;
@ -383,21 +571,30 @@ SECStatus
ssl3_RegisterExtensionSender(const sslSocket *ss,
TLSExtensionData *xtnData,
PRUint16 ex_type,
ssl3HelloExtensionSenderFunc cb)
sslExtensionBuilderFunc cb)
{
int i;
ssl3HelloExtensionSender *sender;
sslExtensionBuilder *sender;
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
sender = &xtnData->serverHelloSenders[0];
} else {
if (tls13_ExtensionAllowed(ex_type, server_hello)) {
PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions));
if (tls13_ExtensionStatus(ex_type, ssl_hs_server_hello) ==
tls13_extension_allowed) {
PORT_Assert(tls13_ExtensionStatus(ex_type,
ssl_hs_encrypted_extensions) ==
tls13_extension_disallowed);
sender = &xtnData->serverHelloSenders[0];
} else if (tls13_ExtensionAllowed(ex_type, certificate)) {
} else if (tls13_ExtensionStatus(ex_type,
ssl_hs_encrypted_extensions) ==
tls13_extension_allowed) {
sender = &xtnData->encryptedExtensionsSenders[0];
} else if (tls13_ExtensionStatus(ex_type, ssl_hs_certificate) ==
tls13_extension_allowed) {
sender = &xtnData->certificateSenders[0];
} else {
PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions));
sender = &xtnData->encryptedExtensionsSenders[0];
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
}
for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
@ -418,32 +615,289 @@ ssl3_RegisterExtensionSender(const sslSocket *ss,
return SECFailure;
}
/* call each of the extension senders and return the accumulated length */
PRInt32
ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
const ssl3HelloExtensionSender *sender)
static SECStatus
ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf,
SSLHandshakeType message)
{
PRInt32 total_exten_len = 0;
int i;
sslBuffer tail = SSL_BUFFER_EMPTY;
SECStatus rv;
PRCList *cursor;
if (!sender) {
if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) {
sender = &clientHelloSendersTLS[0];
} else {
sender = &clientHelloSendersSSL3[0];
/* Save any extensions that want to be last. */
if (ss->xtnData.lastXtnOffset) {
rv = sslBuffer_Append(&tail, buf->buf + ss->xtnData.lastXtnOffset,
buf->len - ss->xtnData.lastXtnOffset);
if (rv != SECSuccess) {
return SECFailure;
}
buf->len = ss->xtnData.lastXtnOffset;
}
/* 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;
}
}
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;
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;
}
}
return total_exten_len;
if (!PR_CLIST_IS_EMPTY(&ss->extensionHooks)) {
rv = ssl_CallCustomExtensionSenders(ss, buf, message);
if (rv != SECSuccess) {
goto loser;
}
}
if (buf->len > 0xffff) {
PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG);
goto loser;
}
return SECSuccess;
loser:
sslBuffer_Clear(buf);
return SECFailure;
}
/* This extension sender can be used anywhere that an always empty extension is
* needed. Mostly that is for ServerHello where sender registration is dynamic;
* ClientHello senders are usually conditional in some way. */
SECStatus
ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append)
{
*append = PR_TRUE;
return SECSuccess;
}
/* Takes the size of the ClientHello, less the record header, and determines how
* much padding is required. */
static unsigned int
ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength)
{
unsigned int recordLength = 1 /* handshake message type */ +
3 /* handshake message length */ +
clientHelloLength;
unsigned int extensionLen;
/* Don't pad for DTLS, for SSLv3, or for renegotiation. */
if (IS_DTLS(ss) ||
ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 ||
ss->firstHsDone) {
return 0;
}
/* A padding extension may be included to ensure that the record containing
* the ClientHello doesn't have a length between 256 and 511 bytes
* (inclusive). Initial ClientHello records with such lengths trigger bugs
* in F5 devices. */
if (recordLength < 256 || recordLength >= 512) {
return 0;
}
extensionLen = 512 - recordLength;
/* Extensions take at least four bytes to encode. Always include at least
* one byte of data if we are padding. Some servers will time out or
* terminate the connection if the last ClientHello extension is empty. */
if (extensionLen < 5) {
extensionLen = 5;
}
return extensionLen - 4;
}
/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a
* ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures
* that we don't trigger bugs in F5 products.
*
* This takes an existing extension buffer, |buf|, and the length of the
* remainder of the ClientHello, |prefixLen|. It modifies the extension buffer
* to insert padding at the right place.
*/
SECStatus
ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen,
sslBuffer *buf)
{
static unsigned char padding[252] = { 0 };
unsigned int paddingLen;
unsigned int tailLen;
SECStatus rv;
/* Account for the size of the header, the length field of the extensions
* block and the size of the existing extensions. */
paddingLen = ssl_CalculatePaddingExtLen(ss, prefixLen + 2 + buf->len);
if (!paddingLen) {
return SECSuccess;
}
/* Move the tail if there is one. This only happens if we are sending the
* TLS 1.3 PSK extension, which needs to be at the end. */
if (ss->xtnData.lastXtnOffset) {
PORT_Assert(buf->len > ss->xtnData.lastXtnOffset);
tailLen = buf->len - ss->xtnData.lastXtnOffset;
rv = sslBuffer_Grow(buf, buf->len + 4 + paddingLen);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Memmove(buf->buf + ss->xtnData.lastXtnOffset + 4 + paddingLen,
buf->buf + ss->xtnData.lastXtnOffset,
tailLen);
buf->len = ss->xtnData.lastXtnOffset;
} else {
tailLen = 0;
}
rv = sslBuffer_AppendNumber(buf, ssl_padding_xtn, 2);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
rv = sslBuffer_AppendVariable(buf, padding, paddingLen, 2);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
buf->len += tailLen;
return SECSuccess;
}
void
@ -460,52 +914,59 @@ ssl3_DestroyRemoteExtensions(PRCList *list)
/* Initialize the extension data block. */
void
ssl3_InitExtensionData(TLSExtensionData *xtnData)
ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
{
unsigned int advertisedMax;
PRCList *cursor;
/* Set things up to the right starting state. */
PORT_Memset(xtnData, 0, sizeof(*xtnData));
xtnData->peerSupportsFfdheGroups = PR_FALSE;
PR_INIT_CLIST(&xtnData->remoteKeyShares);
/* Allocate enough to allow for native extensions, plus any custom ones. */
if (ss->sec.isServer) {
advertisedMax = PR_MAX(PR_ARRAY_SIZE(certificateRequestHandlers),
PR_ARRAY_SIZE(tls13_cert_req_senders));
} else {
advertisedMax = PR_MAX(PR_ARRAY_SIZE(clientHelloHandlers),
PR_ARRAY_SIZE(clientHelloSendersTLS));
++advertisedMax; /* For the RI SCSV, which we also track. */
}
for (cursor = PR_NEXT_LINK(&ss->extensionHooks);
cursor != &ss->extensionHooks;
cursor = PR_NEXT_LINK(cursor)) {
++advertisedMax;
}
xtnData->advertised = PORT_ZNewArray(PRUint16, advertisedMax);
}
void
ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
{
ssl3_FreeSniNameArray(xtnData);
PORT_Free(xtnData->sigSchemes);
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);
}
/* Free everything that has been allocated and then reset back to
* the starting state. */
void
ssl3_ResetExtensionData(TLSExtensionData *xtnData)
ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss)
{
/* Clean up. */
ssl3_FreeSniNameArray(xtnData);
PORT_Free(xtnData->clientSigSchemes);
SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
tls13_DestroyKeyShares(&xtnData->remoteKeyShares);
/* Now reinit. */
ssl3_InitExtensionData(xtnData);
ssl3_DestroyExtensionData(xtnData);
ssl3_InitExtensionData(xtnData, ss);
}
/* Thunks to let extension handlers operate on const sslSocket* objects. */
SECStatus
ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src,
PRInt32 bytes)
{
return ssl3_AppendHandshake((sslSocket *)ss, void_src, bytes);
}
SECStatus
ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num,
PRInt32 lenSize)
{
return ssl3_AppendHandshakeNumber((sslSocket *)ss, num, lenSize);
}
SECStatus
ssl3_ExtAppendHandshakeVariable(const sslSocket *ss,
const PRUint8 *src, PRInt32 bytes,
PRInt32 lenSize)
{
return ssl3_AppendHandshakeVariable((sslSocket *)ss, src, bytes, lenSize);
}
void
ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level,
SSL3AlertDescription desc)

View file

@ -9,54 +9,38 @@
#ifndef __ssl3ext_h_
#define __ssl3ext_h_
#include "sslencode.h"
typedef enum {
sni_nametype_hostname
} SNINameType;
typedef struct TLSExtensionDataStr TLSExtensionData;
/* registerable callback function that either appends extension to buffer
/* Registerable callback function that either appends extension to buffer
* or returns length of data that it would have appended.
*/
typedef PRInt32 (*ssl3HelloExtensionSenderFunc)(const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
/* registerable callback function that handles a received extension,
* of the given type.
*/
typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss,
TLSExtensionData *xtnData,
PRUint16 ex_type,
SECItem *data);
typedef SECStatus (*sslExtensionBuilderFunc)(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
/* row in a table of hello extension senders */
typedef struct {
PRInt32 ex_type;
ssl3HelloExtensionSenderFunc ex_sender;
} ssl3HelloExtensionSender;
/* row in a table of hello extension handlers */
typedef struct {
PRInt32 ex_type;
ssl3ExtensionHandlerFunc ex_handler;
} ssl3ExtensionHandler;
sslExtensionBuilderFunc ex_sender;
} sslExtensionBuilder;
struct TLSExtensionDataStr {
/* registered callbacks that send server hello extensions */
ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS];
ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS];
ssl3HelloExtensionSender certificateSenders[SSL_MAX_EXTENSIONS];
sslExtensionBuilder serverHelloSenders[SSL_MAX_EXTENSIONS];
sslExtensionBuilder encryptedExtensionsSenders[SSL_MAX_EXTENSIONS];
sslExtensionBuilder certificateSenders[SSL_MAX_EXTENSIONS];
/* Keep track of the extensions that are negotiated. */
/* Keep track of the extensions that are advertised or negotiated. */
PRUint16 numAdvertised;
PRUint16 *advertised; /* Allocated dynamically. */
PRUint16 numNegotiated;
PRUint16 advertised[SSL_MAX_EXTENSIONS];
PRUint16 negotiated[SSL_MAX_EXTENSIONS];
/* Amount of padding we need to add. */
PRUint16 paddingLen;
/* SessionTicket Extension related data. */
PRBool ticketTimestampVerified;
PRBool emptySessionTicket;
@ -86,10 +70,13 @@ struct TLSExtensionDataStr {
PRBool peerSupportsFfdheGroups; /* if the peer supports named ffdhe groups */
/* clientSigAndHash contains the contents of the signature_algorithms
* extension (if any) from the client. This is only valid for TLS 1.2
* or later. */
SSLSignatureScheme *clientSigSchemes;
unsigned int numClientSigScheme;
* extension (if any) the other side supports. This is only valid for TLS
* 1.2 or later. In TLS 1.3, it is also used for CertificateRequest. */
SSLSignatureScheme *sigSchemes;
unsigned int numSigSchemes;
SECItem certReqContext;
CERTDistNames certReqAuthorities;
/* In a client: if the server supports Next Protocol Negotiation, then
* this is the protocol that was negotiated.
@ -99,9 +86,18 @@ struct TLSExtensionDataStr {
PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */
SECItem pskBinder; /* The PSK binder for the first PSK (TLS 1.3) */
unsigned long pskBinderPrefixLen; /* The length of the binder input. */
PRCList remoteKeyShares; /* The other side's public keys (TLS 1.3) */
unsigned int lastXtnOffset; /* Where to insert padding. 0 = end. */
PRCList remoteKeyShares; /* The other side's public keys (TLS 1.3) */
/* The following are used by a TLS 1.3 server. */
SECItem pskBinder; /* The binder for the first PSK. */
unsigned int pskBindersLen; /* The length of the binders. */
PRUint32 ticketAge; /* Used to accept early data. */
SECItem cookie; /* HRR Cookie. */
const sslNamedGroupDef *selectedGroup; /* For HRR. */
/* The application token contains a value that was passed to the client via
* a session ticket, or the cookie in a HelloRetryRequest. */
SECItem applicationToken;
};
typedef struct TLSExtensionStr {
@ -110,40 +106,44 @@ typedef struct TLSExtensionStr {
SECItem data; /* Pointers into the handshake data. */
} TLSExtension;
typedef struct sslCustomExtensionHooks {
PRCList link;
PRUint16 type;
SSLExtensionWriter writer;
void *writerArg;
SSLExtensionHandler handler;
void *handlerArg;
} sslCustomExtensionHooks;
SECStatus ssl3_HandleExtensions(sslSocket *ss,
PRUint8 **b, PRUint32 *length,
SSL3HandshakeType handshakeMessage);
SSLHandshakeType handshakeMessage);
SECStatus ssl3_ParseExtensions(sslSocket *ss,
PRUint8 **b, PRUint32 *length);
SECStatus ssl3_HandleParsedExtensions(sslSocket *ss,
SSL3HandshakeType handshakeMessage);
SSLHandshakeType handshakeMessage);
TLSExtension *ssl3_FindExtension(sslSocket *ss,
SSLExtensionType extension_type);
void ssl3_DestroyRemoteExtensions(PRCList *list);
void ssl3_InitExtensionData(TLSExtensionData *xtnData);
void ssl3_ResetExtensionData(TLSExtensionData *xtnData);
void ssl3_InitExtensionData(TLSExtensionData *xtnData, const sslSocket *ss);
void ssl3_DestroyExtensionData(TLSExtensionData *xtnData);
void ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss);
PRBool ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type);
PRBool ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type);
PRBool ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type);
SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss,
TLSExtensionData *xtnData,
PRUint16 ex_type,
ssl3HelloExtensionSenderFunc cb);
PRInt32 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
const ssl3HelloExtensionSender *sender);
void ssl3_CalculatePaddingExtLen(sslSocket *ss,
unsigned int clientHelloLength);
sslExtensionBuilderFunc cb);
SECStatus ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf,
SSLHandshakeType message);
SECStatus ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen,
sslBuffer *buf);
/* Thunks to let us operate on const sslSocket* objects. */
SECStatus ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src,
PRInt32 bytes);
SECStatus ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num,
PRInt32 lenSize);
SECStatus ssl3_ExtAppendHandshakeVariable(const sslSocket *ss,
const PRUint8 *src, PRInt32 bytes,
PRInt32 lenSize);
void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level,
SSL3AlertDescription desc);
void ssl3_ExtDecodeError(const sslSocket *ss);
@ -156,4 +156,10 @@ SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
PRUint32 bytes, PRUint8 **b,
PRUint32 *length);
SECStatus SSLExp_GetExtensionSupport(PRUint16 type,
SSLExtensionSupport *support);
SECStatus SSLExp_InstallExtensionHooks(
PRFileDesc *fd, PRUint16 extension, SSLExtensionWriter writer,
void *writerArg, SSLExtensionHandler handler, void *handlerArg);
#endif

File diff suppressed because it is too large Load diff

View file

@ -9,90 +9,114 @@
#ifndef __ssl3exthandle_h_
#define __ssl3exthandle_h_
PRInt32 ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
SECStatus ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type, SECItem *data);
SECStatus ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type, SECItem *data);
SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type, SECItem *data);
SECStatus ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type, SECItem *data);
SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
PRInt32 ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes);
PRInt32 ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes);
PRInt32 ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes);
PRInt32 ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes);
PRInt32 ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes);
SECStatus ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
PRInt32 ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type, SECItem *data);
SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type,
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);
#include "sslencode.h"
PRInt32 ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
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);
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);
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, 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,
PRBool append, PRUint32 maxBytes);
PRInt32 ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
SECStatus ssl3_SendRenegotiationInfoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
SECItem *data);
SECStatus ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ClientSendAppProtoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ServerSendAppProtoXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ClientSendUseSRTPXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ServerSendUseSRTPXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
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,
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);
SECStatus ssl3_ClientSendPaddingExtension(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
/* out */ SECItem *appToken);
SECStatus ssl3_ClientSendServerNameXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_HandleServerNameXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ClientSendSessionTicketXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl_SendSupportedGroupsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
#endif

View file

@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Gather (Read) entire SSL3 records from socket into buffer.
*
@ -98,7 +99,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
if (gs->state == GS_INIT) {
gs->state = GS_HEADER;
gs->remainder = ss->ssl3.hs.shortHeaders ? 2 : 5;
gs->remainder = 5;
gs->offset = 0;
gs->writeOffset = 0;
gs->readOffset = 0;
@ -156,19 +157,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
/* Should have a non-SSLv2 record header in gs->hdr. Extract
* the length of the following encrypted data, and then
* read in the rest of the record into gs->inbuf. */
if (ss->ssl3.hs.shortHeaders) {
PRUint16 len = (gs->hdr[0] << 8) | gs->hdr[1];
if (!(len & 0x8000)) {
SSL_DBG(("%d: SSL3[%d]: incorrectly formatted header"));
SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
gs->state = GS_INIT;
PORT_SetError(SSL_ERROR_BAD_MAC_READ);
return SECFailure;
}
gs->remainder = len & ~0x8000;
} else {
gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4];
}
gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4];
} else {
/* Probably an SSLv2 record header. No need to handle any
* security escapes (gs->hdr[0] & 0x40) as we wouldn't get
@ -361,6 +350,9 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
}
}
SSL_TRC(20, ("%d: SSL3[%d]: dtls gathered record type=%d len=%d",
SSL_GETPID(), ss->fd, gs->hdr[0], gs->inbuf.len));
memcpy(gs->inbuf.buf, gs->dtlsPacket.buf + gs->dtlsPacketOffset,
gs->remainder);
gs->inbuf.len = gs->remainder;
@ -394,7 +386,8 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
SSL3Ciphertext cText;
PRBool keepGoing = PR_TRUE;
SSL_TRC(30, ("ssl3_GatherCompleteHandshake"));
SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
SSL_GETPID(), ss->fd));
/* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake,
* which requires the 1stHandshakeLock, which must be acquired before the
@ -405,9 +398,12 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
do {
PRBool handleRecordNow = PR_FALSE;
PRBool processingEarlyData;
ssl_GetSSL3HandshakeLock(ss);
processingEarlyData = ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
/* Without this, we may end up wrongly reporting
* SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the
* peer while we are waiting to be restarted.
@ -493,18 +489,12 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
* If it's a change cipher spec, alert, or handshake message,
* ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
*/
if (ss->ssl3.hs.shortHeaders) {
cText.type = content_application_data;
cText.version = SSL_LIBRARY_VERSION_TLS_1_0;
} else {
cText.type = (SSL3ContentType)ss->gs.hdr[0];
cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
}
cText.type = (SSL3ContentType)ss->gs.hdr[0];
cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
if (IS_DTLS(ss)) {
sslSequenceNumber seq_num;
cText.version = dtls_DTLSVersionToTLSVersion(cText.version);
/* DTLS sequence number */
PORT_Memcpy(&seq_num, &ss->gs.hdr[3], sizeof(seq_num));
cText.seq_num = PR_ntohll(seq_num);
@ -555,12 +545,22 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
} else {
ss->ssl3.hs.canFalseStart = PR_FALSE;
}
} else if (processingEarlyData &&
ss->ssl3.hs.zeroRttState == ssl_0rtt_done &&
!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) {
/* If we were processing early data and we are no longer, then force
* the handshake to block. This ensures that early data is
* delivered to the application before the handshake completes. */
ssl_ReleaseSSL3HandshakeLock(ss);
PORT_SetError(PR_WOULD_BLOCK_ERROR);
return SECWouldBlock;
}
ssl_ReleaseSSL3HandshakeLock(ss);
} while (keepGoing);
/* Service the DTLS timer so that the holddown timer eventually fires. */
if (IS_DTLS(ss)) {
/* Service the DTLS timer so that the post-handshake timers
* fire. */
if (IS_DTLS(ss) && (ss->ssl3.hs.ws == idle_handshake)) {
dtls_CheckTimer(ss);
}
ss->gs.readOffset = 0;

View file

@ -16,13 +16,12 @@ typedef PRUint16 SSL3ProtocolVersion;
/* The TLS 1.3 draft version. Used to avoid negotiating
* between incompatible pre-standard TLS 1.3 drafts.
* TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */
#define TLS_1_3_DRAFT_VERSION 18
#define TLS_1_3_DRAFT_VERSION 23
typedef PRUint16 ssl3CipherSuite;
/* The cipher suites are defined in sslproto.h */
#define MAX_CERT_TYPES 10
#define MAX_COMPRESSION_METHODS 10
#define MAX_MAC_LENGTH 64
#define MAX_PADDING_LENGTH 64
#define MAX_KEY_LENGTH 64
@ -30,7 +29,6 @@ typedef PRUint16 ssl3CipherSuite;
#define SSL3_RANDOM_LENGTH 32
#define SSL3_RECORD_HEADER_LENGTH 5
#define TLS13_RECORD_HEADER_LENGTH_SHORT 2
/* SSL3_RECORD_HEADER_LENGTH + epoch/sequence_number */
#define DTLS_RECORD_HEADER_LENGTH 13
@ -41,47 +39,18 @@ typedef enum {
content_change_cipher_spec = 20,
content_alert = 21,
content_handshake = 22,
content_application_data = 23
content_application_data = 23,
content_alt_handshake = 24,
content_ack = 25
} SSL3ContentType;
typedef struct {
SSL3ContentType type;
SSL3ProtocolVersion version;
PRUint16 length;
SECItem fragment;
} SSL3Plaintext;
typedef struct {
SSL3ContentType type;
SSL3ProtocolVersion version;
PRUint16 length;
SECItem fragment;
} SSL3Compressed;
typedef struct {
SECItem content;
PRUint8 MAC[MAX_MAC_LENGTH];
} SSL3GenericStreamCipher;
typedef struct {
SECItem content;
PRUint8 MAC[MAX_MAC_LENGTH];
PRUint8 padding[MAX_PADDING_LENGTH];
PRUint8 padding_length;
} SSL3GenericBlockCipher;
typedef enum { change_cipher_spec_choice = 1 } SSL3ChangeCipherSpecChoice;
typedef struct {
SSL3ChangeCipherSpecChoice choice;
} SSL3ChangeCipherSpec;
typedef enum { alert_warning = 1,
alert_fatal = 2 } SSL3AlertLevel;
typedef enum {
close_notify = 0,
end_of_early_data = 1, /* TLS 1.3 */
unexpected_message = 10,
bad_record_mac = 20,
decryption_failed_RESERVED = 21, /* do not send; see RFC 5246 */
@ -122,64 +91,13 @@ typedef enum {
no_alert = 256
} SSL3AlertDescription;
typedef struct {
SSL3AlertLevel level;
SSL3AlertDescription description;
} SSL3Alert;
typedef enum {
hello_request = 0,
client_hello = 1,
server_hello = 2,
hello_verify_request = 3,
new_session_ticket = 4,
hello_retry_request = 6,
encrypted_extensions = 8,
certificate = 11,
server_key_exchange = 12,
certificate_request = 13,
server_hello_done = 14,
certificate_verify = 15,
client_key_exchange = 16,
finished = 20,
certificate_status = 22,
next_proto = 67
} SSL3HandshakeType;
typedef struct {
PRUint8 empty;
} SSL3HelloRequest;
typedef struct {
PRUint8 rand[SSL3_RANDOM_LENGTH];
} SSL3Random;
typedef PRUint8 SSL3Random[SSL3_RANDOM_LENGTH];
typedef struct {
PRUint8 id[32];
PRUint8 length;
} SSL3SessionID;
typedef struct {
SSL3ProtocolVersion client_version;
SSL3Random random;
SSL3SessionID session_id;
SECItem cipher_suites;
PRUint8 cm_count;
SSLCompressionMethod compression_methods[MAX_COMPRESSION_METHODS];
} SSL3ClientHello;
typedef struct {
SSL3ProtocolVersion server_version;
SSL3Random random;
SSL3SessionID session_id;
ssl3CipherSuite cipher_suite;
SSLCompressionMethod compression_method;
} SSL3ServerHello;
typedef struct {
SECItem list;
} SSL3Certificate;
/* SSL3SignType moved to ssl.h */
/* The SSL key exchange method used */
@ -201,24 +119,6 @@ typedef enum {
kea_tls13_any,
} SSL3KeyExchangeAlgorithm;
typedef struct {
SECItem modulus;
SECItem exponent;
} SSL3ServerRSAParams;
typedef struct {
SECItem p;
SECItem g;
SECItem Ys;
} SSL3ServerDHParams;
typedef struct {
union {
SSL3ServerDHParams dh;
SSL3ServerRSAParams rsa;
} u;
} SSL3ServerParams;
/* SSL3HashesIndividually contains a combination MD5/SHA1 hash, as used in TLS
* prior to 1.2. */
typedef struct {
@ -235,17 +135,9 @@ typedef struct {
union {
PRUint8 raw[64];
SSL3HashesIndividually s;
unsigned int transcriptLen;
} u;
} SSL3Hashes;
typedef struct {
union {
PRUint8 anonymous;
SSL3Hashes certified;
} u;
} SSL3ServerKeyExchange;
typedef enum {
ct_RSA_sign = 1,
ct_DSS_sign = 2,
@ -256,16 +148,8 @@ typedef enum {
ct_ECDSA_sign = 64,
ct_RSA_fixed_ECDH = 65,
ct_ECDSA_fixed_ECDH = 66
} SSL3ClientCertificateType;
typedef struct {
PRUint8 client_version[2];
PRUint8 random[46];
} SSL3RSAPreMasterSecret;
typedef PRUint8 SSL3MasterSecret[48];
typedef enum {
sender_client = 0x434c4e54,
sender_server = 0x53525652

View file

@ -0,0 +1,94 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* A bloom filter.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "sslbloom.h"
#include "prnetdb.h"
#include "secport.h"
static inline unsigned int
sslBloom_Size(unsigned int bits)
{
return (bits >= 3) ? (1 << (bits - 3)) : 1;
}
SECStatus
sslBloom_Init(sslBloomFilter *filter, unsigned int k, unsigned int bits)
{
PORT_Assert(filter);
PORT_Assert(bits > 0);
PORT_Assert(bits <= sizeof(PRUint32) * 8);
PORT_Assert(k > 0);
filter->filter = PORT_ZNewArray(PRUint8, sslBloom_Size(bits));
if (!filter->filter) {
return SECFailure; /* Error code already set. */
}
filter->k = k;
filter->bits = bits;
return SECSuccess;
}
void
sslBloom_Zero(sslBloomFilter *filter)
{
PORT_Memset(filter->filter, 0, sslBloom_Size(filter->bits));
}
void
sslBloom_Fill(sslBloomFilter *filter)
{
PORT_Memset(filter->filter, 0xff, sslBloom_Size(filter->bits));
}
static PRBool
sslBloom_AddOrCheck(sslBloomFilter *filter, const PRUint8 *hashes, PRBool add)
{
unsigned int iteration;
unsigned int bitIndex;
PRUint32 tmp = 0;
PRUint8 mask;
unsigned int bytes = (filter->bits + 7) / 8;
unsigned int shift = (bytes * 8) - filter->bits;
PRBool found = PR_TRUE;
PORT_Assert(bytes <= sizeof(unsigned int));
for (iteration = 0; iteration < filter->k; ++iteration) {
PORT_Memcpy(((PRUint8 *)&tmp) + (sizeof(tmp) - bytes),
hashes, bytes);
hashes += bytes;
bitIndex = PR_ntohl(tmp) >> shift;
mask = 1 << (bitIndex % 8);
found = found && filter->filter[bitIndex / 8] & mask;
if (add) {
filter->filter[bitIndex / 8] |= mask;
}
}
return found;
}
PRBool
sslBloom_Add(sslBloomFilter *filter, const PRUint8 *hashes)
{
return sslBloom_AddOrCheck(filter, hashes, PR_TRUE);
}
PRBool
sslBloom_Check(sslBloomFilter *filter, const PRUint8 *hashes)
{
return sslBloom_AddOrCheck(filter, hashes, PR_FALSE);
}
void
sslBloom_Destroy(sslBloomFilter *filter)
{
PORT_Free(filter->filter);
PORT_Memset(filter, 0, sizeof(*filter));
}

View file

@ -0,0 +1,32 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* A bloom filter.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __sslbloom_h_
#define __sslbloom_h_
#include "prtypes.h"
#include "seccomon.h"
typedef struct sslBloomFilterStr {
unsigned int k; /* The number of hashes. */
unsigned int bits; /* The number of bits in each hash: bits = log2(m) */
PRUint8 *filter; /* The filter itself. */
} sslBloomFilter;
SECStatus sslBloom_Init(sslBloomFilter *filter, unsigned int k, unsigned int bits);
void sslBloom_Zero(sslBloomFilter *filter);
void sslBloom_Fill(sslBloomFilter *filter);
/* Add the given hashes to the filter. It's the caller's responsibility to
* ensure that there is at least |ceil(k*bits/8)| bytes of data available in
* |hashes|. Returns PR_TRUE if the entry was already present or it was likely
* to be present. */
PRBool sslBloom_Add(sslBloomFilter *filter, const PRUint8 *hashes);
PRBool sslBloom_Check(sslBloomFilter *filter, const PRUint8 *hashes);
void sslBloom_Destroy(sslBloomFilter *filter);
#endif /* __sslbloom_h_ */

View file

@ -46,7 +46,7 @@ ssl_SetupCAListOnce(void *arg)
}
SECStatus
ssl_SetupCAList(sslSocket *ss)
ssl_SetupCAList(const sslSocket *ss)
{
if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_server_ca_list.setup,
&ssl_SetupCAListOnce,
@ -58,11 +58,11 @@ ssl_SetupCAList(sslSocket *ss)
}
SECStatus
ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calen,
SECItem **names, unsigned int *nnames)
ssl_GetCertificateRequestCAs(const sslSocket *ss, unsigned int *calen,
const SECItem **names, unsigned int *nnames)
{
SECItem *name;
CERTDistNames *ca_list;
const SECItem *name;
const CERTDistNames *ca_list;
unsigned int i;
*calen = 0;

View file

@ -0,0 +1,296 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nss.h"
#include "prnetdb.h"
#include "ssl.h"
#include "sslimpl.h"
/* Helper function to encode an unsigned integer into a buffer. */
static void
ssl_EncodeUintX(PRUint8 *to, PRUint64 value, unsigned int bytes)
{
PRUint64 encoded;
PORT_Assert(bytes > 0 && bytes <= sizeof(encoded));
encoded = PR_htonll(value);
PORT_Memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes),
bytes);
}
/* Grow a buffer to hold newLen bytes of data. When used for recv/xmit buffers,
* the caller must hold xmitBufLock or recvBufLock, as appropriate. */
SECStatus
sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
{
if (b->fixed) {
PORT_Assert(newLen <= b->space);
if (newLen > b->space) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return SECSuccess;
}
newLen = PR_MAX(newLen, b->len + 1024);
if (newLen > b->space) {
unsigned char *newBuf;
if (b->buf) {
newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen);
} else {
newBuf = (unsigned char *)PORT_Alloc(newLen);
}
if (!newBuf) {
return SECFailure;
}
b->buf = newBuf;
b->space = newLen;
}
return SECSuccess;
}
SECStatus
sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
{
SECStatus rv = sslBuffer_Grow(b, b->len + len);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
b->len += len;
return SECSuccess;
}
SECStatus
sslBuffer_AppendNumber(sslBuffer *b, PRUint64 v, unsigned int size)
{
SECStatus rv = sslBuffer_Grow(b, b->len + size);
if (rv != SECSuccess) {
return SECFailure;
}
ssl_EncodeUintX(SSL_BUFFER_NEXT(b), v, size);
b->len += size;
return SECSuccess;
}
SECStatus
sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
unsigned int size)
{
PORT_Assert(size <= 4 && size > 0);
if (len >= (1ULL << (8 * size))) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (sslBuffer_Grow(b, b->len + len + size) != SECSuccess) {
return SECFailure;
}
ssl_EncodeUintX(SSL_BUFFER_NEXT(b), len, size);
b->len += size;
PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
b->len += len;
return SECSuccess;
}
SECStatus
sslBuffer_AppendBuffer(sslBuffer *b, const sslBuffer *append)
{
return sslBuffer_Append(b, append->buf, append->len);
}
SECStatus
sslBuffer_AppendBufferVariable(sslBuffer *b, const sslBuffer *append,
unsigned int size)
{
return sslBuffer_AppendVariable(b, append->buf, append->len, size);
}
SECStatus
sslBuffer_Skip(sslBuffer *b, unsigned int size, unsigned int *savedOffset)
{
if (sslBuffer_Grow(b, b->len + size) != SECSuccess) {
return SECFailure;
}
if (savedOffset) {
*savedOffset = b->len;
}
b->len += size;
return SECSuccess;
}
/* A common problem is that a buffer is used to construct a variable length
* structure of unknown length. The length field for that structure is then
* populated afterwards. This function makes this process a little easier.
*
* To use this, before encoding the variable length structure, skip the spot
* where the length would be using sslBuffer_Skip(). After encoding the
* structure, and before encoding anything else, call this function passing the
* value returned from sslBuffer_Skip() as |at| to have the length inserted.
*/
SECStatus
sslBuffer_InsertLength(sslBuffer *b, unsigned int at, unsigned int size)
{
unsigned int len;
PORT_Assert(b->len >= at + size);
PORT_Assert(b->space >= at + size);
len = b->len - (at + size);
PORT_Assert(size <= 4 && size > 0);
if (len >= (1ULL << (8 * size))) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
ssl_EncodeUintX(SSL_BUFFER_BASE(b) + at, len, size);
return SECSuccess;
}
void
sslBuffer_Clear(sslBuffer *b)
{
if (!b->fixed) {
if (b->buf) {
PORT_Free(b->buf);
b->buf = NULL;
}
b->space = 0;
}
b->len = 0;
}
SECStatus
ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, unsigned int size)
{
if (size > item->len) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*buf = item->data;
item->data += size;
item->len -= size;
return SECSuccess;
}
SECStatus
ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, unsigned int size)
{
int i;
if (size > item->len || size > sizeof(*num)) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*num = 0;
for (i = 0; i < size; i++) {
*num = (*num << 8) + item->data[i];
}
item->data += size;
item->len -= size;
return SECSuccess;
}
/**************************************************************************
* Append Handshake functions.
* All these functions set appropriate error codes.
* Most rely on ssl3_AppendHandshake to set the error code.
**************************************************************************/
#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */
#define MIN_SEND_BUF_LENGTH 4000
SECStatus
ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
{
unsigned char *src = (unsigned char *)void_src;
int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); /* protects sendBuf. */
if (!bytes)
return SECSuccess;
if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) {
rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH,
PR_MIN(MAX_SEND_BUF_LENGTH, ss->sec.ci.sendBuf.len + bytes)));
if (rv != SECSuccess)
return SECFailure; /* sslBuffer_Grow sets a memory error code. */
room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
}
PRINT_BUF(60, (ss, "Append to Handshake", (unsigned char *)void_src, bytes));
rv = ssl3_UpdateHandshakeHashes(ss, src, bytes);
if (rv != SECSuccess)
return SECFailure; /* error code set by ssl3_UpdateHandshakeHashes */
while (bytes > room) {
if (room > 0)
PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src,
room);
ss->sec.ci.sendBuf.len += room;
rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
if (rv != SECSuccess) {
return SECFailure; /* error code set by ssl3_FlushHandshake */
}
bytes -= room;
src += room;
room = ss->sec.ci.sendBuf.space;
PORT_Assert(ss->sec.ci.sendBuf.len == 0);
}
PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, bytes);
ss->sec.ci.sendBuf.len += bytes;
return SECSuccess;
}
SECStatus
ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num, unsigned int lenSize)
{
PRUint8 b[sizeof(num)];
SSL_TRC(60, ("%d: number:", SSL_GETPID()));
ssl_EncodeUintX(b, num, lenSize);
return ssl3_AppendHandshake(ss, b, lenSize);
}
SECStatus
ssl3_AppendHandshakeVariable(sslSocket *ss, const PRUint8 *src,
unsigned int bytes, unsigned int lenSize)
{
SECStatus rv;
PORT_Assert((bytes < (1 << 8) && lenSize == 1) ||
(bytes < (1L << 16) && lenSize == 2) ||
(bytes < (1L << 24) && lenSize == 3));
SSL_TRC(60, ("%d: append variable:", SSL_GETPID()));
rv = ssl3_AppendHandshakeNumber(ss, bytes, lenSize);
if (rv != SECSuccess) {
return SECFailure; /* error code set by AppendHandshake. */
}
SSL_TRC(60, ("data:"));
return ssl3_AppendHandshake(ss, src, bytes);
}
SECStatus
ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf)
{
return ssl3_AppendHandshake(ss, buf->buf, buf->len);
}
SECStatus
ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf,
unsigned int lenSize)
{
return ssl3_AppendHandshakeVariable(ss, buf->buf, buf->len, lenSize);
}

View file

@ -0,0 +1,69 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __sslencode_h_
#define __sslencode_h_
/* A buffer object, used for assembling messages. */
typedef struct sslBufferStr {
PRUint8 *buf;
unsigned int len;
unsigned int space;
/* Set to true if the storage for the buffer is fixed, such as a stack
* variable or a view on another buffer. Growing a fixed buffer fails. */
PRBool fixed;
} sslBuffer;
#define SSL_BUFFER_EMPTY \
{ \
NULL, 0, 0, PR_FALSE \
}
#define SSL_BUFFER_FIXED(b, maxlen) \
{ \
b, 0, maxlen, PR_TRUE \
}
#define SSL_BUFFER(b) SSL_BUFFER_FIXED(b, sizeof(b))
#define SSL_BUFFER_BASE(b) ((b)->buf)
#define SSL_BUFFER_LEN(b) ((b)->len)
#define SSL_BUFFER_NEXT(b) ((b)->buf + (b)->len)
#define SSL_BUFFER_SPACE(b) ((b)->space - (b)->len)
SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
SECStatus sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len);
SECStatus sslBuffer_AppendNumber(sslBuffer *b, PRUint64 v, unsigned int size);
SECStatus sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data,
unsigned int len, unsigned int size);
SECStatus sslBuffer_AppendBuffer(sslBuffer *b, const sslBuffer *append);
SECStatus sslBuffer_AppendBufferVariable(sslBuffer *b, const sslBuffer *append,
unsigned int size);
SECStatus sslBuffer_Skip(sslBuffer *b, unsigned int size,
unsigned int *savedOffset);
SECStatus sslBuffer_InsertLength(sslBuffer *b, unsigned int at,
unsigned int size);
void sslBuffer_Clear(sslBuffer *b);
/* All of these functions modify the underlying SECItem, and so should
* be performed on a shallow copy.*/
SECStatus ssl3_ConsumeFromItem(SECItem *item,
PRUint8 **buf, unsigned int size);
SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
PRUint32 *num, unsigned int size);
SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
unsigned int bytes);
SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
SSLHandshakeType t, unsigned int length);
SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num,
unsigned int lenSize);
SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss, const PRUint8 *src,
unsigned int bytes, unsigned int lenSize);
SECStatus ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf);
SECStatus ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf,
unsigned int lenSize);
#endif /* __sslencode_h_ */

View file

@ -234,6 +234,7 @@ typedef enum {
SSL_ERROR_MALFORMED_PRE_SHARED_KEY = (SSL_ERROR_BASE + 147),
SSL_ERROR_MALFORMED_EARLY_DATA = (SSL_ERROR_BASE + 148),
SSL_ERROR_END_OF_EARLY_DATA_ALERT = (SSL_ERROR_BASE + 149),
/* error 149 is obsolete */
SSL_ERROR_MISSING_ALPN_EXTENSION = (SSL_ERROR_BASE + 150),
SSL_ERROR_RX_UNEXPECTED_EXTENSION = (SSL_ERROR_BASE + 151),
SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION = (SSL_ERROR_BASE + 152),
@ -246,6 +247,19 @@ typedef enum {
SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 159),
SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA = (SSL_ERROR_BASE + 160),
SSL_ERROR_TOO_MUCH_EARLY_DATA = (SSL_ERROR_BASE + 161),
SSL_ERROR_RX_UNEXPECTED_END_OF_EARLY_DATA = (SSL_ERROR_BASE + 162),
SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA = (SSL_ERROR_BASE + 163),
SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API = (SSL_ERROR_BASE + 164),
SSL_ERROR_APPLICATION_ABORT = (SSL_ERROR_BASE + 165),
SSL_ERROR_APP_CALLBACK_ERROR = (SSL_ERROR_BASE + 166),
SSL_ERROR_NO_TIMERS_FOUND = (SSL_ERROR_BASE + 167),
SSL_ERROR_MISSING_COOKIE_EXTENSION = (SSL_ERROR_BASE + 168),
SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE = (SSL_ERROR_BASE + 169),
SSL_ERROR_RX_MALFORMED_KEY_UPDATE = (SSL_ERROR_BASE + 170),
SSL_ERROR_TOO_MANY_KEY_UPDATES = (SSL_ERROR_BASE + 171),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */

View file

@ -0,0 +1,358 @@
/*
* This file contains prototypes for experimental SSL functions.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __sslexp_h_
#define __sslexp_h_
#include "ssl.h"
#include "sslerr.h"
SEC_BEGIN_PROTOS
/* The functions in this header file are not guaranteed to remain available in
* future NSS versions. Code that uses these functions needs to safeguard
* against the function not being available. */
#define SSL_EXPERIMENTAL_API(name, arglist, args) \
(SSL_GetExperimentalAPI(name) \
? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \
: SECFailure)
#define SSL_DEPRECATED_EXPERIMENTAL_API \
(PR_SetError(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, 0), SECFailure)
/*
* SSL_GetExtensionSupport() returns whether NSS supports a particular TLS
* extension.
*
* - ssl_ext_none indicates that NSS does not support the extension and
* extension hooks can be installed.
*
* - ssl_ext_native indicates that NSS supports the extension natively, but
* allows an application to override that support and install its own
* extension hooks.
*
* - ssl_ext_native_only indicates that NSS supports the extension natively
* and does not permit custom extension hooks to be installed. These
* extensions are critical to the functioning of NSS.
*/
typedef enum {
ssl_ext_none,
ssl_ext_native,
ssl_ext_native_only
} SSLExtensionSupport;
#define SSL_GetExtensionSupport(extension, support) \
SSL_EXPERIMENTAL_API("SSL_GetExtensionSupport", \
(PRUint16 _extension, \
SSLExtensionSupport * _support), \
(extension, support))
/*
* Custom extension hooks.
*
* The SSL_InstallExtensionHooks() registers two callback functions for use
* with the identified extension type.
*
* Installing extension hooks disables the checks in TLS 1.3 that ensure that
* extensions are only added to the correct messages. The application is
* responsible for ensuring that extensions are only sent with the right message
* or messages.
*
* Installing an extension handler does not disable checks for whether an
* extension can be used in a message that is a response to an extension in
* another message. Extensions in ServerHello, EncryptedExtensions and the
* server Certificate messages are rejected unless the client sends an extension
* in the ClientHello. Similarly, a client Certificate message cannot contain
* extensions that don't appear in a CertificateRequest (in TLS 1.3).
*
* Setting both |writer| and |handler| to NULL removes any existing hooks for
* that extension.
*
* == SSLExtensionWriter
*
* An SSLExtensionWriter function is responsible for constructing the contents
* of an extension. This function is called during the construction of all
* handshake messages where an extension might be included.
*
* - The |fd| argument is the socket file descriptor.
*
* - The |message| argument is the TLS handshake message type. The writer will
* be called for every handshake message that NSS sends. Most extensions
* should only be sent in a subset of messages. NSS doesn’t check that
* extension writers don’t violate protocol rules regarding which message an
* extension can be sent in.
*
* - The |data| argument is a pointer to a buffer that should be written to with
* any data for the extension.
*
* - The |len| argument is an outparam indicating how many bytes were written to
* |data|. The value referenced by |len| is initialized to zero, so an
* extension that is empty does not need to write to this value.
*
* - The |maxLen| indicates the maximum number of bytes that can be written to
* |data|.
*
* - The |arg| argument is the value of the writerArg that was passed during
* installation.
*
* An SSLExtensionWriter function returns PR_TRUE if an extension should be
* written, and PR_FALSE otherwise.
*
* If there is an error, return PR_FALSE; if the error is truly fatal, the
* application can mark the connection as failed. However, recursively calling
* functions that alter the file descriptor in the callback - such as PR_Close()
* - should be avoided.
*
* Note: The ClientHello message can be sent twice in TLS 1.3. An
* SSLExtensionWriter will be called twice with the same arguments in that case;
* NSS does not distinguish between a first and second ClientHello. It is up to
* the application to track this if it needs to act differently each time. In
* most cases the correct behaviour is to provide an identical extension on each
* invocation.
*
* == SSLExtensionHandler
*
* An SSLExtensionHandler function consumes a handshake message. This function
* is called when an extension is present.
*
* - The |fd| argument is the socket file descriptor.
*
* - The |message| argument is the TLS handshake message type. This can be used
* to validate that the extension was included in the correct handshake
* message.
*
* - The |data| argument points to the contents of the extension.
*
* - The |len| argument contains the length of the extension.
*
* - The |alert| argument is an outparam that allows an application to choose
* which alert is sent in the case of a fatal error.
*
* - The |arg| argument is the value of the handlerArg that was passed during
* installation.
*
* An SSLExtensionHandler function returns SECSuccess when the extension is
* process successfully. It can return SECFailure to cause the handshake to
* fail. If the value of alert is written to, NSS will generate a fatal alert
* using the provided alert code. The value of |alert| is otherwise not used.
*/
typedef PRBool(PR_CALLBACK *SSLExtensionWriter)(
PRFileDesc *fd, SSLHandshakeType message,
PRUint8 *data, unsigned int *len, unsigned int maxLen, void *arg);
typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
PRFileDesc *fd, SSLHandshakeType message,
const PRUint8 *data, unsigned int len,
SSLAlertDescription *alert, void *arg);
#define SSL_InstallExtensionHooks(fd, extension, writer, writerArg, \
handler, handlerArg) \
SSL_EXPERIMENTAL_API("SSL_InstallExtensionHooks", \
(PRFileDesc * _fd, PRUint16 _extension, \
SSLExtensionWriter _writer, void *_writerArg, \
SSLExtensionHandler _handler, void *_handlerArg), \
(fd, extension, writer, writerArg, \
handler, handlerArg))
/*
* Setup the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers.
*
* To use 0-RTT on a server, you must call this function. Failing to call this
* function will result in all 0-RTT being rejected. Connections will complete,
* but early data will be rejected.
*
* NSS uses a Bloom filter to track the ClientHello messages that it receives
* (specifically, it uses the PSK binder). This function initializes a pair of
* Bloom filters. The two filters are alternated over time, with new
* ClientHello messages recorded in the current filter and, if they are not
* already present, being checked against the previous filter. If the
* ClientHello is found, then early data is rejected, but the handshake is
* allowed to proceed.
*
* The false-positive probability of Bloom filters means that some valid
* handshakes will be marked as potential replays. Early data will be rejected
* for a false positive. To minimize this and to allow a trade-off of space
* against accuracy, the size of the Bloom filter can be set by this function.
*
* The first tuning parameter to consider is |window|, which determines the
* window over which ClientHello messages will be tracked. This also causes
* early data to be rejected if a ClientHello contains a ticket age parameter
* that is outside of this window (see Section 4.2.10.4 of
* draft-ietf-tls-tls13-20 for details). Set |window| to account for any
* potential sources of clock error. |window| is the entire width of the
* window, which is symmetrical. Therefore to allow 5 seconds of clock error in
* both directions, set the value to 10 seconds (i.e., 10 * PR_USEC_PER_SEC).
*
* After calling this function, early data will be rejected until |window|
* elapses. This prevents replay across crashes and restarts. Only call this
* function once to avoid inadvertently disabling 0-RTT (use PR_CallOnce() to
* avoid this problem).
*
* The primary tuning parameter is |bits| which determines the amount of memory
* allocated to each Bloom filter. NSS will allocate two Bloom filters, each
* |2^(bits - 3)| octets in size. The value of |bits| is primarily driven by
* the number of connections that are expected in any time window. Note that
* this needs to account for there being two filters both of which have
* (presumably) independent false positive rates. The following formulae can be
* used to find a value of |bits| and |k| given a chosen false positive
* probability |p| and the number of requests expected in a given window |n|:
*
* bits = log2(n) + log2(-ln(1 - sqrt(1 - p))) + 1.0575327458897952
* k = -log2(p)
*
* ... where log2 and ln are base 2 and e logarithms respectively. For a target
* false positive rate of 1% and 1000 handshake attempts, this produces bits=14
* and k=7. This results in two Bloom filters that are 2kB each in size. Note
* that rounding |k| and |bits| up causes the false positive probability for
* these values to be a much lower 0.123%.
*
* IMPORTANT: This anti-replay scheme has several weaknesses. See the TLS 1.3
* specification for the details of the generic problems with this technique.
*
* In addition to the generic anti-replay weaknesses, the state that the server
* maintains is in local memory only. Servers that operate in a cluster, even
* those that use shared memory for tickets, will not share anti-replay state.
* Early data can be replayed at least once with every server instance that will
* accept tickets that are encrypted with the same key.
*/
#define SSL_SetupAntiReplay(window, k, bits) \
SSL_EXPERIMENTAL_API("SSL_SetupAntiReplay", \
(PRTime _window, unsigned int _k, unsigned int _bits), \
(window, k, bits))
/*
* This function allows a server application to generate a session ticket that
* will embed the provided token.
*
* This function will cause a NewSessionTicket message to be sent by a server.
* This happens even if SSL_ENABLE_SESSION_TICKETS is disabled. This allows a
* server to suppress the usually automatic generation of a session ticket at
* the completion of the handshake - which do not include any token - and to
* control when session tickets are transmitted.
*
* This function will fail unless the socket has an active TLS 1.3 session.
* Earlier versions of TLS do not support the spontaneous sending of the
* NewSessionTicket message.
*/
#define SSL_SendSessionTicket(fd, appToken, appTokenLen) \
SSL_EXPERIMENTAL_API("SSL_SendSessionTicket", \
(PRFileDesc * _fd, const PRUint8 *_appToken, \
unsigned int _appTokenLen), \
(fd, appToken, appTokenLen))
/*
* A stateless retry handler gives an application some control over NSS handling
* of ClientHello messages.
*
* SSL_HelloRetryRequestCallback() installs a callback that allows an
* application to control how NSS sends HelloRetryRequest messages. This
* handler is only used on servers and will only be called if the server selects
* TLS 1.3. Support for older TLS versions could be added in other releases.
*
* The SSLHelloRetryRequestCallback is invoked during the processing of a
* TLS 1.3 ClientHello message. It takes the following arguments:
*
* - |firstHello| indicates if the NSS believes that this is an initial
* ClientHello. An initial ClientHello will never include a cookie extension,
* though it may contain a session ticket.
*
* - |clientToken| includes a token previously provided by the application. If
* |clientTokenLen| is 0, then |clientToken| may be NULL.
*
* - If |firstHello| is PR_FALSE, the value that was provided in the
* |retryToken| outparam of previous invocations of this callback will be
* present here.
*
* - If |firstHello| is PR_TRUE, and the handshake is resuming a session, then
* this will contain any value that was passed in the |token| parameter of
* SSL_SendNewSessionTicket() method (see below). If this is not resuming a
* session, then the token will be empty (and this value could be NULL).
*
* - |clientTokenLen| is the length of |clientToken|.
*
* - |retryToken| is an item that callback can write to. This provides NSS with
* a token. This token is encrypted and integrity protected and embedded in
* the cookie extension of a HelloRetryRequest. The value of this field is
* only used if the handler returns ssl_stateless_retry_check. NSS allocates
* space for this value.
*
* - |retryTokenLen| is an outparam for the length of the token. If this value
* is not set, or set to 0, an empty token will be sent.
*
* - |retryTokenMax| is the size of the space allocated for retryToken. An
* application cannot write more than this many bytes to retryToken.
*
* - |arg| is the same value that was passed to
* SSL_InstallStatelessRetryHandler().
*
* The handler can validate any the value of |clientToken|, query the socket
* status (using SSL_GetPreliminaryChannelInfo() for example) and decide how to
* proceed:
*
* - Returning ssl_hello_retry_fail causes the handshake to fail. This might be
* used if the token is invalid or the application wishes to abort the
* handshake.
*
* - Returning ssl_hello_retry_accept causes the handshake to proceed.
*
* - Returning ssl_hello_retry_request causes NSS to send a HelloRetryRequest
* message and request a second ClientHello. NSS generates a cookie extension
* and embeds the value of |retryToken|. The value of |retryToken| value may
* be left empty if the application does not require any additional context to
* validate a second ClientHello attempt. This return code cannot be used to
* reject a second ClientHello (i.e., when firstHello is PR_FALSE); NSS will
* abort the handshake if this value is returned from a second call.
*
* An application that chooses to perform a stateless retry can discard the
* server socket. All necessary state to continue the TLS handshake will be
* included in the cookie extension. This makes it possible to use a new socket
* to handle the remainder of the handshake. The existing socket can be safely
* discarded.
*
* If the same socket is retained, the information in the cookie will be checked
* for consistency against the existing state of the socket. Any discrepancy
* will result in the connection being closed.
*
* Tokens should be kept as small as possible. NSS sets a limit on the size of
* tokens, which it passes in |retryTokenMax|. Depending on circumstances,
* observing a smaller limit might be desirable or even necessary. For
* instance, having HelloRetryRequest and ClientHello fit in a single packet has
* significant performance benefits.
*/
typedef enum {
ssl_hello_retry_fail,
ssl_hello_retry_accept,
ssl_hello_retry_request
} SSLHelloRetryRequestAction;
typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
PRBool firstHello, const PRUint8 *clientToken, unsigned int clientTokenLen,
PRUint8 *retryToken, unsigned int *retryTokenLen, unsigned int retryTokMax,
void *arg);
#define SSL_HelloRetryRequestCallback(fd, cb, arg) \
SSL_EXPERIMENTAL_API("SSL_HelloRetryRequestCallback", \
(PRFileDesc * _fd, \
SSLHelloRetryRequestCallback _cb, void *_arg), \
(fd, cb, arg))
/* Update traffic keys (TLS 1.3 only).
*
* The |requestUpdate| flag determines whether to request an update from the
* remote peer.
*/
#define SSL_KeyUpdate(fd, requestUpdate) \
SSL_EXPERIMENTAL_API("SSL_KeyUpdate", \
(PRFileDesc * _fd, PRBool _requestUpdate), \
(fd, requestUpdate))
#define SSL_UseAltServerHelloType(fd, enable) \
SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS
#endif /* __sslexp_h_ */

View file

@ -19,6 +19,7 @@
#include "secport.h"
#include "secerr.h"
#include "sslerr.h"
#include "sslexp.h"
#include "ssl3prot.h"
#include "hasht.h"
#include "nssilock.h"
@ -34,36 +35,11 @@
#include "sslt.h" /* for some formerly private types, now public */
typedef struct sslSocketStr sslSocket;
typedef struct ssl3CipherSpecStr ssl3CipherSpec;
typedef struct sslNamedGroupDefStr sslNamedGroupDef;
#include "sslencode.h"
#include "sslexp.h"
#include "ssl3ext.h"
/* to make some of these old enums public without namespace pollution,
** it was necessary to prepend ssl_ to the names.
** These #defines preserve compatibility with the old code here in libssl.
*/
typedef SSLMACAlgorithm SSL3MACAlgorithm;
#define calg_null ssl_calg_null
#define calg_rc4 ssl_calg_rc4
#define calg_rc2 ssl_calg_rc2
#define calg_des ssl_calg_des
#define calg_3des ssl_calg_3des
#define calg_idea ssl_calg_idea
#define calg_fortezza ssl_calg_fortezza /* deprecated, must preserve */
#define calg_aes ssl_calg_aes
#define calg_camellia ssl_calg_camellia
#define calg_seed ssl_calg_seed
#define calg_aes_gcm ssl_calg_aes_gcm
#define calg_chacha20 ssl_calg_chacha20
#define mac_null ssl_mac_null
#define mac_md5 ssl_mac_md5
#define mac_sha ssl_mac_sha
#define hmac_md5 ssl_hmac_md5
#define hmac_sha ssl_hmac_sha
#define hmac_sha256 ssl_hmac_sha256
#define hmac_sha384 ssl_hmac_sha384
#define mac_aead ssl_mac_aead
#include "sslspec.h"
#if defined(DEBUG) || defined(TRACE)
#ifdef __cplusplus
@ -160,7 +136,7 @@ typedef enum {
ticket_allow_psk_sign_auth = 16
} TLS13SessionTicketFlags;
typedef struct {
struct sslNamedGroupDefStr {
/* The name is the value that is encoded on the wire in TLS. */
SSLNamedGroup name;
/* The number of bits in the group. */
@ -172,9 +148,8 @@ typedef struct {
SECOidTag oidTag;
/* Assume that the group is always supported. */
PRBool assumeSupported;
} sslNamedGroupDef;
};
typedef struct sslBufferStr sslBuffer;
typedef struct sslConnectInfoStr sslConnectInfo;
typedef struct sslGatherStr sslGather;
typedef struct sslSecurityInfoStr sslSecurityInfo;
@ -183,8 +158,6 @@ typedef struct sslSocketOpsStr sslSocketOps;
typedef struct ssl3StateStr ssl3State;
typedef struct ssl3CertNodeStr ssl3CertNode;
typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
typedef struct ssl3MACDefStr ssl3MACDef;
typedef struct sslKeyPairStr sslKeyPair;
typedef struct ssl3DHParamsStr ssl3DHParams;
@ -201,9 +174,6 @@ typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
unsigned char *sid,
unsigned int sidLen,
CERTCertDBHandle *dbHandle);
typedef void (*sslCipherSpecChangedFunc)(void *arg,
PRBool sending,
ssl3CipherSpec *newSpec);
/* Socket ops */
struct sslSocketOpsStr {
@ -229,19 +199,8 @@ 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.
*/
@ -282,7 +241,7 @@ typedef struct sslOptionsStr {
unsigned int detectRollBack : 1;
unsigned int noLocks : 1;
unsigned int enableSessionTickets : 1;
unsigned int enableDeflate : 1;
unsigned int enableDeflate : 1; /* Deprecated. */
unsigned int enableRenegotiation : 2;
unsigned int requireSafeNegotiation : 1;
unsigned int enableFalseStart : 1;
@ -297,7 +256,7 @@ typedef struct sslOptionsStr {
unsigned int enableSignedCertTimestamps : 1;
unsigned int requireDHENamedGroups : 1;
unsigned int enable0RttData : 1;
unsigned int enableShortHeaders : 1;
unsigned int enableTls13CompatMode : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@ -382,136 +341,13 @@ struct sslGatherStr {
#define GS_HEADER 1
#define GS_DATA 2
/*
** ssl3State and CipherSpec structs
*/
/* The SSL bulk cipher definition */
typedef enum {
cipher_null,
cipher_rc4,
cipher_des,
cipher_3des,
cipher_aes_128,
cipher_aes_256,
cipher_camellia_128,
cipher_camellia_256,
cipher_seed,
cipher_aes_128_gcm,
cipher_aes_256_gcm,
cipher_chacha20,
cipher_missing /* reserved for no such supported cipher */
/* This enum must match ssl3_cipherName[] in ssl3con.c. */
} SSL3BulkCipher;
typedef enum { type_stream,
type_block,
type_aead } CipherType;
#define MAX_IV_LENGTH 24
typedef PRUint64 sslSequenceNumber;
typedef PRUint16 DTLSEpoch;
typedef void (*DTLSTimerCb)(sslSocket *);
typedef struct {
PRUint8 wrapped_master_secret[48];
PRUint16 wrapped_master_secret_len;
PRUint8 msIsWrapped;
PRUint8 resumable;
PRUint8 extendedMasterSecretUsed;
} ssl3SidKeys; /* 52 bytes */
typedef struct {
PK11SymKey *write_key;
PK11SymKey *write_mac_key;
PK11Context *write_mac_context;
SECItem write_key_item;
SECItem write_iv_item;
SECItem write_mac_key_item;
PRUint8 write_iv[MAX_IV_LENGTH];
} ssl3KeyMaterial;
typedef SECStatus (*SSLCipher)(void *context,
unsigned char *out,
int *outlen,
int maxout,
const unsigned char *in,
int inlen);
typedef SECStatus (*SSLAEADCipher)(
ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
int *outlen,
int maxout,
const unsigned char *in,
int inlen,
const unsigned char *additionalData,
int additionalDataLen);
typedef SECStatus (*SSLCompressor)(void *context,
unsigned char *out,
int *outlen,
int maxout,
const unsigned char *in,
int inlen);
typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
/* The DTLS anti-replay window in number of packets. Defined here because we
* need it in the cipher spec. Note that this is a ring buffer but left and
* right represent the true window, with modular arithmetic used to map them
* onto the buffer.
*/
#define DTLS_RECVD_RECORDS_WINDOW 1024
#define RECORD_SEQ_MAX ((1ULL << 48) - 1)
PR_STATIC_ASSERT(DTLS_RECVD_RECORDS_WINDOW % 8 == 0);
typedef struct DTLSRecvdRecordsStr {
unsigned char data[DTLS_RECVD_RECORDS_WINDOW / 8];
sslSequenceNumber left;
sslSequenceNumber right;
} DTLSRecvdRecords;
/*
** These are the "specs" in the "ssl3" struct.
** Access to the pointers to these specs, and all the specs' contents
** (direct and indirect) is protected by the reader/writer lock ss->specLock.
*/
struct ssl3CipherSpecStr {
PRCList link;
const ssl3BulkCipherDef *cipher_def;
const ssl3MACDef *mac_def;
SSLCompressionMethod compression_method;
int mac_size;
SSLCipher encode;
SSLCipher decode;
SSLAEADCipher aead;
void *encodeContext;
void *decodeContext;
SSLCompressor compressor; /* Don't name these fields compress */
SSLCompressor decompressor; /* and uncompress because zconf.h */
/* may define them as macros. */
SSLDestroy destroyCompressContext;
void *compressContext;
SSLDestroy destroyDecompressContext;
void *decompressContext;
PK11SymKey *master_secret;
sslSequenceNumber write_seq_num;
sslSequenceNumber read_seq_num;
SSL3ProtocolVersion version;
ssl3KeyMaterial client;
ssl3KeyMaterial server;
SECItem msItem;
DTLSEpoch epoch;
DTLSRecvdRecords recvdRecords;
/* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
* will be zero for everything but 0-RTT. */
PRUint32 earlyDataRemaining;
PRUint8 refCt;
const char *phase;
};
typedef enum { never_cached,
in_client_cache,
in_server_cache,
@ -527,7 +363,7 @@ struct sslSessionIDStr {
sslSessionID *next; /* chain used for client sockets, only */
Cached cached;
int references;
PRUint32 lastAccessTime; /* seconds since Jan 1, 1970 */
PRTime lastAccessTime;
/* The rest of the members, except for the members of u.ssl3.locked, may
* be modified only when the sid is not in any cache.
@ -545,13 +381,15 @@ struct sslSessionIDStr {
SSL3ProtocolVersion version;
PRUint32 creationTime; /* seconds since Jan 1, 1970 */
PRUint32 expirationTime; /* seconds since Jan 1, 1970 */
PRTime creationTime;
PRTime expirationTime;
SSLAuthType authType;
PRUint32 authKeyBits;
SSLKEAType keaType;
PRUint32 keaKeyBits;
SSLNamedGroup keaGroup;
SSLSignatureScheme sigScheme;
union {
struct {
@ -560,7 +398,6 @@ struct sslSessionIDStr {
PRUint8 sessionID[SSL3_SESSIONID_BYTES];
ssl3CipherSuite cipherSuite;
SSLCompressionMethod compression;
int policy;
ssl3SidKeys keys;
/* mechanism used to wrap master secret */
@ -627,13 +464,13 @@ struct sslSessionIDStr {
} u;
};
typedef struct ssl3CipherSuiteDefStr {
struct ssl3CipherSuiteDefStr {
ssl3CipherSuite cipher_suite;
SSL3BulkCipher bulk_cipher_alg;
SSL3MACAlgorithm mac_alg;
SSL3KeyExchangeAlgorithm key_exchange_alg;
SSLHashType prf_hash;
} ssl3CipherSuiteDef;
};
/*
** There are tables of these, all const.
@ -656,37 +493,6 @@ typedef struct {
SECOidTag oid;
} ssl3KEADef;
/*
** There are tables of these, all const.
*/
struct ssl3BulkCipherDefStr {
SSL3BulkCipher cipher;
SSLCipherAlgorithm calg;
unsigned int key_size;
unsigned int secret_key_size;
CipherType type;
unsigned int iv_size;
unsigned int block_size;
unsigned int tag_size; /* for AEAD ciphers. */
unsigned int explicit_nonce_size; /* for AEAD ciphers. */
SECOidTag oid;
const char *short_name;
/* The maximum number of records that can be sent/received with the same
* symmetric key before the connection will be terminated. */
PRUint64 max_records;
};
/*
** There are tables of these, all const.
*/
struct ssl3MACDefStr {
SSL3MACAlgorithm mac;
CK_MECHANISM_TYPE mmech;
int pad_size;
int mac_size;
SECOidTag oid;
};
typedef enum {
ssl_0rtt_none, /* 0-RTT not present */
ssl_0rtt_sent, /* 0-RTT sent (no decision yet) */
@ -704,6 +510,7 @@ typedef enum {
typedef enum {
idle_handshake,
wait_client_hello,
wait_end_of_early_data,
wait_client_cert,
wait_client_key,
wait_cert_verify,
@ -760,14 +567,15 @@ typedef enum {
handshake_hash_record
} SSL3HandshakeHashType;
/* This holds state for TLS 1.3 CertificateRequest handling. */
typedef struct TLS13CertificateRequestStr {
PLArenaPool *arena;
SECItem context;
SSLSignatureScheme *signatureSchemes;
unsigned int signatureSchemeCount;
CERTDistNames ca_list;
} TLS13CertificateRequest;
// A DTLS Timer.
typedef void (*DTLSTimerCb)(sslSocket *);
typedef struct {
const char *label;
DTLSTimerCb cb;
PRIntervalTime started;
PRUint32 timeout;
} dtlsTimer;
/*
** This is the "hs" member of the "ssl3" struct.
@ -791,13 +599,12 @@ typedef struct SSL3HandshakeStateStr {
const ssl3KEADef *kea_def;
ssl3CipherSuite cipher_suite;
const ssl3CipherSuiteDef *suite_def;
SSLCompressionMethod compression;
sslBuffer msg_body; /* protected by recvBufLock */
/* partial handshake message from record layer */
unsigned int header_bytes;
/* number of bytes consumed from handshake */
/* message for message type and header length */
SSL3HandshakeType msg_type;
SSLHandshakeType msg_type;
unsigned long msg_len;
PRBool isResuming; /* we are resuming (not used in TLS 1.3) */
PRBool sendingSCSV; /* instead of empty RI */
@ -834,25 +641,25 @@ typedef struct SSL3HandshakeStateStr {
PRCList remoteExtensions; /* Parsed incoming extensions */
/* This group of values is used for DTLS */
PRUint16 sendMessageSeq; /* The sending message sequence
PRUint16 sendMessageSeq; /* The sending message sequence
* number */
PRCList lastMessageFlight; /* The last message flight we
PRCList lastMessageFlight; /* The last message flight we
* sent */
PRUint16 maxMessageSent; /* The largest message we sent */
PRUint16 recvMessageSeq; /* The receiving message sequence
PRUint16 maxMessageSent; /* The largest message we sent */
PRUint16 recvMessageSeq; /* The receiving message sequence
* number */
sslBuffer recvdFragments; /* The fragments we have received in
sslBuffer recvdFragments; /* The fragments we have received in
* a bitmask */
PRInt32 recvdHighWater; /* The high water mark for fragments
PRInt32 recvdHighWater; /* The high water mark for fragments
* received. -1 means no reassembly
* in progress. */
SECItem cookie; /* The Hello(Retry|Verify)Request cookie. */
PRIntervalTime rtTimerStarted; /* When the timer was started */
DTLSTimerCb rtTimerCb; /* The function to call on expiry */
PRUint32 rtTimeoutMs; /* The length of the current timeout
* used for backoff (in ms) */
PRUint32 rtRetries; /* The retry counter */
SECItem srvVirtName; /* for server: name that was negotiated
SECItem cookie; /* The Hello(Retry|Verify)Request cookie. */
dtlsTimer timers[3]; /* Holder for timers. */
dtlsTimer *rtTimer; /* Retransmit timer. */
dtlsTimer *ackTimer; /* Ack timer (DTLS 1.3 only). */
dtlsTimer *hdTimer; /* Read cipher holddown timer (DLTS 1.3 only) */
PRUint32 rtRetries; /* The retry counter */
SECItem srvVirtName; /* for server: name that was negotiated
* with a client. For client - is
* always set to NULL.*/
@ -869,22 +676,37 @@ typedef struct SSL3HandshakeStateStr {
PK11SymKey *serverTrafficSecret; /* traffic keys */
PK11SymKey *earlyExporterSecret; /* for 0-RTT exporters */
PK11SymKey *exporterSecret; /* for exporters */
/* The certificate request from the server. */
TLS13CertificateRequest *certificateRequest;
PRCList cipherSpecs; /* The cipher specs in the sequence they
* will be applied. */
sslZeroRttState zeroRttState; /* Are we doing a 0-RTT handshake? */
sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */
ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */
PRCList bufferedEarlyData; /* Buffered TLS 1.3 early data
* on server.*/
PRBool helloRetry; /* True if HelloRetryRequest has been sent
* or received. */
ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def
* we use for TLS 1.3 */
PRBool shortHeaders; /* Assigned if we are doing short headers. */
PRCList cipherSpecs; /* The cipher specs in the sequence they
* will be applied. */
sslZeroRttState zeroRttState; /* Are we doing a 0-RTT handshake? */
sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */
ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */
PRCList bufferedEarlyData; /* Buffered TLS 1.3 early data
* on server.*/
PRBool helloRetry; /* True if HelloRetryRequest has been sent
* or received. */
PRBool receivedCcs; /* A server received ChangeCipherSpec
* before the handshake started. */
PRBool clientCertRequested; /* True if CertificateRequest received. */
ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def
* we use for TLS 1.3 */
PRTime serverHelloTime; /* Time the ServerHello flight was sent. */
PRUint16 ticketNonce; /* A counter we use for tickets. */
SECItem fakeSid; /* ... (server) the SID the client used. */
PRBool endOfFlight; /* Processed a full flight (DTLS 1.3). */
/* The following lists contain DTLSHandshakeRecordEntry */
PRCList dtlsSentHandshake; /* Used to map records to handshake fragments. */
PRCList dtlsRcvdHandshake; /* Handshake records we have received
* used to generate ACKs. */
} SSL3HandshakeState;
#define SSL_ASSERT_HASHES_EMPTY(ss) \
do { \
PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown); \
PORT_Assert(ss->ssl3.hs.messages.len == 0); \
} while (0)
/*
** This is the "ssl3" struct, as in "ss->ssl3".
** note:
@ -904,6 +726,10 @@ struct ssl3StateStr {
ssl3CipherSpec *cwSpec; /* current write spec. */
ssl3CipherSpec *pwSpec; /* pending write spec. */
/* This is true after the peer requests a key update; false after a key
* update is initiated locally. */
PRBool peerRequestedKeyUpdate;
/* Internal callback for when we do a cipher suite change. Used for
* debugging in TLS 1.3. This can only be set by non-public functions. */
sslCipherSpecChangedFunc changedCipherSpecFunc;
@ -924,9 +750,7 @@ struct ssl3StateStr {
/* chain while we are trying to validate it. */
CERTDistNames *ca_list;
/* used by server. trusted CAs for this socket. */
PRBool initialized;
SSL3HandshakeState hs;
ssl3CipherSpec specs[2]; /* one is current, one is pending. */
PRUint16 mtu; /* Our estimate of the MTU */
@ -995,11 +819,12 @@ typedef struct SessionTicketStr {
PRBool valid;
SSL3ProtocolVersion ssl_version;
ssl3CipherSuite cipher_suite;
SSLCompressionMethod compression_method;
SSLAuthType authType;
PRUint32 authKeyBits;
SSLKEAType keaType;
PRUint32 keaKeyBits;
SSLNamedGroup originalKeaGroup;
SSLSignatureScheme signatureScheme;
const sslNamedGroupDef *namedCurve; /* For certificate lookup. */
/*
@ -1012,11 +837,13 @@ typedef struct SessionTicketStr {
PRBool extendedMasterSecretUsed;
ClientAuthenticationType client_auth_type;
SECItem peer_cert;
PRUint32 timestamp;
PRTime timestamp;
PRUint32 flags;
SECItem srvName; /* negotiated server name */
SECItem alpnSelection;
PRUint32 maxEarlyData;
PRUint32 ticketAgeBaseline;
SECItem applicationToken;
} SessionTicket;
/*
@ -1066,6 +893,7 @@ struct sslSecurityInfoStr {
SSLKEAType keaType;
PRUint32 keaKeyBits;
const sslNamedGroupDef *keaGroup;
const sslNamedGroupDef *originalKeaGroup;
/* The selected certificate (for servers only). */
const sslServerCert *serverCert;
@ -1151,6 +979,9 @@ struct sslSocketStr {
void *pkcs11PinArg;
SSLNextProtoCallback nextProtoCallback;
void *nextProtoArg;
SSLHelloRetryRequestCallback hrrCallback;
void *hrrCallbackArg;
PRCList extensionHooks;
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
@ -1241,6 +1072,7 @@ extern char ssl_debug;
extern char ssl_trace;
extern FILE *ssl_trace_iob;
extern FILE *ssl_keylog_iob;
extern PZLock *ssl_keylog_lock;
extern PRUint32 ssl3_sid_timeout;
extern PRUint32 ssl_ticket_lifetime;
extern PRUint32 ssl_max_early_data_size;
@ -1331,14 +1163,10 @@ extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
extern int ssl_Do1stHandshake(sslSocket *ss);
extern SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
extern SECStatus sslBuffer_Append(sslBuffer *b, const void *data,
unsigned int len);
extern void sslBuffer_Clear(sslBuffer *b);
extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
extern void ssl3_InitCipherSpec(ssl3CipherSpec *spec);
extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
PRBool derive);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
const char *peerID, const char *urlSvrName);
@ -1363,11 +1191,20 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
extern SECStatus ssl3_ConstrainRangeByPolicy(void);
extern void ssl3_InitState(sslSocket *ss);
extern SECStatus ssl3_InitState(sslSocket *ss);
extern SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
int maxOutputLen, const unsigned char *input,
int inputLen);
extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
const unsigned char *b,
unsigned int l);
SECStatus
ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
PRUint32 dtlsSeq,
const PRUint8 *b, PRUint32 length);
SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
const PRUint8 *b, PRUint32 length);
/* Returns PR_TRUE if we are still waiting for the server to complete its
* response to our client second round. Once we've received the Finished from
@ -1380,21 +1217,14 @@ extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
const PRUint8 *pIn, PRInt32 nIn,
PRInt32 flags);
#ifdef NSS_SSL_ENABLE_ZLIB
/*
* The DEFLATE algorithm can result in an expansion of 0.1% + 12 bytes. For a
* maximum TLS record payload of 2**14 bytes, that's 29 bytes.
*/
#define SSL3_COMPRESSION_MAX_EXPANSION 29
#else /* !NSS_SSL_ENABLE_ZLIB */
#define SSL3_COMPRESSION_MAX_EXPANSION 0
#endif
/* Clear any PRCList, optionally calling f on the value. */
void ssl_ClearPRCList(PRCList *list, void (*f)(void *));
/*
* make sure there is room in the write buffer for padding and
* other compression and cryptographic expansions.
* Make sure there is room in the write buffer for padding and
* cryptographic expansions.
*/
#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION
#define SSL3_BUFFER_FUDGE 100
#define SSL_LOCK_READER(ss) \
if (ss->recvLock) \
@ -1547,7 +1377,7 @@ extern SECStatus ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error);
* for dealing with SSL 3.0 clients sending SSL 2.0 format hellos
*/
extern SECStatus ssl3_HandleV2ClientHello(
sslSocket *ss, unsigned char *buffer, int length, PRUint8 padding);
sslSocket *ss, unsigned char *buffer, unsigned int length, PRUint8 padding);
SECStatus ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type);
@ -1583,7 +1413,7 @@ extern PRBool ssl_HaveEphemeralKeyPair(const sslSocket *ss,
const sslNamedGroupDef *groupDef);
extern void ssl_FreeEphemeralKeyPairs(sslSocket *ss);
extern SECStatus ssl_AppendPaddedDHKeyShare(const sslSocket *ss,
extern SECStatus ssl_AppendPaddedDHKeyShare(sslBuffer *buf,
const SECKEYPublicKey *pubKey,
PRBool appendLength);
extern const ssl3DHParams *ssl_GetDHEParams(const sslNamedGroupDef *groupDef);
@ -1645,6 +1475,10 @@ extern SECStatus ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b,
extern SECStatus ssl3_NegotiateVersion(sslSocket *ss,
SSL3ProtocolVersion peerVersion,
PRBool allowLargerPeerVersion);
extern SECStatus ssl_ClientSetCipherSuite(sslSocket *ss,
SSL3ProtocolVersion version,
ssl3CipherSuite suite,
PRBool initHashes);
extern SECStatus ssl_GetPeerInfo(sslSocket *ss);
@ -1660,23 +1494,11 @@ extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss);
extern SECStatus ssl_ImportECDHKeyShare(
sslSocket *ss, SECKEYPublicKey *peerKey,
PRUint8 *b, PRUint32 length, const sslNamedGroupDef *curve);
SECStatus tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss,
const SECKEYPublicKey *pubKey);
extern SECStatus ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
PRUint8 *hashBuf,
unsigned int bufLen,
SSL3Hashes *hashes);
extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName);
extern SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms);
extern SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
PRInt32 bytes);
extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
SSL3HandshakeType t, PRUint32 length);
extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num,
PRInt32 lenSize);
extern SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss,
const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize);
extern SECStatus ssl3_AppendSignatureAndHashAlgorithm(
sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash);
extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes,
@ -1684,11 +1506,12 @@ extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes,
extern SECStatus ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num,
PRUint32 bytes, PRUint8 **b,
PRUint32 *length);
extern SECStatus ssl3_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *num,
PRUint32 bytes, PRUint8 **b,
PRUint32 *length);
extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
PRUint32 bytes, PRUint8 **b,
PRUint32 *length);
extern PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes,
PRUint8 *to);
extern PRBool ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme);
extern SECStatus ssl_CheckSignatureSchemeConsistency(
sslSocket *ss, SSLSignatureScheme scheme, CERTCertificate *cert);
@ -1703,16 +1526,20 @@ extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
SECKEYPrivateKey *key, SECItem *buf);
extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
SSL3Hashes *hash, SECItem *buf);
extern SECStatus ssl3_CacheWrappedMasterSecret(
sslSocket *ss, sslSessionID *sid, ssl3CipherSpec *spec);
extern SECStatus ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
PK11SymKey *secret);
extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData);
/* Hello Extension related routines. */
extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
/*in/out*/ NewSessionTicket *session_ticket);
SECStatus ssl3_EncodeSessionTicket(sslSocket *ss,
const NewSessionTicket *ticket_input,
SECItem *ticket_data);
const NewSessionTicket *ticket,
const PRUint8 *appToken,
unsigned int appTokenLen,
PK11SymKey *secret, SECItem *ticket_data);
SECStatus SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token,
unsigned int tokenLen);
SECStatus ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair);
SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName,
@ -1728,7 +1555,7 @@ extern void ssl_FreePRSocket(PRFileDesc *fd);
/* Internal config function so SSL3 can initialize the present state of
* various ciphers */
extern int ssl3_config_match_init(sslSocket *);
extern unsigned int ssl3_config_match_init(sslSocket *);
/* calls for accessing wrapping keys across processes. */
extern SECStatus
@ -1758,44 +1585,11 @@ extern SECStatus ssl_InitSessionCacheLocks(PRBool lazyInit);
extern SECStatus ssl_FreeSessionCacheLocks(void);
/**************** DTLS-specific functions **************/
extern void dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg);
extern void dtls_FreeHandshakeMessages(PRCList *lst);
extern SECStatus dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf);
extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss,
PRUint8 *b, PRUint32 length);
extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss);
extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
const PRUint8 *pIn, PRInt32 nIn);
extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss);
extern SECStatus dtls_StartHolddownTimer(sslSocket *ss);
extern void dtls_CheckTimer(sslSocket *ss);
extern void dtls_CancelTimer(sslSocket *ss);
extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised);
extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records);
extern int dtls_RecordGetRecvd(const DTLSRecvdRecords *records,
sslSequenceNumber seq);
extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records,
sslSequenceNumber seq);
extern void dtls_RehandshakeCleanup(sslSocket *ss);
extern SSL3ProtocolVersion
dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv);
extern SSL3ProtocolVersion
dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv);
extern PRBool dtls_IsRelevant(sslSocket *ss, const SSL3Ciphertext *cText,
PRBool *sameEpoch, PRUint64 *seqNum);
extern SECStatus dtls_MaybeRetransmitHandshake(sslSocket *ss,
const SSL3Ciphertext *cText,
PRBool sameEpoch);
CK_MECHANISM_TYPE ssl3_Alg2Mech(SSLCipherAlgorithm calg);
SECStatus ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites,
PRBool initHashes);
SECStatus ssl3_InitHandshakeHashes(sslSocket *ss);
SECStatus ssl3_ServerCallSNICallback(sslSocket *ss);
SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss);
SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
SECStatus ssl3_CompleteHandleCertificate(sslSocket *ss,
PRUint8 *b, PRUint32 length);
@ -1807,17 +1601,21 @@ SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
SECStatus ssl3_AuthCertificate(sslSocket *ss);
SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b,
PRUint32 length);
SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf,
unsigned maxLen, PRUint32 *len);
SECStatus ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calenp,
SECItem **namesp, unsigned int *nnamesp);
SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, sslBuffer *buf);
SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
unsigned int *calenp,
const SECItem **namesp,
unsigned int *nnamesp);
SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b,
PRUint32 *length, PLArenaPool *arena,
CERTDistNames *ca_list);
PRUint32 *length, CERTDistNames *ca_list);
SECStatus ssl3_CompleteHandleCertificateRequest(
sslSocket *ss, const SSLSignatureScheme *signatureSchemes,
unsigned int signatureSchemeCount, CERTDistNames *ca_list);
SECStatus ssl_ConstructServerHello(sslSocket *ss, PRBool helloRetry,
const sslBuffer *extensionBuf,
sslBuffer *messageBuf);
SECStatus ssl3_SendServerHello(sslSocket *ss);
SECStatus ssl3_SendChangeCipherSpecsInt(sslSocket *ss);
SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
ssl3CipherSpec *spec,
SSL3Hashes *hashes,
@ -1832,10 +1630,9 @@ PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
PK11SlotInfo *masterSecretSlot,
CK_MECHANISM_TYPE masterWrapMech,
void *pwArg);
SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid);
SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
PK11SymKey *secret);
const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
const ssl3BulkCipherDef *
ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def);
SECStatus ssl3_SelectServerCert(sslSocket *ss);
SECStatus ssl_PickSignatureScheme(sslSocket *ss,
SECKEYPublicKey *pubKey,
@ -1847,11 +1644,14 @@ SECOidTag ssl3_HashTypeToOID(SSLHashType hashType);
SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme);
KeyType ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme);
SECStatus ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
PRBool initHashes);
SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes);
/* Pull in DTLS functions */
#include "dtlscon.h"
/* Pull in TLS 1.3 functions */
#include "tls13con.h"
#include "dtls13con.h"
/********************** misc calls *********************/
@ -1861,22 +1661,27 @@ extern void ssl3_CheckCipherSuiteOrderConsistency();
extern int ssl_MapLowLevelError(int hiLevelError);
extern PRUint32 ssl_Time(void);
extern PRUint32 ssl_TimeSec(void);
#ifdef UNSAFE_FUZZER_MODE
#define ssl_TimeUsec() ((PRTime)12345678)
#else
#define ssl_TimeUsec() (PR_Now())
#endif
extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket);
extern void SSL_AtomicIncrementLong(long *x);
SECStatus ssl3_ApplyNSSPolicy(void);
extern HASH_HashType
ssl3_GetTls12HashType(sslSocket *ss);
extern SECStatus
ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec,
const char *label, unsigned int labelLen,
const unsigned char *val, unsigned int valLen,
unsigned char *out, unsigned int outLen);
extern void
ssl3_RecordKeyLog(sslSocket *ss, const char *label, PK11SymKey *secret);
PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag);
#ifdef TRACE

View file

@ -2,26 +2,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "pk11pub.h"
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "tls13hkdf.h"
static const char *
ssl_GetCompressionMethodName(SSLCompressionMethod compression)
{
switch (compression) {
case ssl_compression_null:
return "NULL";
#ifdef NSS_ENABLE_ZLIB
case ssl_compression_deflate:
return "DEFLATE";
#endif
default:
return "???";
}
}
SECStatus
SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
{
@ -48,48 +34,58 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
inf.length = PR_MIN(sizeof inf, len);
if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
SSLCipherSuiteInfo cinfo;
SECStatus rv;
sid = ss->sec.ci.sid;
inf.protocolVersion = ss->version;
inf.authKeyBits = ss->sec.authKeyBits;
inf.keaKeyBits = ss->sec.keaKeyBits;
if (ss->ssl3.initialized) {
SSLCipherSuiteInfo cinfo;
SECStatus rv;
ssl_GetSpecReadLock(ss);
/* XXX The cipher suite should be in the specs and this
* function should get it from cwSpec rather than from the "hs".
* See bug 275744 comment 69 and bug 766137.
*/
inf.cipherSuite = ss->ssl3.hs.cipher_suite;
inf.compressionMethod = ss->ssl3.cwSpec->compression_method;
ssl_ReleaseSpecReadLock(ss);
inf.compressionMethodName =
ssl_GetCompressionMethodName(inf.compressionMethod);
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.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;
/* Fill in the cipher details from the cipher suite. */
rv = SSL_GetCipherSuiteInfo(inf.cipherSuite,
&cinfo, sizeof(cinfo));
if (rv != SECSuccess) {
return SECFailure; /* Error code already set. */
}
inf.symCipher = cinfo.symCipher;
inf.macAlgorithm = cinfo.macAlgorithm;
/* Get these fromm |ss->sec| because that is accurate
* even with TLS 1.3 disaggregated cipher suites. */
inf.keaType = ss->sec.keaType;
inf.originalKeaGroup = ss->sec.originalKeaGroup
? ss->sec.originalKeaGroup->name
: ssl_grp_none;
inf.keaGroup = ss->sec.keaGroup
? ss->sec.keaGroup->name
: ssl_grp_none;
inf.keaKeyBits = ss->sec.keaKeyBits;
inf.authType = ss->sec.authType;
inf.authKeyBits = ss->sec.authKeyBits;
inf.signatureScheme = ss->sec.signatureScheme;
/* If this is a resumed session, signatureScheme isn't set in ss->sec.
* Use the signature scheme from the previous handshake. */
if (inf.signatureScheme == ssl_sig_none && sid->sigScheme) {
inf.signatureScheme = sid->sigScheme;
}
inf.resumed = ss->statelessResume || ss->ssl3.hs.isResuming;
if (sid) {
unsigned int sidLen;
inf.creationTime = sid->creationTime;
inf.lastAccessTime = sid->lastAccessTime;
inf.expirationTime = sid->expirationTime;
inf.creationTime = sid->creationTime / PR_USEC_PER_SEC;
inf.lastAccessTime = sid->lastAccessTime / PR_USEC_PER_SEC;
inf.expirationTime = sid->expirationTime / PR_USEC_PER_SEC;
inf.extendedMasterSecretUsed =
(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ||
sid->u.ssl3.keys.extendedMasterSecretUsed)
@ -196,17 +192,17 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
#define K_ANY "TLS 1.3", ssl_kea_tls13_any
/* record protection cipher */
#define C_SEED "SEED", calg_seed
#define C_CAMELLIA "CAMELLIA", calg_camellia
#define C_AES "AES", calg_aes
#define C_RC4 "RC4", calg_rc4
#define C_RC2 "RC2", calg_rc2
#define C_DES "DES", calg_des
#define C_3DES "3DES", calg_3des
#define C_NULL "NULL", calg_null
#define C_SJ "SKIPJACK", calg_sj
#define C_AESGCM "AES-GCM", calg_aes_gcm
#define C_CHACHA20 "CHACHA20POLY1305", calg_chacha20
#define C_SEED "SEED", ssl_calg_seed
#define C_CAMELLIA "CAMELLIA", ssl_calg_camellia
#define C_AES "AES", ssl_calg_aes
#define C_RC4 "RC4", ssl_calg_rc4
#define C_RC2 "RC2", ssl_calg_rc2
#define C_DES "DES", ssl_calg_des
#define C_3DES "3DES", ssl_calg_3des
#define C_NULL "NULL", ssl_calg_null
#define C_SJ "SKIPJACK", ssl_calg_sj
#define C_AESGCM "AES-GCM", ssl_calg_aes_gcm
#define C_CHACHA20 "CHACHA20POLY1305", ssl_calg_chacha20
/* "block cipher" sizes */
#define B_256 256, 256, 256
@ -367,8 +363,7 @@ SSL_GetNegotiatedHostInfo(PRFileDesc *fd)
}
if (ss->sec.isServer) {
if (ss->version > SSL_LIBRARY_VERSION_3_0 &&
ss->ssl3.initialized) { /* TLS */
if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* TLS */
SECItem *crsName;
ssl_GetSpecReadLock(ss); /*********************************/
crsName = &ss->ssl3.hs.srvVirtName;
@ -392,22 +387,47 @@ SSL_GetNegotiatedHostInfo(PRFileDesc *fd)
return sniName;
}
/*
* HKDF-Expand-Label(Derive-Secret(Secret, label, ""),
* "exporter", Hash(context_value), key_length)
*/
static SECStatus
tls13_Exporter(sslSocket *ss, PK11SymKey *secret,
const char *label, unsigned int labelLen,
const unsigned char *context, unsigned int contextLen,
unsigned char *out, unsigned int outLen)
{
SSL3Hashes contextHash;
PK11SymKey *innerSecret = NULL;
SECStatus rv;
static const char *kExporterInnerLabel = "exporter";
if (!secret) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
return tls13_HkdfExpandLabelRaw(secret,
tls13_GetHash(ss),
context, contextLen,
label, labelLen,
out, outLen);
/* Pre-hash the context. */
rv = tls13_ComputeHash(ss, &contextHash, context, contextLen);
if (rv != SECSuccess) {
return rv;
}
rv = tls13_DeriveSecretNullHash(ss, secret, label, labelLen,
&innerSecret);
if (rv != SECSuccess) {
return rv;
}
rv = tls13_HkdfExpandLabelRaw(innerSecret,
tls13_GetHash(ss),
contextHash.u.raw, contextHash.len,
kExporterInnerLabel,
strlen(kExporterInnerLabel),
out, outLen);
PK11_FreeSymKey(innerSecret);
return rv;
}
SECStatus
@ -457,9 +477,9 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd,
return SECFailure;
}
i = 0;
PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
PORT_Memcpy(val + i, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
i += SSL3_RANDOM_LENGTH;
PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH);
PORT_Memcpy(val + i, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
i += SSL3_RANDOM_LENGTH;
if (hasContext) {
val[i++] = contextLen >> 8;
@ -473,7 +493,7 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd,
* secret is available and we have sent ChangeCipherSpec.
*/
ssl_GetSpecReadLock(ss);
if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) {
if (!ss->ssl3.cwSpec->masterSecret) {
PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
rv = SECFailure;
} else {

View file

@ -256,7 +256,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
if (!urlSvrName)
return NULL;
now = ssl_Time();
now = ssl_TimeSec();
LOCK_CACHE;
sidp = &cache;
while ((sid = *sidp) != 0) {
@ -306,8 +306,6 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
static void
CacheSID(sslSessionID *sid)
{
PRUint32 expirationPeriod;
PORT_Assert(sid->cached == never_cached);
SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
@ -335,7 +333,6 @@ CacheSID(sslSessionID *sid)
return;
sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
}
expirationPeriod = ssl3_sid_timeout;
PRINT_BUF(8, (0, "sessionID:",
sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength));
@ -345,9 +342,9 @@ CacheSID(sslSessionID *sid)
}
PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0);
if (!sid->creationTime)
sid->lastAccessTime = sid->creationTime = ssl_Time();
sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
if (!sid->expirationTime)
sid->expirationTime = sid->creationTime + expirationPeriod;
sid->expirationTime = sid->creationTime + ssl3_sid_timeout * PR_USEC_PER_SEC;
/*
* Put sid into the cache. Bump reference count to indicate that
@ -438,7 +435,7 @@ SSL_ClearSessionCache(void)
/* returns an unsigned int containing the number of seconds in PR_Now() */
PRUint32
ssl_Time(void)
ssl_TimeSec(void)
{
#ifdef UNSAFE_FUZZER_MODE
return 1234;
@ -471,7 +468,7 @@ ssl_TicketTimeValid(const NewSessionTicket *ticket)
endTime = ticket->received_timestamp +
(PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
return endTime > PR_Now();
return endTime > ssl_TimeUsec();
}
void

View file

@ -92,18 +92,16 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc *socket,
/* according to public API SSL_GetChannelInfo, this doesn't need a lock */
if (sslsocket->opt.useSecurity) {
if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */
/* now we know this socket went through ssl3_InitState() and
* ss->xtnData got initialized, which is the only member accessed by
* ssl3_ExtensionNegotiated();
* Member xtnData appears to get accessed in functions that handle
* the handshake (hello messages and extension sending),
* therefore the handshake lock should be sufficient.
*/
ssl_GetSSL3HandshakeLock(sslsocket);
*pYes = ssl3_ExtensionNegotiated(sslsocket, extId);
ssl_ReleaseSSL3HandshakeLock(sslsocket);
}
/* now we know this socket went through ssl3_InitState() and
* ss->xtnData got initialized, which is the only member accessed by
* ssl3_ExtensionNegotiated();
* Member xtnData appears to get accessed in functions that handle
* the handshake (hello messages and extension sending),
* therefore the handshake lock should be sufficient.
*/
ssl_GetSSL3HandshakeLock(sslsocket);
*pYes = ssl3_ExtensionNegotiated(sslsocket, extId);
ssl_ReleaseSSL3HandshakeLock(sslsocket);
}
return SECSuccess;

View file

@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Various SSL functions.
*
@ -200,7 +201,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl_Release1stHandshakeLock(ss);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
ssl3_ResetExtensionData(&ss->xtnData);
ssl3_ResetExtensionData(&ss->xtnData, ss);
if (!ss->TCPconnected)
ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
@ -342,11 +343,6 @@ SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart)
return SECFailure;
}
if (!ss->ssl3.initialized) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Require a forward-secret key exchange. */
*canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
@ -434,58 +430,6 @@ SSL_ForceHandshakeWithTimeout(PRFileDesc *fd,
/************************************************************************/
/*
** Grow a buffer to hold newLen bytes of data.
** Called for both recv buffers and xmit buffers.
** Caller must hold xmitBufLock or recvBufLock, as appropriate.
*/
SECStatus
sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
{
newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048);
if (newLen > b->space) {
unsigned char *newBuf;
if (b->buf) {
newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen);
} else {
newBuf = (unsigned char *)PORT_Alloc(newLen);
}
if (!newBuf) {
return SECFailure;
}
SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d",
SSL_GETPID(), b->space, newLen));
b->buf = newBuf;
b->space = newLen;
}
return SECSuccess;
}
SECStatus
sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
{
unsigned int newLen = b->len + len;
SECStatus rv;
rv = sslBuffer_Grow(b, newLen);
if (rv != SECSuccess)
return rv;
PORT_Memcpy(b->buf + b->len, data, len);
b->len += len;
return SECSuccess;
}
void
sslBuffer_Clear(sslBuffer *b)
{
if (b->buf) {
PORT_Free(b->buf);
b->buf = NULL;
b->len = 0;
b->space = 0;
}
}
/*
** Save away write data that is trying to be written before the security
** handshake has been completed. When the handshake is completed, we will
@ -774,8 +718,7 @@ ssl_SecureClose(sslSocket *ss)
if (!(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
ss->firstHsDone &&
!ss->recvdCloseNotify &&
ss->ssl3.initialized) {
!ss->recvdCloseNotify) {
/* We don't want the final alert to be Nagle delayed. */
if (!ss->delayDisabled) {
@ -805,8 +748,7 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow)
if ((sslHow & ssl_SHUTDOWN_SEND) != 0 &&
!(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
ss->firstHsDone &&
!ss->recvdCloseNotify &&
ss->ssl3.initialized) {
!ss->recvdCloseNotify) {
(void)SSL3_SendAlert(ss, alert_warning, close_notify);
}
@ -820,6 +762,55 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow)
/************************************************************************/
static SECStatus
tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
{
PRBool keyUpdate;
ssl3CipherSpec *spec;
sslSequenceNumber seqNum;
sslSequenceNumber margin;
SECStatus rv;
/* Bug 1413368: enable for DTLS */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 || IS_DTLS(ss)) {
return SECSuccess;
}
/* If both sides update at the same number, then this will cause two updates
* to happen at once. The problem is that the KeyUpdate itself consumes a
* sequence number, and that will trigger the reading side to request an
* update.
*
* If we have the writing side update first, the writer will be the one that
* drives the update. An update by the writer doesn't need a response, so
* it is more efficient overall. The margins here are pretty arbitrary, but
* having the write margin larger reduces the number of times that a
* KeyUpdate is sent by a reader. */
ssl_GetSpecReadLock(ss);
if (dir == CipherSpecRead) {
spec = ss->ssl3.crSpec;
margin = spec->cipherDef->max_records / 8;
} else {
spec = ss->ssl3.cwSpec;
margin = spec->cipherDef->max_records / 4;
}
seqNum = spec->seqNum;
keyUpdate = seqNum > spec->cipherDef->max_records - margin;
ssl_ReleaseSpecReadLock(ss);
if (!keyUpdate) {
return SECSuccess;
}
SSL_TRC(5, ("%d: SSL[%d]: automatic key update at %llx for %s cipher spec",
SSL_GETPID(), ss->fd, seqNum,
(dir == CipherSpecRead) ? "read" : "write"));
ssl_GetSSL3HandshakeLock(ss);
rv = tls13_SendKeyUpdate(ss, (dir == CipherSpecRead) ? update_requested : update_not_requested,
dir == CipherSpecWrite /* buffer */);
ssl_ReleaseSSL3HandshakeLock(ss);
return rv;
}
int
ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
{
@ -859,8 +850,17 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
rv = ssl_Do1stHandshake(ss);
}
ssl_Release1stHandshakeLock(ss);
} else {
if (tls13_CheckKeyUpdate(ss, CipherSpecRead) != SECSuccess) {
rv = PR_FAILURE;
}
}
if (rv < 0) {
if (PORT_GetError() == PR_WOULD_BLOCK_ERROR &&
!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) {
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
return tls13_Read0RttData(ss, buf, len);
}
return rv;
}
@ -942,11 +942,19 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
}
ssl_Release1stHandshakeLock(ss);
}
if (rv < 0) {
ss->writerThread = NULL;
goto done;
}
if (ss->firstHsDone) {
if (tls13_CheckKeyUpdate(ss, CipherSpecWrite) != SECSuccess) {
rv = PR_FAILURE;
goto done;
}
}
if (zeroRtt) {
/* There's a limit to the number of early data octets we can send.
*
@ -1241,14 +1249,7 @@ SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error)
}
ssl_Get1stHandshakeLock(ss);
if (!ss->ssl3.initialized) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
} else {
rv = ssl3_AuthCertificateComplete(ss, error);
}
rv = ssl3_AuthCertificateComplete(ss, error);
ssl_Release1stHandshakeLock(ss);
return rv;

View file

@ -85,11 +85,12 @@
/*
** Format of a cache entry in the shared memory.
*/
PR_STATIC_ASSERT(sizeof(PRTime) == 8);
struct sidCacheEntryStr {
/* 16 */ PRIPv6Addr addr; /* client's IP address */
/* 4 */ PRUint32 creationTime;
/* 4 */ PRUint32 lastAccessTime;
/* 4 */ PRUint32 expirationTime;
/* 8 */ PRTime creationTime;
/* 8 */ PRTime lastAccessTime;
/* 8 */ PRTime expirationTime;
/* 2 */ PRUint16 version;
/* 1 */ PRUint8 valid;
/* 1 */ PRUint8 sessionIDLength;
@ -98,25 +99,25 @@ struct sidCacheEntryStr {
/* 2 */ PRUint16 authKeyBits;
/* 2 */ PRUint16 keaType;
/* 2 */ PRUint16 keaKeyBits;
/* 72 - common header total */
/* 4 */ PRUint32 signatureScheme;
/* 4 */ PRUint32 keaGroup;
/* 92 - common header total */
union {
struct {
/* 2 */ ssl3CipherSuite cipherSuite;
/* 2 */ PRUint16 compression; /* SSLCompressionMethod */
/* 54 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
/* 52 */ ssl3SidKeys keys; /* keys, wrapped as needed. */
/* 4 */ PRUint32 masterWrapMech;
/* 4 */ PRInt32 certIndex;
/* 4 */ PRInt32 srvNameIndex;
/* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */
/* 2 */ PRUint16 namedCurve;
/*104 */} ssl3;
/*100 */} ssl3;
/* force sizeof(sidCacheEntry) to be a multiple of cache line size */
struct {
/*120 */ PRUint8 filler[120]; /* 72+120==192, a multiple of 16 */
/*116 */ PRUint8 filler[116]; /* 92+116==208, a multiple of 16 */
} forceSize;
} u;
};
@ -282,7 +283,7 @@ LockSidCacheLock(sidCacheLock *lock, PRUint32 now)
if (rv != SECSuccess)
return 0;
if (!now)
now = ssl_Time();
now = ssl_TimeSec();
lock->timeStamp = now;
lock->pid = myPid;
return now;
@ -298,7 +299,7 @@ UnlockSidCacheLock(sidCacheLock *lock)
return rv;
}
/* returns the value of ssl_Time on success, zero on failure. */
/* returns the value of ssl_TimeSec on success, zero on failure. */
static PRUint32
LockSet(cacheDesc *cache, PRUint32 set, PRUint32 now)
{
@ -432,9 +433,10 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
to->authKeyBits = from->authKeyBits;
to->keaType = from->keaType;
to->keaKeyBits = from->keaKeyBits;
to->keaGroup = from->keaGroup;
to->signatureScheme = from->sigScheme;
to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
to->u.ssl3.compression = (PRUint16)from->u.ssl3.compression;
to->u.ssl3.keys = from->u.ssl3.keys;
to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
to->sessionIDLength = from->u.ssl3.sessionIDLength;
@ -452,9 +454,10 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from)
SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x "
"cipherSuite=%d",
myPid, to->creationTime, to->addr.pr_s6_addr32[0],
to->addr.pr_s6_addr32[1], to->addr.pr_s6_addr32[2],
to->addr.pr_s6_addr32[3], to->u.ssl3.cipherSuite));
myPid, to->creationTime / PR_USEC_PER_SEC,
to->addr.pr_s6_addr32[0], to->addr.pr_s6_addr32[1],
to->addr.pr_s6_addr32[2], to->addr.pr_s6_addr32[3],
to->u.ssl3.cipherSuite));
}
/*
@ -476,7 +479,6 @@ ConvertToSID(sidCacheEntry *from,
to->u.ssl3.sessionIDLength = from->sessionIDLength;
to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite;
to->u.ssl3.compression = (SSLCompressionMethod)from->u.ssl3.compression;
to->u.ssl3.keys = from->u.ssl3.keys;
to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech;
if (from->u.ssl3.srvNameIndex != -1 && psnce) {
@ -541,6 +543,8 @@ ConvertToSID(sidCacheEntry *from,
to->authKeyBits = from->authKeyBits;
to->keaType = from->keaType;
to->keaKeyBits = from->keaKeyBits;
to->keaGroup = from->keaGroup;
to->sigScheme = from->signatureScheme;
return to;
@ -748,17 +752,19 @@ ServerSessionIDCache(sslSessionID *sid)
PORT_Assert(sid->creationTime != 0);
if (!sid->creationTime)
sid->lastAccessTime = sid->creationTime = ssl_Time();
sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
/* override caller's expiration time, which uses client timeout
* duration, not server timeout duration.
*/
sid->expirationTime = sid->creationTime + cache->ssl3Timeout;
sid->expirationTime =
sid->creationTime + cache->ssl3Timeout * PR_USEC_PER_SEC;
SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x "
"cipherSuite=%d",
myPid, sid->cached,
sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
sid->creationTime, sid->u.ssl3.cipherSuite));
sid->creationTime / PR_USEC_PER_SEC,
sid->u.ssl3.cipherSuite));
PRINT_BUF(8, (0, "sessionID:", sid->u.ssl3.sessionID,
sid->u.ssl3.sessionIDLength));
@ -820,7 +826,8 @@ ServerSessionIDUncache(sslSessionID *sid)
myPid, sid->cached,
sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1],
sid->addr.pr_s6_addr32[2], sid->addr.pr_s6_addr32[3],
sid->creationTime, sid->u.ssl3.cipherSuite));
sid->creationTime / PR_USEC_PER_SEC,
sid->u.ssl3.cipherSuite));
PRINT_BUF(8, (0, "sessionID:", sessionID, sessionIDLength));
set = SIDindex(cache, &sid->addr, sessionID, sessionIDLength);
now = LockSet(cache, set, 0);
@ -1086,7 +1093,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries,
cache->srvNameCacheData = (srvNameCacheEntry *)(cache->cacheMem + (ptrdiff_t)cache->srvNameCacheData);
/* initialize the locks */
init_time = ssl_Time();
init_time = ssl_TimeSec();
pLock = cache->sidCacheLocks;
for (locks_to_initialize = cache->numSIDCacheLocks + 3;
locks_initialized < locks_to_initialize;
@ -1134,6 +1141,10 @@ SSL_SetMaxServerCacheLocks(PRUint32 maxLocks)
return SECSuccess;
}
PR_STATIC_ASSERT(sizeof(sidCacheEntry) % 16 == 0);
PR_STATIC_ASSERT(sizeof(certCacheEntry) == 4096);
PR_STATIC_ASSERT(sizeof(srvNameCacheEntry) == 1072);
static SECStatus
ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
PRUint32 ssl3_timeout,
@ -1145,10 +1156,6 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
{
SECStatus rv;
PORT_Assert(sizeof(sidCacheEntry) == 192);
PORT_Assert(sizeof(certCacheEntry) == 4096);
PORT_Assert(sizeof(srvNameCacheEntry) == 1072);
rv = ssl_Init();
if (rv != SECSuccess) {
return rv;
@ -1519,7 +1526,7 @@ LockPoller(void *arg)
if (sharedCache->stopPolling)
break;
now = ssl_Time();
now = ssl_TimeSec();
then = now - expiration;
for (pLock = cache->sidCacheLocks, locks_polled = 0;
locks_to_poll > locks_polled && !sharedCache->stopPolling;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,273 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Handling of cipher specs.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ssl.h"
#include "sslproto.h"
#include "pk11func.h"
#include "secitem.h"
#include "sslimpl.h"
/* Record protection algorithms, indexed by SSL3BulkCipher.
*
* The |max_records| field (|mr| below) is set to a number that is higher than
* recommended in some literature (esp. TLS 1.3) because we currently abort the
* connection when this limit is reached and we want to ensure that we only
* rarely hit this limit. See bug 1268745 for details.
*/
#define MR_MAX RECORD_SEQ_MAX /* 2^48-1 */
#define MR_128 (0x5aULL << 28) /* For AES and similar. */
#define MR_LOW (1ULL << 20) /* For weak ciphers. */
/* clang-format off */
static const ssl3BulkCipherDef ssl_bulk_cipher_defs[] = {
/* |--------- Lengths ---------| */
/* cipher calg : s : */
/* : e b n */
/* oid short_name mr : c l o */
/* k r o t n */
/* e e i c a c */
/* y t type v k g e */
{cipher_null, ssl_calg_null, 0, 0, type_stream, 0, 0, 0, 0,
SEC_OID_NULL_CIPHER, "NULL", MR_MAX},
{cipher_rc4, ssl_calg_rc4, 16,16, type_stream, 0, 0, 0, 0,
SEC_OID_RC4, "RC4", MR_LOW},
{cipher_des, ssl_calg_des, 8, 8, type_block, 8, 8, 0, 0,
SEC_OID_DES_CBC, "DES-CBC", MR_LOW},
{cipher_3des, ssl_calg_3des, 24,24, type_block, 8, 8, 0, 0,
SEC_OID_DES_EDE3_CBC, "3DES-EDE-CBC", MR_LOW},
{cipher_aes_128, ssl_calg_aes, 16,16, type_block, 16,16, 0, 0,
SEC_OID_AES_128_CBC, "AES-128", MR_128},
{cipher_aes_256, ssl_calg_aes, 32,32, type_block, 16,16, 0, 0,
SEC_OID_AES_256_CBC, "AES-256", MR_128},
{cipher_camellia_128, ssl_calg_camellia, 16,16, type_block, 16,16, 0, 0,
SEC_OID_CAMELLIA_128_CBC, "Camellia-128", MR_128},
{cipher_camellia_256, ssl_calg_camellia, 32,32, type_block, 16,16, 0, 0,
SEC_OID_CAMELLIA_256_CBC, "Camellia-256", MR_128},
{cipher_seed, ssl_calg_seed, 16,16, type_block, 16,16, 0, 0,
SEC_OID_SEED_CBC, "SEED-CBC", MR_128},
{cipher_aes_128_gcm, ssl_calg_aes_gcm, 16,16, type_aead, 4, 0,16, 8,
SEC_OID_AES_128_GCM, "AES-128-GCM", MR_128},
{cipher_aes_256_gcm, ssl_calg_aes_gcm, 32,32, type_aead, 4, 0,16, 8,
SEC_OID_AES_256_GCM, "AES-256-GCM", MR_128},
{cipher_chacha20, ssl_calg_chacha20, 32,32, type_aead, 12, 0,16, 0,
SEC_OID_CHACHA20_POLY1305, "ChaCha20-Poly1305", MR_MAX},
{cipher_missing, ssl_calg_null, 0, 0, type_stream, 0, 0, 0, 0,
SEC_OID_UNKNOWN, "missing", 0U},
};
/* clang-format on */
const ssl3BulkCipherDef *
ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *suiteDef)
{
SSL3BulkCipher bulkCipher = suiteDef->bulk_cipher_alg;
PORT_Assert(bulkCipher < PR_ARRAY_SIZE(ssl_bulk_cipher_defs));
PORT_Assert(ssl_bulk_cipher_defs[bulkCipher].cipher == bulkCipher);
return &ssl_bulk_cipher_defs[bulkCipher];
}
/* indexed by SSL3MACAlgorithm */
static const ssl3MACDef ssl_mac_defs[] = {
/* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */
/* mac mmech pad_size mac_size */
{ ssl_mac_null, CKM_INVALID_MECHANISM, 0, 0, 0 },
{ ssl_mac_md5, CKM_SSL3_MD5_MAC, 48, MD5_LENGTH, SEC_OID_HMAC_MD5 },
{ ssl_mac_sha, CKM_SSL3_SHA1_MAC, 40, SHA1_LENGTH, SEC_OID_HMAC_SHA1 },
{ ssl_hmac_md5, CKM_MD5_HMAC, 0, MD5_LENGTH, SEC_OID_HMAC_MD5 },
{ ssl_hmac_sha, CKM_SHA_1_HMAC, 0, SHA1_LENGTH, SEC_OID_HMAC_SHA1 },
{ ssl_hmac_sha256, CKM_SHA256_HMAC, 0, SHA256_LENGTH, SEC_OID_HMAC_SHA256 },
{ ssl_mac_aead, CKM_INVALID_MECHANISM, 0, 0, 0 },
{ ssl_hmac_sha384, CKM_SHA384_HMAC, 0, SHA384_LENGTH, SEC_OID_HMAC_SHA384 }
};
const ssl3MACDef *
ssl_GetMacDefByAlg(SSL3MACAlgorithm mac)
{
/* Cast here for clang: https://bugs.llvm.org/show_bug.cgi?id=16154 */
PORT_Assert((size_t)mac < PR_ARRAY_SIZE(ssl_mac_defs));
PORT_Assert(ssl_mac_defs[mac].mac == mac);
return &ssl_mac_defs[mac];
}
const ssl3MACDef *
ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef)
{
SSL3MACAlgorithm mac = suiteDef->mac_alg;
if (ss->version > SSL_LIBRARY_VERSION_3_0) {
switch (mac) {
case ssl_mac_md5:
mac = ssl_hmac_md5;
break;
case ssl_mac_sha:
mac = ssl_hmac_sha;
break;
default:
break;
}
}
return ssl_GetMacDefByAlg(mac);
}
ssl3CipherSpec *
ssl_FindCipherSpecByEpoch(sslSocket *ss, CipherSpecDirection direction,
DTLSEpoch epoch)
{
PRCList *cur_p;
for (cur_p = PR_LIST_HEAD(&ss->ssl3.hs.cipherSpecs);
cur_p != &ss->ssl3.hs.cipherSpecs;
cur_p = PR_NEXT_LINK(cur_p)) {
ssl3CipherSpec *spec = (ssl3CipherSpec *)cur_p;
if (spec->epoch != epoch) {
continue;
}
if (direction != spec->direction) {
continue;
}
return spec;
}
return NULL;
}
ssl3CipherSpec *
ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction)
{
ssl3CipherSpec *spec = PORT_ZNew(ssl3CipherSpec);
if (!spec) {
return NULL;
}
spec->refCt = 1;
spec->version = ss->version;
spec->direction = direction;
SSL_TRC(10, ("%d: SSL[%d]: new %s spec %d ct=%d",
SSL_GETPID(), ss->fd, SPEC_DIR(spec), spec,
spec->refCt));
return spec;
}
void
ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
{
PR_APPEND_LINK(&spec->link, &ss->ssl3.hs.cipherSpecs);
}
/* Called from ssl3_InitState. */
/* Caller must hold the SpecWriteLock. */
SECStatus
ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir)
{
ssl3CipherSpec *spec;
PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
spec = ssl_CreateCipherSpec(ss, dir);
if (!spec) {
return SECFailure;
}
/* Set default versions. This value will be used to generate and send
* alerts if a version is not negotiated. These values are overridden when
* sending a ClientHello and when a version is negotiated. */
spec->version = SSL_LIBRARY_VERSION_TLS_1_0;
spec->recordVersion = IS_DTLS(ss)
? SSL_LIBRARY_VERSION_DTLS_1_0_WIRE
: SSL_LIBRARY_VERSION_TLS_1_0;
spec->cipherDef = &ssl_bulk_cipher_defs[cipher_null];
PORT_Assert(spec->cipherDef->cipher == cipher_null);
spec->macDef = &ssl_mac_defs[ssl_mac_null];
PORT_Assert(spec->macDef->mac == ssl_mac_null);
spec->cipher = Null_Cipher;
spec->phase = "cleartext";
dtls_InitRecvdRecords(&spec->recvdRecords);
ssl_SaveCipherSpec(ss, spec);
if (dir == CipherSpecRead) {
ss->ssl3.crSpec = spec;
} else {
ss->ssl3.cwSpec = spec;
}
return SECSuccess;
}
void
ssl_CipherSpecAddRef(ssl3CipherSpec *spec)
{
++spec->refCt;
SSL_TRC(10, ("%d: SSL[-]: Increment ref ct for %s spec %d. new ct = %d",
SSL_GETPID(), SPEC_DIR(spec), spec, spec->refCt));
}
static void
ssl_DestroyKeyMaterial(ssl3KeyMaterial *keyMaterial)
{
PK11_FreeSymKey(keyMaterial->key);
PK11_FreeSymKey(keyMaterial->macKey);
if (keyMaterial->macContext != NULL) {
PK11_DestroyContext(keyMaterial->macContext, PR_TRUE);
}
}
static void
ssl_FreeCipherSpec(ssl3CipherSpec *spec)
{
SSL_TRC(10, ("%d: SSL[-]: Freeing %s spec %d. epoch=%d",
SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch));
PR_REMOVE_LINK(&spec->link);
/* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */
if (spec->cipherContext) {
PK11_DestroyContext(spec->cipherContext, PR_TRUE);
}
PK11_FreeSymKey(spec->masterSecret);
ssl_DestroyKeyMaterial(&spec->keyMaterial);
PORT_ZFree(spec, sizeof(*spec));
}
/* This function is never called on a spec which is on the
* cipherSpecs list. */
void
ssl_CipherSpecRelease(ssl3CipherSpec *spec)
{
if (!spec) {
return;
}
PORT_Assert(spec->refCt > 0);
--spec->refCt;
SSL_TRC(10, ("%d: SSL[-]: decrement refct for %s spec %d. epoch=%d new ct = %d",
SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch, spec->refCt));
if (!spec->refCt) {
ssl_FreeCipherSpec(spec);
}
}
void
ssl_DestroyCipherSpecs(PRCList *list)
{
while (!PR_CLIST_IS_EMPTY(list)) {
ssl3CipherSpec *spec = (ssl3CipherSpec *)PR_LIST_TAIL(list);
ssl_FreeCipherSpec(spec);
}
}
void
ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection dir,
DTLSEpoch epoch)
{
ssl3CipherSpec *spec;
SSL_TRC(10, ("%d: SSL[%d]: releasing %s cipher spec for epoch %d",
SSL_GETPID(), ss->fd,
(dir == CipherSpecRead) ? "read" : "write", epoch));
spec = ssl_FindCipherSpecByEpoch(ss, dir, epoch);
if (spec) {
ssl_CipherSpecRelease(spec);
}
}

View file

@ -0,0 +1,194 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __sslspec_h_
#define __sslspec_h_
#include "sslexp.h"
#include "prclist.h"
typedef enum {
TrafficKeyClearText = 0,
TrafficKeyEarlyApplicationData = 1,
TrafficKeyHandshake = 2,
TrafficKeyApplicationData = 3
} TrafficKeyType;
typedef enum {
CipherSpecRead,
CipherSpecWrite,
} CipherSpecDirection;
#define SPEC_DIR(spec) \
((spec->direction == CipherSpecRead) ? "read" : "write")
typedef struct ssl3CipherSpecStr ssl3CipherSpec;
typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
typedef struct ssl3MACDefStr ssl3MACDef;
typedef struct ssl3CipherSuiteDefStr ssl3CipherSuiteDef;
typedef PRUint64 sslSequenceNumber;
typedef PRUint16 DTLSEpoch;
/* The SSL bulk cipher definition */
typedef enum {
cipher_null,
cipher_rc4,
cipher_des,
cipher_3des,
cipher_aes_128,
cipher_aes_256,
cipher_camellia_128,
cipher_camellia_256,
cipher_seed,
cipher_aes_128_gcm,
cipher_aes_256_gcm,
cipher_chacha20,
cipher_missing /* reserved for no such supported cipher */
/* This enum must match ssl3_cipherName[] in ssl3con.c. */
} SSL3BulkCipher;
typedef enum {
type_stream,
type_block,
type_aead
} CipherType;
/*
** There are tables of these, all const.
*/
struct ssl3BulkCipherDefStr {
SSL3BulkCipher cipher;
SSLCipherAlgorithm calg;
unsigned int key_size;
unsigned int secret_key_size;
CipherType type;
unsigned int iv_size;
unsigned int block_size;
unsigned int tag_size; /* for AEAD ciphers. */
unsigned int explicit_nonce_size; /* for AEAD ciphers. */
SECOidTag oid;
const char *short_name;
/* The maximum number of records that can be sent/received with the same
* symmetric key before the connection will be terminated. */
PRUint64 max_records;
};
/* to make some of these old enums public without namespace pollution,
** it was necessary to prepend ssl_ to the names.
** These #defines preserve compatibility with the old code here in libssl.
*/
typedef SSLMACAlgorithm SSL3MACAlgorithm;
/*
* There are tables of these, all const.
*/
struct ssl3MACDefStr {
SSL3MACAlgorithm mac;
CK_MECHANISM_TYPE mmech;
int pad_size;
int mac_size;
SECOidTag oid;
};
#define MAX_IV_LENGTH 24
typedef struct {
PK11SymKey *key;
PK11SymKey *macKey;
PK11Context *macContext;
PRUint8 iv[MAX_IV_LENGTH];
} ssl3KeyMaterial;
typedef SECStatus (*SSLCipher)(void *context,
unsigned char *out,
int *outlen,
int maxout,
const unsigned char *in,
int inlen);
typedef SECStatus (*SSLAEADCipher)(
ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
int *outlen,
int maxout,
const unsigned char *in,
int inlen,
const unsigned char *additionalData,
int additionalDataLen);
/* The DTLS anti-replay window in number of packets. Defined here because we
* need it in the cipher spec. Note that this is a ring buffer but left and
* right represent the true window, with modular arithmetic used to map them
* onto the buffer.
*/
#define DTLS_RECVD_RECORDS_WINDOW 1024
#define RECORD_SEQ_MASK ((1ULL << 48) - 1)
#define RECORD_SEQ_MAX RECORD_SEQ_MASK
PR_STATIC_ASSERT(DTLS_RECVD_RECORDS_WINDOW % 8 == 0);
typedef struct DTLSRecvdRecordsStr {
unsigned char data[DTLS_RECVD_RECORDS_WINDOW / 8];
sslSequenceNumber left;
sslSequenceNumber right;
} DTLSRecvdRecords;
/*
* These are the "specs" used for reading and writing records. Access to the
* pointers to these specs, and all the specs' contents (direct and indirect) is
* protected by the reader/writer lock ss->specLock.
*/
struct ssl3CipherSpecStr {
PRCList link;
PRUint8 refCt;
CipherSpecDirection direction;
SSL3ProtocolVersion version;
SSL3ProtocolVersion recordVersion;
const ssl3BulkCipherDef *cipherDef;
const ssl3MACDef *macDef;
SSLCipher cipher;
SSLAEADCipher aead;
void *cipherContext;
PK11SymKey *masterSecret;
ssl3KeyMaterial keyMaterial;
DTLSEpoch epoch;
const char *phase;
sslSequenceNumber seqNum;
DTLSRecvdRecords recvdRecords;
/* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
* will be zero for everything but 0-RTT. */
PRUint32 earlyDataRemaining;
};
typedef void (*sslCipherSpecChangedFunc)(void *arg,
PRBool sending,
ssl3CipherSpec *newSpec);
const ssl3BulkCipherDef *ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def);
const ssl3MACDef *ssl_GetMacDefByAlg(SSL3MACAlgorithm mac);
const ssl3MACDef *ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef);
ssl3CipherSpec *ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction);
void ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec);
void ssl_CipherSpecAddRef(ssl3CipherSpec *spec);
void ssl_CipherSpecRelease(ssl3CipherSpec *spec);
void ssl_DestroyCipherSpecs(PRCList *list);
SECStatus ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir);
ssl3CipherSpec *ssl_FindCipherSpecByEpoch(sslSocket *ss,
CipherSpecDirection direction,
DTLSEpoch epoch);
void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection direction,
DTLSEpoch epoch);
#endif /* __sslspec_h_ */

View file

@ -13,6 +13,28 @@
#include "secitem.h"
#include "certt.h"
typedef enum {
ssl_hs_hello_request = 0,
ssl_hs_client_hello = 1,
ssl_hs_server_hello = 2,
ssl_hs_hello_verify_request = 3,
ssl_hs_new_session_ticket = 4,
ssl_hs_end_of_early_data = 5,
ssl_hs_hello_retry_request = 6,
ssl_hs_encrypted_extensions = 8,
ssl_hs_certificate = 11,
ssl_hs_server_key_exchange = 12,
ssl_hs_certificate_request = 13,
ssl_hs_server_hello_done = 14,
ssl_hs_certificate_verify = 15,
ssl_hs_client_key_exchange = 16,
ssl_hs_finished = 20,
ssl_hs_certificate_status = 22,
ssl_hs_key_update = 24,
ssl_hs_next_proto = 67,
ssl_hs_message_hash = 254, /* Not a real message. */
} SSLHandshakeType;
typedef struct SSL3StatisticsStr {
/* statistics from ssl3_SendClientHello (sch) */
long sch_sid_cache_hits;
@ -275,6 +297,14 @@ typedef struct SSLChannelInfoStr {
SSLAuthType authType;
SSLSignatureScheme signatureScheme;
/* The following fields were added in NSS 3.34. */
/* When the session was resumed this holds the key exchange group of the
* original handshake. */
SSLNamedGroup originalKeaGroup;
/* This field is PR_TRUE when the session is resumed and PR_FALSE
* otherwise. */
PRBool resumed;
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLChannelInfo;
@ -395,16 +425,19 @@ typedef enum {
ssl_padding_xtn = 21,
ssl_extended_master_secret_xtn = 23,
ssl_session_ticket_xtn = 35,
ssl_tls13_key_share_xtn = 40,
/* 40 was used in draft versions of TLS 1.3; it is now reserved. */
ssl_tls13_pre_shared_key_xtn = 41,
ssl_tls13_early_data_xtn = 42,
ssl_tls13_supported_versions_xtn = 43,
ssl_tls13_cookie_xtn = 44,
ssl_tls13_psk_key_exchange_modes_xtn = 45,
ssl_tls13_ticket_early_data_info_xtn = 46,
ssl_next_proto_nego_xtn = 13172,
ssl_tls13_ticket_early_data_info_xtn = 46, /* Deprecated. */
ssl_tls13_certificate_authorities_xtn = 47,
ssl_signature_algorithms_cert_xtn = 50,
ssl_tls13_key_share_xtn = 51,
ssl_next_proto_nego_xtn = 13172, /* Deprecated. */
ssl_renegotiation_info_xtn = 0xff01,
ssl_tls13_short_header_xtn = 0xff03
ssl_tls13_short_header_xtn = 0xff03 /* Deprecated. */
} SSLExtensionType;
/* This is the old name for the supported_groups extensions. */

File diff suppressed because it is too large Load diff

View file

@ -9,15 +9,25 @@
#ifndef __tls13con_h_
#define __tls13con_h_
#include "sslexp.h"
#include "sslspec.h"
typedef enum {
StaticSharedSecret,
EphemeralSharedSecret
} SharedSecretType;
tls13_extension_allowed,
tls13_extension_disallowed,
tls13_extension_unknown
} tls13ExtensionStatus;
typedef enum {
update_not_requested = 0,
update_requested = 1
} tls13KeyUpdateRequest;
#define TLS13_MAX_FINISHED_SIZE 64
SECStatus tls13_UnprotectRecord(
sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext,
sslSocket *ss, ssl3CipherSpec *spec,
SSL3Ciphertext *cText, sslBuffer *plaintext,
SSL3AlertDescription *alert);
#if defined(WIN32)
@ -41,6 +51,14 @@ SSLHashType tls13_GetHash(const sslSocket *ss);
unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
unsigned int tls13_GetHashSize(const sslSocket *ss);
CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss);
SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
const PRUint8 *buf, unsigned int len);
SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
SSL3Hashes *hashes);
SECStatus tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
const char *label,
unsigned int labelLen,
PK11SymKey **dest);
void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
SSL3AlertDescription desc);
SECStatus tls13_SetupClientHello(sslSocket *ss);
@ -49,27 +67,30 @@ PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend
PRBool tls13_AllowPskCipher(const sslSocket *ss,
const ssl3CipherSuiteDef *cipher_def);
PRBool tls13_PskSuiteEnabled(sslSocket *ss);
SECStatus tls13_ComputePskBinder(sslSocket *ss, PRBool sending,
unsigned int prefixLength,
PRUint8 *output, unsigned int *outputLen,
unsigned int maxOutputLen);
SECStatus tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions);
SECStatus tls13_HandleClientHelloPart2(sslSocket *ss,
const SECItem *suites,
sslSessionID *sid);
sslSessionID *sid,
const PRUint8 *msg,
unsigned int len);
SECStatus tls13_HandleServerHelloPart2(sslSocket *ss);
SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
PRUint32 length,
SSL3Hashes *hashesPtr);
SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b,
PRUint32 length);
SECStatus tls13_ConstructHelloRetryRequest(sslSocket *ss,
ssl3CipherSuite cipherSuite,
const sslNamedGroupDef *selectedGroup,
PRUint8 *cookie,
unsigned int cookieLen,
sslBuffer *buffer);
SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *b,
PRUint32 length);
void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry);
void tls13_DestroyKeyShares(PRCList *list);
SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef);
void tls13_DestroyEarlyData(PRCList *list);
void tls13_CipherSpecAddRef(ssl3CipherSpec *spec);
void tls13_CipherSpecRelease(ssl3CipherSpec *spec);
void tls13_DestroyCipherSpecs(PRCList *list);
PRBool tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message);
SECStatus tls13_SetAlertCipherSpec(sslSocket *ss);
tls13ExtensionStatus tls13_ExtensionStatus(PRUint16 extension,
SSLHandshakeType message);
SECStatus tls13_ProtectRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec,
SSL3ContentType type,
@ -77,13 +98,25 @@ SECStatus tls13_ProtectRecord(sslSocket *ss,
PRUint32 contentLen,
sslBuffer *wrBuf);
PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss);
SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
PRUint16 tls13_DecodeDraftVersion(PRUint16 version);
SECStatus tls13_NegotiateVersion(sslSocket *ss,
const TLSExtension *supported_versions);
SECStatus tls13_SendNewSessionTicket(sslSocket *ss);
PRBool tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid);
void tls13_AntiReplayRollover(PRTime now);
SECStatus SSLExp_SetupAntiReplay(PRTime window, unsigned int k,
unsigned int bits);
SECStatus SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
SSLHelloRetryRequestCallback cb,
void *arg);
SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request,
PRBool buffer);
SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate);
PRBool tls13_MaybeTls13(sslSocket *ss);
void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
#endif /* __tls13con_h_ */

View file

@ -0,0 +1,28 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __tls13err_h_
#define __tls13err_h_
/* Use this instead of FATAL_ERROR when an alert isn't possible. */
#define LOG_ERROR(ss, prError) \
do { \
SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \
SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \
PORT_SetError(prError); \
} while (0)
/* Log an error and generate an alert because something is irreparably wrong. */
#define FATAL_ERROR(ss, prError, desc) \
do { \
LOG_ERROR(ss, prError); \
tls13_FatalError(ss, prError, desc); \
} while (0)
void tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc);
#endif

File diff suppressed because it is too large Load diff

View file

@ -9,66 +9,80 @@
#ifndef __tls13exthandle_h_
#define __tls13exthandle_h_
PRInt32 tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
PRInt32 tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes);
SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type,
SECStatus tls13_ServerSendStatusRequestXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ClientSendKeyShareXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type,
SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type,
SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
PRInt32 tls13_ServerSendKeyShareXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
PRInt32 tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
PRUint32 maxBytes);
SECStatus tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type,
SECStatus tls13_ServerSendKeyShareXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type,
SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
PRInt32 tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
PRInt32 tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
SECStatus tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECStatus tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ClientSendEarlyDataXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ServerHandleEarlyDataXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
PRInt32 tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
SECStatus tls13_ClientHandleTicketEarlyDataInfoXtn(
const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
PRInt32 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
PRInt32 tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PRBool append,
PRUint32 maxBytes);
PRInt32 tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss,
SECStatus tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
SECStatus tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
PRUint16 ex_type, SECItem *data);
PRInt32 tls13_SendShortHeaderXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
PRBool append, PRUint32 maxBytes);
SECStatus tls13_HandleShortHeaderXtn(
const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data);
SECItem *data);
SECStatus tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ClientSendHrrCookieXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ClientSendPskModesXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ServerHandlePskModesXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_SendCertAuthoritiesXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *append);
SECStatus tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerHandleCookieXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_ServerSendHrrCookieXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
#endif

View file

@ -0,0 +1,181 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "pk11func.h"
#include "ssl.h"
#include "sslt.h"
#include "sslimpl.h"
#include "selfencrypt.h"
#include "tls13con.h"
#include "tls13err.h"
#include "tls13hashstate.h"
/*
* The cookie is structured as a self-encrypted structure with the
* inner value being.
*
* struct {
* uint8 indicator = 0xff; // To disambiguate from tickets.
* uint16 cipherSuite; // Selected cipher suite.
* uint16 keyShare; // Requested key share group (0=none)
* opaque applicationToken<0..65535>; // Application token
* opaque ch_hash[rest_of_buffer]; // H(ClientHello)
* } CookieInner;
*/
SECStatus
tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
const PRUint8 *appToken, unsigned int appTokenLen,
PRUint8 *buf, unsigned int *len, unsigned int maxlen)
{
SECStatus rv;
SSL3Hashes hashes;
PRUint8 cookie[1024];
sslBuffer cookieBuf = SSL_BUFFER(cookie);
static const PRUint8 indicator = 0xff;
/* Encode header. */
rv = sslBuffer_Append(&cookieBuf, &indicator, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(&cookieBuf, ss->ssl3.hs.cipher_suite, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(&cookieBuf,
selectedGroup ? selectedGroup->name : 0, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* Application token. */
rv = sslBuffer_AppendVariable(&cookieBuf, appToken, appTokenLen, 2);
if (rv != SECSuccess) {
return SECFailure;
}
/* Compute and encode hashes. */
rv = tls13_ComputeHandshakeHashes(ss, &hashes);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Append(&cookieBuf, hashes.u.raw, hashes.len);
if (rv != SECSuccess) {
return SECFailure;
}
/* Encrypt right into the buffer. */
rv = ssl_SelfEncryptProtect(ss, cookieBuf.buf, cookieBuf.len,
buf, len, maxlen);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
/* Recover the hash state from the cookie. */
SECStatus
tls13_RecoverHashState(sslSocket *ss,
unsigned char *cookie, unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup)
{
SECStatus rv;
unsigned char plaintext[1024];
SECItem ptItem = { siBuffer, plaintext, 0 };
sslBuffer messageBuf = SSL_BUFFER_EMPTY;
PRUint32 sentinel;
PRUint32 cipherSuite;
PRUint32 group;
const sslNamedGroupDef *selectedGroup;
PRUint32 appTokenLen;
PRUint8 *appToken;
rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
ptItem.data, &ptItem.len, sizeof(plaintext));
if (rv != SECSuccess) {
return SECFailure;
}
/* Should start with 0xff. */
rv = ssl3_ConsumeNumberFromItem(&ptItem, &sentinel, 1);
if ((rv != SECSuccess) || (sentinel != 0xff)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The cipher suite should be the same or there are some shenanigans. */
rv = ssl3_ConsumeNumberFromItem(&ptItem, &cipherSuite, 2);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The named group, if any. */
rv = ssl3_ConsumeNumberFromItem(&ptItem, &group, 2);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
selectedGroup = ssl_LookupNamedGroup(group);
/* Application token. */
PORT_Assert(ss->xtnData.applicationToken.len == 0);
rv = ssl3_ConsumeNumberFromItem(&ptItem, &appTokenLen, 2);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
appTokenLen) == NULL) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
ss->xtnData.applicationToken.len = appTokenLen;
rv = ssl3_ConsumeFromItem(&ptItem, &appToken, appTokenLen);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
PORT_Memcpy(ss->xtnData.applicationToken.data, appToken, appTokenLen);
/* The remainder is the hash. */
if (ptItem.len != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
ptItem.data, ptItem.len);
if (rv != SECSuccess) {
return SECFailure;
}
/* And finally reinject the HRR. */
rv = tls13_ConstructHelloRetryRequest(ss, cipherSuite,
selectedGroup,
cookie, cookieLen,
&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_server_hello, 0,
SSL_BUFFER_BASE(&messageBuf),
SSL_BUFFER_LEN(&messageBuf));
sslBuffer_Clear(&messageBuf);
if (rv != SECSuccess) {
return SECFailure;
}
*previousCipherSuite = cipherSuite;
*previousGroup = selectedGroup;
return SECSuccess;
}

View file

@ -0,0 +1,25 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is PRIVATE to SSL.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __tls13hashstate_h_
#define __tls13hashstate_h_
#include "ssl.h"
#include "sslt.h"
#include "sslimpl.h"
SECStatus tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
const PRUint8 *appToken, unsigned int appTokenLen,
PRUint8 *buf, unsigned int *len, unsigned int maxlen);
SECStatus tls13_GetHrrCookieLength(sslSocket *ss, unsigned int *length);
SECStatus tls13_RecoverHashState(sslSocket *ss,
unsigned char *cookie,
unsigned int cookieLen,
ssl3CipherSuite *previousCipherSuite,
const sslNamedGroupDef **previousGroup);
#endif

View file

@ -134,10 +134,10 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
* Label, plus HandshakeHash. If it's ever to small, the code will abort.
*/
PRUint8 info[256];
PRUint8 *ptr = info;
unsigned int infoLen;
sslBuffer infoBuf = SSL_BUFFER(info);
PK11SymKey *derived;
const char *kLabelPrefix = "TLS 1.3, ";
SECStatus rv;
const char *kLabelPrefix = "tls13 ";
const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
if (handshakeHash) {
@ -170,29 +170,31 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
* - HkdfLabel.label is "TLS 1.3, " + Label
*
*/
infoLen = 2 + 1 + kLabelPrefixLen + labelLen + 1 + handshakeHashLen;
if (infoLen > sizeof(info)) {
PORT_Assert(0);
goto abort;
rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2);
if (rv != SECSuccess) {
return SECFailure;
}
ptr = ssl_EncodeUintX(keySize, 2, ptr);
ptr = ssl_EncodeUintX(labelLen + kLabelPrefixLen, 1, ptr);
PORT_Memcpy(ptr, kLabelPrefix, kLabelPrefixLen);
ptr += kLabelPrefixLen;
PORT_Memcpy(ptr, label, labelLen);
ptr += labelLen;
ptr = ssl_EncodeUintX(handshakeHashLen, 1, ptr);
if (handshakeHash) {
PORT_Memcpy(ptr, handshakeHash, handshakeHashLen);
ptr += handshakeHashLen;
rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_Append(&infoBuf, label, labelLen);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Assert((ptr - info) == infoLen);
params.bExtract = CK_FALSE;
params.bExpand = CK_TRUE;
params.pInfo = info;
params.ulInfoLen = infoLen;
params.pInfo = SSL_BUFFER_BASE(&infoBuf);
params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
paramsi.data = (unsigned char *)&params;
paramsi.len = sizeof(params);
@ -211,20 +213,17 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
char labelStr[100];
PORT_Memcpy(labelStr, label, labelLen);
labelStr[labelLen] = 0;
SSL_TRC(50, ("HKDF Expand: label=[TLS 1.3, ] + '%s',requested length=%d",
SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d",
labelStr, keySize));
}
PRINT_KEY(50, (NULL, "PRK", prk));
PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen));
PRINT_BUF(50, (NULL, "Info", info, infoLen));
PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf),
SSL_BUFFER_LEN(&infoBuf)));
PRINT_KEY(50, (NULL, "Derived key", derived));
#endif
return SECSuccess;
abort:
PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
return SECFailure;
}
SECStatus

View file

@ -0,0 +1,276 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Anti-replay measures for TLS 1.3.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nss.h" /* for NSS_RegisterShutdown */
#include "nssilock.h" /* for PZMonitor */
#include "pk11pub.h"
#include "prinit.h" /* for PR_CallOnce */
#include "prmon.h"
#include "prtime.h"
#include "secerr.h"
#include "ssl.h"
#include "sslbloom.h"
#include "sslimpl.h"
#include "tls13hkdf.h"
static struct {
/* Used to ensure that we only initialize the cleanup function once. */
PRCallOnceType init;
/* Used to serialize access to the filters. */
PZMonitor *lock;
/* The filters, use of which alternates. */
sslBloomFilter filters[2];
/* Which of the two filters is active (0 or 1). */
PRUint8 current;
/* The time that we will next update. */
PRTime nextUpdate;
/* The width of the window; i.e., the period of updates. */
PRTime window;
/* This key ensures that the bloom filter index is unpredictable. */
PK11SymKey *key;
} ssl_anti_replay;
/* Clear the current state and free any resources we allocated. The signature
* here is odd to allow this to be called during shutdown. */
static SECStatus
tls13_AntiReplayReset(void *appData, void *nssData)
{
if (ssl_anti_replay.key) {
PK11_FreeSymKey(ssl_anti_replay.key);
ssl_anti_replay.key = NULL;
}
if (ssl_anti_replay.lock) {
PZ_DestroyMonitor(ssl_anti_replay.lock);
ssl_anti_replay.lock = NULL;
}
sslBloom_Destroy(&ssl_anti_replay.filters[0]);
sslBloom_Destroy(&ssl_anti_replay.filters[1]);
return SECSuccess;
}
static PRStatus
tls13_AntiReplayInit(void)
{
SECStatus rv = NSS_RegisterShutdown(tls13_AntiReplayReset, NULL);
if (rv != SECSuccess) {
return PR_FAILURE;
}
return PR_SUCCESS;
}
static SECStatus
tls13_AntiReplayKeyGen()
{
PRUint8 buf[32];
SECItem keyItem = { siBuffer, buf, sizeof(buf) };
PK11SlotInfo *slot;
SECStatus rv;
slot = PK11_GetInternalSlot();
if (!slot) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = PK11_GenerateRandomOnSlot(slot, buf, sizeof(buf));
if (rv != SECSuccess) {
goto loser;
}
ssl_anti_replay.key = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256,
PK11_OriginUnwrap, CKA_DERIVE,
&keyItem, NULL);
if (!ssl_anti_replay.key) {
goto loser;
}
PK11_FreeSlot(slot);
return SECSuccess;
loser:
PK11_FreeSlot(slot);
return SECFailure;
}
/* Set a limit on the combination of number of hashes and bits in each hash. */
#define SSL_MAX_BLOOM_FILTER_SIZE 64
/*
* The structures created by this function can be called concurrently on
* multiple threads if the server is multi-threaded. A monitor is used to
* ensure that only one thread can access the structures that change over time,
* but no such guarantee is provided for configuration data.
*
* Functions that read from static configuration data depend on there being a
* memory barrier between the setup and use of this function.
*/
SECStatus
SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits)
{
SECStatus rv;
if (k == 0 || bits == 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((k * (bits + 7) / 8) > SSL_MAX_BLOOM_FILTER_SIZE) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (PR_SUCCESS != PR_CallOnce(&ssl_anti_replay.init,
tls13_AntiReplayInit)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
(void)tls13_AntiReplayReset(NULL, NULL);
ssl_anti_replay.lock = PZ_NewMonitor(nssILockSSL);
if (!ssl_anti_replay.lock) {
goto loser; /* Code already set. */
}
rv = tls13_AntiReplayKeyGen();
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
rv = sslBloom_Init(&ssl_anti_replay.filters[0], k, bits);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
rv = sslBloom_Init(&ssl_anti_replay.filters[1], k, bits);
if (rv != SECSuccess) {
goto loser; /* Code already set. */
}
/* When starting out, ensure that 0-RTT is not accepted until the window is
* updated. A ClientHello might have been accepted prior to a restart. */
sslBloom_Fill(&ssl_anti_replay.filters[1]);
ssl_anti_replay.current = 0;
ssl_anti_replay.nextUpdate = ssl_TimeUsec() + window;
ssl_anti_replay.window = window;
return SECSuccess;
loser:
(void)tls13_AntiReplayReset(NULL, NULL);
return SECFailure;
}
/* This is exposed to tests. Though it could, this doesn't take the lock on the
* basis that those tests use thread confinement. */
void
tls13_AntiReplayRollover(PRTime now)
{
ssl_anti_replay.current ^= 1;
ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window;
sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current);
}
static void
tls13_AntiReplayUpdate()
{
PRTime now;
PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ssl_anti_replay.lock);
now = ssl_TimeUsec();
if (now < ssl_anti_replay.nextUpdate) {
return;
}
tls13_AntiReplayRollover(now);
}
PRBool
tls13_InWindow(const sslSocket *ss, const sslSessionID *sid)
{
PRInt32 timeDelta;
/* Calculate the difference between the client's view of the age of the
* ticket (in |ss->xtnData.ticketAge|) and the server's view, which we now
* calculate. The result should be close to zero. timeDelta is signed to
* make the comparisons below easier. */
timeDelta = ss->xtnData.ticketAge -
((ssl_TimeUsec() - sid->creationTime) / PR_USEC_PER_MSEC);
/* Only allow the time delta to be at most half of our window. This is
* symmetrical, though it doesn't need to be; this assumes that clock errors
* on server and client will tend to cancel each other out.
*
* There are two anti-replay filters that roll over each window. In the
* worst case, immediately after a rollover of the filters, we only have a
* single window worth of recorded 0-RTT attempts. Thus, the period in
* which we can accept 0-RTT is at most one window wide. This uses PR_ABS()
* and half the window so that the first attempt can be up to half a window
* early and then replays will be caught until the attempts are half a
* window late.
*
* For example, a 0-RTT attempt arrives early, but near the end of window 1.
* The attempt is then recorded in window 1. Rollover to window 2 could
* occur immediately afterwards. Window 1 is still checked for new 0-RTT
* attempts for the remainder of window 2. Therefore, attempts to replay
* are detected because the value is recorded in window 1. When rollover
* occurs again, window 1 is erased and window 3 instated. If we allowed an
* attempt to be late by more than half a window, then this check would not
* prevent the same 0-RTT attempt from being accepted during window 1 and
* later window 3.
*/
return PR_ABS(timeDelta) < (ssl_anti_replay.window / 2);
}
/* Checks for a duplicate in the two filters we have. Performs maintenance on
* the filters as a side-effect. This only detects a probable replay, it's
* possible that this will return true when the 0-RTT attempt is not genuinely a
* replay. In that case, we reject 0-RTT unnecessarily, but that's OK because
* no client expects 0-RTT to work every time. */
PRBool
tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid)
{
PRBool replay;
unsigned int size;
PRUint8 index;
SECStatus rv;
static const char *label = "tls13 anti-replay";
PRUint8 buf[SSL_MAX_BLOOM_FILTER_SIZE];
/* If SSL_SetupAntiReplay hasn't been called, then treat all attempts at
* 0-RTT as a replay. */
if (!ssl_anti_replay.init.initialized) {
return PR_TRUE;
}
if (!tls13_InWindow(ss, sid)) {
return PR_TRUE;
}
size = ssl_anti_replay.filters[0].k *
(ssl_anti_replay.filters[0].bits + 7) / 8;
PORT_Assert(size <= SSL_MAX_BLOOM_FILTER_SIZE);
rv = tls13_HkdfExpandLabelRaw(ssl_anti_replay.key, ssl_hash_sha256,
ss->xtnData.pskBinder.data,
ss->xtnData.pskBinder.len,
label, strlen(label),
buf, size);
if (rv != SECSuccess) {
return PR_TRUE;
}
PZ_EnterMonitor(ssl_anti_replay.lock);
tls13_AntiReplayUpdate();
index = ssl_anti_replay.current;
replay = sslBloom_Add(&ssl_anti_replay.filters[index], buf);
if (!replay) {
replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1],
buf);
}
PZ_ExitMonitor(ssl_anti_replay.lock);
return replay;
}