| Index: net/third_party/nss/ssl/dtlscon.c
|
| diff --git a/net/third_party/nss/ssl/dtlscon.c b/net/third_party/nss/ssl/dtlscon.c
|
| index 1b21107094e8426c29b81662cbe32f7e1c613a70..35d995e91756f353eb67479c29348c21e09689c5 100644
|
| --- a/net/third_party/nss/ssl/dtlscon.c
|
| +++ b/net/third_party/nss/ssl/dtlscon.c
|
| @@ -11,7 +11,7 @@
|
| #include "sslproto.h"
|
|
|
| #ifndef PR_ARRAY_SIZE
|
| -#define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
| +#define PR_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
| #endif
|
|
|
| static SECStatus dtls_TransmitMessageFlight(sslSocket *ss);
|
| @@ -20,10 +20,10 @@ static SECStatus dtls_SendSavedWriteData(sslSocket *ss);
|
|
|
| /* -28 adjusts for the IP/UDP header */
|
| static const PRUint16 COMMON_MTU_VALUES[] = {
|
| - 1500 - 28, /* Ethernet MTU */
|
| - 1280 - 28, /* IPv6 minimum MTU */
|
| - 576 - 28, /* Common assumption */
|
| - 256 - 28 /* We're in serious trouble now */
|
| + 1500 - 28, /* Ethernet MTU */
|
| + 1280 - 28, /* IPv6 minimum MTU */
|
| + 576 - 28, /* Common assumption */
|
| + 256 - 28 /* We're in serious trouble now */
|
| };
|
|
|
| #define DTLS_COOKIE_BYTES 32
|
| @@ -86,6 +86,11 @@ dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv)
|
| if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) {
|
| return SSL_LIBRARY_VERSION_TLS_1_1;
|
| }
|
| + /* Handle the skipped version of DTLS 1.1 by returning
|
| + * an error. */
|
| + if (dtlsv == ((~0x0101) & 0xffff)) {
|
| + return 0;
|
| + }
|
| if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_2_WIRE) {
|
| return SSL_LIBRARY_VERSION_TLS_1_2;
|
| }
|
| @@ -94,14 +99,14 @@ dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv)
|
| }
|
|
|
| /* Return a fictional higher version than we know of */
|
| - return SSL_LIBRARY_VERSION_TLS_1_2 + 1;
|
| + return SSL_LIBRARY_VERSION_MAX_SUPPORTED + 1;
|
| }
|
|
|
| /* On this socket, Disable non-DTLS cipher suites in the argument's list */
|
| SECStatus
|
| -ssl3_DisableNonDTLSSuites(sslSocket * ss)
|
| +ssl3_DisableNonDTLSSuites(sslSocket *ss)
|
| {
|
| - const ssl3CipherSuite * suite;
|
| + const ssl3CipherSuite *suite;
|
|
|
| for (suite = nonDTLSSuites; *suite; ++suite) {
|
| PORT_CheckSuccess(ssl3_CipherPrefSet(ss, *suite, PR_FALSE));
|
| @@ -185,8 +190,8 @@ dtls_FreeHandshakeMessages(PRCList *list)
|
| * the state of reassembly (i.e., whether one is in progress). That
|
| * is carried in recvdHighWater and recvdFragments.
|
| */
|
| -#define OFFSET_BYTE(o) (o/8)
|
| -#define OFFSET_MASK(o) (1 << (o%8))
|
| +#define OFFSET_BYTE(o) (o / 8)
|
| +#define OFFSET_MASK(o) (1 << (o % 8))
|
|
|
| SECStatus
|
| dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| @@ -224,7 +229,7 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| fragment_offset = (buf.buf[6] << 16) | (buf.buf[7] << 8) | buf.buf[8];
|
| fragment_length = (buf.buf[9] << 16) | (buf.buf[10] << 8) | buf.buf[11];
|
|
|
| -#define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */
|
| +#define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */
|
| if (message_length > MAX_HANDSHAKE_MSG_LEN) {
|
| (void)ssl3_DecodeError(ss);
|
| PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
| @@ -258,9 +263,9 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| * If it's the complete next message we accept it right away.
|
| * This is the common case for short messages
|
| */
|
| - if ((message_seq == ss->ssl3.hs.recvMessageSeq)
|
| - && (fragment_offset == 0)
|
| - && (fragment_length == message_length)) {
|
| + if ((message_seq == ss->ssl3.hs.recvMessageSeq) &&
|
| + (fragment_offset == 0) &&
|
| + (fragment_length == message_length)) {
|
| /* Complete next message. Process immediately */
|
| ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
|
| ss->ssl3.hs.msg_len = message_length;
|
| @@ -289,7 +294,7 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| if (ss->ssl3.hs.rtTimerCb == NULL) {
|
| /* Ignore */
|
| } else if (ss->ssl3.hs.rtTimerCb ==
|
| - dtls_RetransmitTimerExpiredCb) {
|
| + dtls_RetransmitTimerExpiredCb) {
|
| SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected",
|
| SSL_GETPID(), ss->fd));
|
| /* Check to see if we retransmitted recently. If so,
|
| @@ -299,23 +304,23 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| */
|
| if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) >
|
| (ss->ssl3.hs.rtTimeoutMs / 4)) {
|
| - SSL_TRC(30,
|
| - ("%d: SSL3[%d]: Shortcutting retransmit timer",
|
| - SSL_GETPID(), ss->fd));
|
| -
|
| - /* Cancel the timer and call the CB,
|
| - * which re-arms the timer */
|
| - dtls_CancelTimer(ss);
|
| - dtls_RetransmitTimerExpiredCb(ss);
|
| - rv = SECSuccess;
|
| - break;
|
| - } else {
|
| - SSL_TRC(30,
|
| - ("%d: SSL3[%d]: We just retransmitted. Ignoring.",
|
| - SSL_GETPID(), ss->fd));
|
| - rv = SECSuccess;
|
| - break;
|
| - }
|
| + SSL_TRC(30,
|
| + ("%d: SSL3[%d]: Shortcutting retransmit timer",
|
| + SSL_GETPID(), ss->fd));
|
| +
|
| + /* Cancel the timer and call the CB,
|
| + * which re-arms the timer */
|
| + dtls_CancelTimer(ss);
|
| + dtls_RetransmitTimerExpiredCb(ss);
|
| + rv = SECSuccess;
|
| + break;
|
| + } else {
|
| + SSL_TRC(30,
|
| + ("%d: SSL3[%d]: We just retransmitted. Ignoring.",
|
| + SSL_GETPID(), ss->fd));
|
| + rv = SECSuccess;
|
| + break;
|
| + }
|
| } else if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb) {
|
| /* Retransmit the messages and re-arm the timer
|
| * Note that we are not backing off the timer here.
|
| @@ -450,7 +455,7 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| buf.len -= fragment_length;
|
| }
|
|
|
| - origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
|
| + origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
|
|
|
| /* XXX OK for now. In future handle rv == SECWouldBlock safely in order
|
| * to deal with asynchronous certificate verification */
|
| @@ -463,8 +468,9 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| * dtls_StageHandshakeMessage()
|
| * ssl3_SendChangeCipherSpecs()
|
| */
|
| -SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
|
| - const SSL3Opaque *pIn, PRInt32 nIn)
|
| +SECStatus
|
| +dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
|
| + const SSL3Opaque *pIn, PRInt32 nIn)
|
| {
|
| SECStatus rv = SECSuccess;
|
| DTLSQueuedMessage *msg = NULL;
|
| @@ -634,7 +640,7 @@ dtls_TransmitMessageFlight(sslSocket *ss)
|
| sent = ssl3_SendRecord(ss, msg->epoch, msg->type,
|
| msg->data, msg->len,
|
| ssl_SEND_FLAG_FORCE_INTO_BUFFER |
|
| - ssl_SEND_FLAG_USE_EPOCH);
|
| + ssl_SEND_FLAG_USE_EPOCH);
|
| if (sent != msg->len) {
|
| rv = SECFailure;
|
| if (sent != -1) {
|
| @@ -694,12 +700,12 @@ dtls_TransmitMessageFlight(sslSocket *ss)
|
| /* Offset */
|
| fragment[6] = (fragment_offset >> 16) & 0xff;
|
| fragment[7] = (fragment_offset >> 8) & 0xff;
|
| - fragment[8] = (fragment_offset) & 0xff;
|
| + fragment[8] = (fragment_offset)&0xff;
|
|
|
| /* Fragment length */
|
| fragment[9] = (fragment_len >> 16) & 0xff;
|
| fragment[10] = (fragment_len >> 8) & 0xff;
|
| - fragment[11] = (fragment_len) & 0xff;
|
| + fragment[11] = (fragment_len)&0xff;
|
|
|
| PORT_Memcpy(fragment + 12, content + fragment_offset,
|
| fragment_len);
|
| @@ -711,7 +717,7 @@ dtls_TransmitMessageFlight(sslSocket *ss)
|
| sent = ssl3_SendRecord(ss, msg->epoch, msg->type,
|
| fragment, fragment_len + 12,
|
| ssl_SEND_FLAG_FORCE_INTO_BUFFER |
|
| - ssl_SEND_FLAG_USE_EPOCH);
|
| + ssl_SEND_FLAG_USE_EPOCH);
|
| if (sent != (fragment_len + 12)) {
|
| rv = SECFailure;
|
| if (sent != -1) {
|
| @@ -747,8 +753,8 @@ dtls_TransmitMessageFlight(sslSocket *ss)
|
| *
|
| * Called from dtls_TransmitMessageFlight()
|
| */
|
| -static
|
| -SECStatus dtls_SendSavedWriteData(sslSocket *ss)
|
| +static SECStatus
|
| +dtls_SendSavedWriteData(sslSocket *ss)
|
| {
|
| PRInt32 sent;
|
|
|
| @@ -779,18 +785,18 @@ SECStatus dtls_SendSavedWriteData(sslSocket *ss)
|
| * Called from ssl3_SendRecord()
|
| */
|
| SECStatus
|
| -dtls_CompressMACEncryptRecord(sslSocket * ss,
|
| - DTLSEpoch epoch,
|
| - PRBool use_epoch,
|
| - SSL3ContentType type,
|
| - const SSL3Opaque * pIn,
|
| - PRUint32 contentLen,
|
| - sslBuffer * wrBuf)
|
| +dtls_CompressMACEncryptRecord(sslSocket *ss,
|
| + DTLSEpoch epoch,
|
| + PRBool use_epoch,
|
| + SSL3ContentType type,
|
| + const SSL3Opaque *pIn,
|
| + PRUint32 contentLen,
|
| + sslBuffer *wrBuf)
|
| {
|
| SECStatus rv = SECFailure;
|
| - ssl3CipherSpec * cwSpec;
|
| + ssl3CipherSpec *cwSpec;
|
|
|
| - ssl_GetSpecReadLock(ss); /********************************/
|
| + ssl_GetSpecReadLock(ss); /********************************/
|
|
|
| /* The reason for this switch-hitting code is that we might have
|
| * a flight of records spanning an epoch boundary, e.g.,
|
| @@ -814,9 +820,13 @@ dtls_CompressMACEncryptRecord(sslSocket * ss,
|
| }
|
|
|
| if (cwSpec) {
|
| - rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE,
|
| - PR_FALSE, type, pIn, contentLen,
|
| - wrBuf);
|
| + if (ss->ssl3.cwSpec->version < SSL_LIBRARY_VERSION_TLS_1_3) {
|
| + rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE,
|
| + PR_FALSE, type, pIn, contentLen,
|
| + wrBuf);
|
| + } else {
|
| + rv = tls13_ProtectRecord(ss, type, pIn, contentLen, wrBuf);
|
| + }
|
| } else {
|
| PR_NOT_REACHED("Couldn't find a cipher spec matching epoch");
|
| PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| @@ -956,7 +966,7 @@ dtls_SetMTU(sslSocket *ss, PRUint16 advertised)
|
| }
|
|
|
| /* Fallback */
|
| - ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES)-1];
|
| + ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES) - 1];
|
| SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu));
|
| }
|
|
|
| @@ -967,27 +977,27 @@ dtls_SetMTU(sslSocket *ss, PRUint16 advertised)
|
| SECStatus
|
| dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| {
|
| - int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST;
|
| - SECStatus rv;
|
| - PRInt32 temp;
|
| - SECItem cookie = {siBuffer, NULL, 0};
|
| - SSL3AlertDescription desc = illegal_parameter;
|
| + int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST;
|
| + SECStatus rv;
|
| + PRInt32 temp;
|
| + SECItem cookie = { siBuffer, NULL, 0 };
|
| + SSL3AlertDescription desc = illegal_parameter;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake",
|
| - SSL_GETPID(), ss->fd));
|
| + SSL_GETPID(), ss->fd));
|
| PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
|
| PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
|
|
| if (ss->ssl3.hs.ws != wait_server_hello) {
|
| errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST;
|
| - desc = unexpected_message;
|
| + desc = unexpected_message;
|
| goto alert_loser;
|
| }
|
|
|
| /* The version */
|
| temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
|
| if (temp < 0) {
|
| - goto loser; /* alert has been sent */
|
| + goto loser; /* alert has been sent */
|
| }
|
|
|
| if (temp != SSL_LIBRARY_VERSION_DTLS_1_0_WIRE &&
|
| @@ -998,23 +1008,22 @@ dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| /* The cookie */
|
| rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length);
|
| if (rv != SECSuccess) {
|
| - goto loser; /* alert has been sent */
|
| + goto loser; /* alert has been sent */
|
| }
|
| if (cookie.len > DTLS_COOKIE_BYTES) {
|
| desc = decode_error;
|
| - goto alert_loser; /* malformed. */
|
| + goto alert_loser; /* malformed. */
|
| }
|
|
|
| PORT_Memcpy(ss->ssl3.hs.cookie, cookie.data, cookie.len);
|
| ss->ssl3.hs.cookieLen = cookie.len;
|
|
|
| -
|
| - ssl_GetXmitBufLock(ss); /*******************************/
|
| + ssl_GetXmitBufLock(ss); /*******************************/
|
|
|
| /* Now re-send the client hello */
|
| rv = ssl3_SendClientHello(ss, PR_TRUE);
|
|
|
| - ssl_ReleaseXmitBufLock(ss); /*******************************/
|
| + ssl_ReleaseXmitBufLock(ss); /*******************************/
|
|
|
| if (rv == SECSuccess)
|
| return rv;
|
| @@ -1023,7 +1032,7 @@ alert_loser:
|
| (void)SSL3_SendAlert(ss, alert_fatal, desc);
|
|
|
| loser:
|
| - errCode = ssl_MapLowLevelError(errCode);
|
| + ssl_MapLowLevelError(errCode);
|
| return SECFailure;
|
| }
|
|
|
| @@ -1047,10 +1056,10 @@ dtls_InitRecvdRecords(DTLSRecvdRecords *records)
|
| * 0 -- not received yet
|
| * 1 -- replay
|
| *
|
| - * Called from: dtls_HandleRecord()
|
| + * Called from: ssl3_HandleRecord()
|
| */
|
| int
|
| -dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
|
| +dtls_RecordGetRecvd(const DTLSRecvdRecords *records, PRUint64 seq)
|
| {
|
| PRUint64 offset;
|
|
|
| @@ -1118,7 +1127,7 @@ dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
|
| SECStatus
|
| DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout)
|
| {
|
| - sslSocket * ss = NULL;
|
| + sslSocket *ss = NULL;
|
| PRIntervalTime elapsed;
|
| PRIntervalTime desired;
|
|
|
| @@ -1144,3 +1153,43 @@ DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout)
|
|
|
| return SECSuccess;
|
| }
|
| +
|
| +/*
|
| + * DTLS relevance checks:
|
| + * Note that this code currently ignores all out-of-epoch packets,
|
| + * which means we lose some in the case of rehandshake +
|
| + * loss/reordering. Since DTLS is explicitly unreliable, this
|
| + * seems like a good tradeoff for implementation effort and is
|
| + * consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1.
|
| + *
|
| + * If the packet is not relevant, this function returns PR_FALSE.
|
| + * If the packet is relevant, this function returns PR_TRUE
|
| + * and sets |*seqNum| to the packet sequence number.
|
| + */
|
| +PRBool
|
| +dtls_IsRelevant(sslSocket *ss, const ssl3CipherSpec *crSpec,
|
| + const SSL3Ciphertext *cText, PRUint64 *seqNum)
|
| +{
|
| + DTLSEpoch epoch = cText->seq_num.high >> 16;
|
| + PRUint64 dtls_seq_num;
|
| +
|
| + if (crSpec->epoch != epoch) {
|
| + SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, received packet "
|
| + "from irrelevant epoch %d",
|
| + SSL_GETPID(), ss->fd, epoch));
|
| + return PR_FALSE;
|
| + }
|
| +
|
| + dtls_seq_num = (((PRUint64)(cText->seq_num.high & 0xffff)) << 32) |
|
| + ((PRUint64)cText->seq_num.low);
|
| +
|
| + if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) {
|
| + SSL_DBG(("%d: SSL3[%d]: dtls_IsRelevant, rejecting "
|
| + "potentially replayed packet",
|
| + SSL_GETPID(), ss->fd));
|
| + return PR_FALSE;
|
| + }
|
| +
|
| + *seqNum = dtls_seq_num;
|
| + return PR_TRUE;
|
| +}
|
|
|