mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-09 16:57:30 +09:00
Update NSS to 3.35-RTM
This commit is contained in:
parent
fe49ad404e
commit
66dd670b60
388 changed files with 39075 additions and 20752 deletions
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
457
security/nss/lib/ssl/dtls13con.c
Normal file
457
security/nss/lib/ssl/dtls13con.c
Normal 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);
|
||||
}
|
||||
29
security/nss/lib/ssl/dtls13con.h
Normal file
29
security/nss/lib/ssl/dtls13con.h
Normal 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
48
security/nss/lib/ssl/dtlscon.h
Normal file
48
security/nss/lib/ssl/dtlscon.h
Normal 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
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
'preenc.h',
|
||||
'ssl.h',
|
||||
'sslerr.h',
|
||||
'sslexp.h',
|
||||
'sslproto.h',
|
||||
'sslt.h'
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -234,3 +234,9 @@ SSL_AlertSentCallback;
|
|||
;+ local:
|
||||
;+*;
|
||||
;+};
|
||||
;+NSS_3.33 { # NSS 3.33 release
|
||||
;+ global:
|
||||
SSL_GetExperimentalAPI;
|
||||
;+ local:
|
||||
;+*;
|
||||
;+};
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
94
security/nss/lib/ssl/sslbloom.c
Normal file
94
security/nss/lib/ssl/sslbloom.c
Normal 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));
|
||||
}
|
||||
32
security/nss/lib/ssl/sslbloom.h
Normal file
32
security/nss/lib/ssl/sslbloom.h
Normal 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_ */
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
296
security/nss/lib/ssl/sslencode.c
Normal file
296
security/nss/lib/ssl/sslencode.c
Normal 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);
|
||||
}
|
||||
69
security/nss/lib/ssl/sslencode.h
Normal file
69
security/nss/lib/ssl/sslencode.h
Normal 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_ */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
358
security/nss/lib/ssl/sslexp.h
Normal file
358
security/nss/lib/ssl/sslexp.h
Normal 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_ */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
273
security/nss/lib/ssl/sslspec.c
Normal file
273
security/nss/lib/ssl/sslspec.c
Normal 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);
|
||||
}
|
||||
}
|
||||
194
security/nss/lib/ssl/sslspec.h
Normal file
194
security/nss/lib/ssl/sslspec.h
Normal 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_ */
|
||||
|
|
@ -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
|
|
@ -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_ */
|
||||
|
|
|
|||
28
security/nss/lib/ssl/tls13err.h
Normal file
28
security/nss/lib/ssl/tls13err.h
Normal 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
|
|
@ -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
|
||||
|
|
|
|||
181
security/nss/lib/ssl/tls13hashstate.c
Normal file
181
security/nss/lib/ssl/tls13hashstate.c
Normal 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;
|
||||
}
|
||||
25
security/nss/lib/ssl/tls13hashstate.h
Normal file
25
security/nss/lib/ssl/tls13hashstate.h
Normal 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
|
||||
|
|
@ -134,10 +134,10 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
|
|||
* Label, plus HandshakeHash. If it's ever to small, the code will abort.
|
||||
*/
|
||||
PRUint8 info[256];
|
||||
PRUint8 *ptr = info;
|
||||
unsigned int infoLen;
|
||||
sslBuffer infoBuf = SSL_BUFFER(info);
|
||||
PK11SymKey *derived;
|
||||
const char *kLabelPrefix = "TLS 1.3, ";
|
||||
SECStatus rv;
|
||||
const char *kLabelPrefix = "tls13 ";
|
||||
const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
|
||||
|
||||
if (handshakeHash) {
|
||||
|
|
@ -170,29 +170,31 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
|
|||
* - HkdfLabel.label is "TLS 1.3, " + Label
|
||||
*
|
||||
*/
|
||||
infoLen = 2 + 1 + kLabelPrefixLen + labelLen + 1 + handshakeHashLen;
|
||||
if (infoLen > sizeof(info)) {
|
||||
PORT_Assert(0);
|
||||
goto abort;
|
||||
rv = sslBuffer_AppendNumber(&infoBuf, keySize, 2);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ptr = ssl_EncodeUintX(keySize, 2, ptr);
|
||||
ptr = ssl_EncodeUintX(labelLen + kLabelPrefixLen, 1, ptr);
|
||||
PORT_Memcpy(ptr, kLabelPrefix, kLabelPrefixLen);
|
||||
ptr += kLabelPrefixLen;
|
||||
PORT_Memcpy(ptr, label, labelLen);
|
||||
ptr += labelLen;
|
||||
ptr = ssl_EncodeUintX(handshakeHashLen, 1, ptr);
|
||||
if (handshakeHash) {
|
||||
PORT_Memcpy(ptr, handshakeHash, handshakeHashLen);
|
||||
ptr += handshakeHashLen;
|
||||
rv = sslBuffer_AppendNumber(&infoBuf, labelLen + kLabelPrefixLen, 1);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
rv = sslBuffer_Append(&infoBuf, kLabelPrefix, kLabelPrefixLen);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
rv = sslBuffer_Append(&infoBuf, label, labelLen);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
rv = sslBuffer_AppendVariable(&infoBuf, handshakeHash, handshakeHashLen, 1);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
PORT_Assert((ptr - info) == infoLen);
|
||||
|
||||
params.bExtract = CK_FALSE;
|
||||
params.bExpand = CK_TRUE;
|
||||
params.pInfo = info;
|
||||
params.ulInfoLen = infoLen;
|
||||
params.pInfo = SSL_BUFFER_BASE(&infoBuf);
|
||||
params.ulInfoLen = SSL_BUFFER_LEN(&infoBuf);
|
||||
paramsi.data = (unsigned char *)¶ms;
|
||||
paramsi.len = sizeof(params);
|
||||
|
||||
|
|
@ -211,20 +213,17 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, SSLHashType baseHash,
|
|||
char labelStr[100];
|
||||
PORT_Memcpy(labelStr, label, labelLen);
|
||||
labelStr[labelLen] = 0;
|
||||
SSL_TRC(50, ("HKDF Expand: label=[TLS 1.3, ] + '%s',requested length=%d",
|
||||
SSL_TRC(50, ("HKDF Expand: label='tls13 %s',requested length=%d",
|
||||
labelStr, keySize));
|
||||
}
|
||||
PRINT_KEY(50, (NULL, "PRK", prk));
|
||||
PRINT_BUF(50, (NULL, "Hash", handshakeHash, handshakeHashLen));
|
||||
PRINT_BUF(50, (NULL, "Info", info, infoLen));
|
||||
PRINT_BUF(50, (NULL, "Info", SSL_BUFFER_BASE(&infoBuf),
|
||||
SSL_BUFFER_LEN(&infoBuf)));
|
||||
PRINT_KEY(50, (NULL, "Derived key", derived));
|
||||
#endif
|
||||
|
||||
return SECSuccess;
|
||||
|
||||
abort:
|
||||
PORT_SetError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
|
|
|
|||
276
security/nss/lib/ssl/tls13replay.c
Normal file
276
security/nss/lib/ssl/tls13replay.c
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue