| Index: net/third_party/nss/patches/dtls.patch
|
| ===================================================================
|
| --- net/third_party/nss/patches/dtls.patch (revision 0)
|
| +++ net/third_party/nss/patches/dtls.patch (revision 0)
|
| @@ -0,0 +1,3321 @@
|
| +Index: net/third_party/nss/ssl/SSLerrs.h
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/SSLerrs.h (revision 127709)
|
| ++++ net/third_party/nss/ssl/SSLerrs.h (working copy)
|
| +@@ -423,3 +423,9 @@
|
| +
|
| + ER3(SSL_ERROR_RX_UNEXPECTED_CERT_STATUS, (SSL_ERROR_BASE + 121),
|
| + "SSL received an unexpected Certificate Status handshake message.")
|
| ++
|
| ++ER3(SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 122),
|
| ++"SSL received a malformed Hello Verify Request handshake message.")
|
| ++
|
| ++ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 123),
|
| ++"SSL received an unexpected Hello Verify Request handshake message.")
|
| +Index: net/third_party/nss/ssl/ssl.h
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/ssl.h (revision 127709)
|
| ++++ net/third_party/nss/ssl/ssl.h (working copy)
|
| +@@ -80,6 +80,12 @@
|
| + SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
|
| +
|
| + /*
|
| ++** Imports fd into DTLS, returning a new socket. Copies DTLS configuration
|
| ++** from model.
|
| ++*/
|
| ++SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
|
| ++
|
| ++/*
|
| + ** Enable/disable an ssl mode
|
| + **
|
| + ** SSL_SECURITY:
|
| +@@ -942,6 +948,14 @@
|
| + PRBool *last_handshake_resumed);
|
| +
|
| + /*
|
| ++** How long should we wait before retransmitting the next flight of
|
| ++** the DTLS handshake? Returns SECFailure if not DTLS or not in a
|
| ++** handshake.
|
| ++*/
|
| ++SSL_IMPORT SECStatus DTLS_GetTimeout(PRFileDesc *socket,
|
| ++ PRIntervalTime *timeout);
|
| ++
|
| ++/*
|
| + * Return a boolean that indicates whether the underlying library
|
| + * will perform as the caller expects.
|
| + *
|
| +Index: net/third_party/nss/ssl/ssl3gthr.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/ssl3gthr.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/ssl3gthr.c (working copy)
|
| +@@ -50,7 +50,7 @@
|
| + *
|
| + * returns 1 if received a complete SSL3 record.
|
| + * returns 0 if recv returns EOF
|
| +- * returns -1 if recv returns <0
|
| ++ * returns -1 if recv returns < 0
|
| + * (The error value may have already been set to PR_WOULD_BLOCK_ERROR)
|
| + *
|
| + * Caller must hold the recv buf lock.
|
| +@@ -59,7 +59,8 @@
|
| + * GS_HEADER: waiting for the 5-byte SSL3 record header to come in.
|
| + * GS_DATA: waiting for the body of the SSL3 record to come in.
|
| + *
|
| +- * This loop returns when either (a) an error or EOF occurs,
|
| ++ * This loop returns when either
|
| ++ * (a) an error or EOF occurs,
|
| + * (b) PR_WOULD_BLOCK_ERROR,
|
| + * (c) data (entire SSL3 record) has been received.
|
| + */
|
| +@@ -167,6 +168,125 @@
|
| + return rv;
|
| + }
|
| +
|
| ++/*
|
| ++ * Read in an entire DTLS record.
|
| ++ *
|
| ++ * Blocks here for blocking sockets, otherwise returns -1 with
|
| ++ * PR_WOULD_BLOCK_ERROR when socket would block.
|
| ++ *
|
| ++ * This is simpler than SSL because we are reading on a datagram socket
|
| ++ * and datagrams must contain >=1 complete records.
|
| ++ *
|
| ++ * returns 1 if received a complete DTLS record.
|
| ++ * returns 0 if recv returns EOF
|
| ++ * returns -1 if recv returns < 0
|
| ++ * (The error value may have already been set to PR_WOULD_BLOCK_ERROR)
|
| ++ *
|
| ++ * Caller must hold the recv buf lock.
|
| ++ *
|
| ++ * This loop returns when either
|
| ++ * (a) an error or EOF occurs,
|
| ++ * (b) PR_WOULD_BLOCK_ERROR,
|
| ++ * (c) data (entire DTLS record) has been received.
|
| ++ */
|
| ++static int
|
| ++dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
|
| ++{
|
| ++ int nb;
|
| ++ int err;
|
| ++ int rv = 1;
|
| ++
|
| ++ SSL_TRC(30, ("dtls_GatherData"));
|
| ++
|
| ++ PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| ++
|
| ++ gs->state = GS_HEADER;
|
| ++ gs->offset = 0;
|
| ++
|
| ++ if (gs->dtlsPacketOffset == gs->dtlsPacket.len) { /* No data left */
|
| ++ gs->dtlsPacketOffset = 0;
|
| ++ gs->dtlsPacket.len = 0;
|
| ++
|
| ++ /* Resize to the maximum possible size so we can fit a full datagram */
|
| ++ /* This is the max fragment length for an encrypted fragment
|
| ++ ** plus the size of the record header.
|
| ++ ** This magic constant is copied from ssl3_GatherData, with 5 changed
|
| ++ ** to 13 (the size of the record header).
|
| ++ */
|
| ++ if (gs->dtlsPacket.space < MAX_FRAGMENT_LENGTH + 2048 + 13) {
|
| ++ err = sslBuffer_Grow(&gs->dtlsPacket,
|
| ++ MAX_FRAGMENT_LENGTH + 2048 + 13);
|
| ++ if (err) { /* realloc has set error code to no mem. */
|
| ++ return err;
|
| ++ }
|
| ++ }
|
| ++
|
| ++ /* recv() needs to read a full datagram at a time */
|
| ++ nb = ssl_DefRecv(ss, gs->dtlsPacket.buf, gs->dtlsPacket.space, flags);
|
| ++
|
| ++ if (nb > 0) {
|
| ++ PRINT_BUF(60, (ss, "raw gather data:", gs->dtlsPacket.buf, nb));
|
| ++ } else if (nb == 0) {
|
| ++ /* EOF */
|
| ++ SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd));
|
| ++ rv = 0;
|
| ++ return rv;
|
| ++ } else /* if (nb < 0) */ {
|
| ++ SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd,
|
| ++ PR_GetError()));
|
| ++ rv = SECFailure;
|
| ++ return rv;
|
| ++ }
|
| ++
|
| ++ gs->dtlsPacket.len = nb;
|
| ++ }
|
| ++
|
| ++ /* At this point we should have >=1 complete records lined up in
|
| ++ * dtlsPacket. Read off the header.
|
| ++ */
|
| ++ if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < 13) {
|
| ++ SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet "
|
| ++ "too short to contain header", SSL_GETPID(), ss->fd));
|
| ++ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
|
| ++ gs->dtlsPacketOffset = 0;
|
| ++ gs->dtlsPacket.len = 0;
|
| ++ rv = SECFailure;
|
| ++ return rv;
|
| ++ }
|
| ++ memcpy(gs->hdr, gs->dtlsPacket.buf + gs->dtlsPacketOffset, 13);
|
| ++ gs->dtlsPacketOffset += 13;
|
| ++
|
| ++ /* Have received SSL3 record header in gs->hdr. */
|
| ++ gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12];
|
| ++
|
| ++ if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < gs->remainder) {
|
| ++ SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet too short "
|
| ++ "to contain rest of body", SSL_GETPID(), ss->fd));
|
| ++ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
|
| ++ gs->dtlsPacketOffset = 0;
|
| ++ gs->dtlsPacket.len = 0;
|
| ++ rv = SECFailure;
|
| ++ return rv;
|
| ++ }
|
| ++
|
| ++ /* OK, we have at least one complete packet, copy into inbuf */
|
| ++ if (gs->remainder > gs->inbuf.space) {
|
| ++ err = sslBuffer_Grow(&gs->inbuf, gs->remainder);
|
| ++ if (err) { /* realloc has set error code to no mem. */
|
| ++ return err;
|
| ++ }
|
| ++ }
|
| ++
|
| ++ memcpy(gs->inbuf.buf, gs->dtlsPacket.buf + gs->dtlsPacketOffset,
|
| ++ gs->remainder);
|
| ++ gs->inbuf.len = gs->remainder;
|
| ++ gs->offset = gs->remainder;
|
| ++ gs->dtlsPacketOffset += gs->remainder;
|
| ++ gs->state = GS_INIT;
|
| ++
|
| ++ return 1;
|
| ++}
|
| ++
|
| + /* Gather in a record and when complete, Handle that record.
|
| + * Repeat this until the handshake is complete,
|
| + * or until application data is available.
|
| +@@ -190,6 +310,8 @@
|
| + int rv;
|
| + PRBool canFalseStart = PR_FALSE;
|
| +
|
| ++ SSL_TRC(30, ("ssl3_GatherCompleteHandshake"));
|
| ++
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| + do {
|
| + /* Without this, we may end up wrongly reporting
|
| +@@ -224,7 +346,24 @@
|
| + rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
|
| + } else {
|
| + /* bring in the next sslv3 record. */
|
| +- rv = ssl3_GatherData(ss, &ss->gs, flags);
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ rv = ssl3_GatherData(ss, &ss->gs, flags);
|
| ++ } else {
|
| ++ rv = dtls_GatherData(ss, &ss->gs, flags);
|
| ++
|
| ++ /* If we got a would block error, that means that no data was
|
| ++ * available, so we check the timer to see if it's time to
|
| ++ * retransmit */
|
| ++ if (rv == SECFailure &&
|
| ++ (PORT_GetError() == PR_WOULD_BLOCK_ERROR)) {
|
| ++ ssl_GetSSL3HandshakeLock(ss);
|
| ++ dtls_CheckTimer(ss);
|
| ++ ssl_ReleaseSSL3HandshakeLock(ss);
|
| ++ /* Restore the error in case something succeeded */
|
| ++ PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
| ++ }
|
| ++ }
|
| ++
|
| + if (rv <= 0) {
|
| + return rv;
|
| + }
|
| +@@ -236,6 +375,20 @@
|
| + */
|
| + cText.type = (SSL3ContentType)ss->gs.hdr[0];
|
| + cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
|
| ++
|
| ++ if (IS_DTLS(ss)) {
|
| ++ int i;
|
| ++
|
| ++ cText.version = dtls_DTLSVersionToTLSVersion(cText.version);
|
| ++ /* DTLS sequence number */
|
| ++ cText.seq_num.high = 0; cText.seq_num.low = 0;
|
| ++ for (i = 0; i < 4; i++) {
|
| ++ cText.seq_num.high <<= 8; cText.seq_num.low <<= 8;
|
| ++ cText.seq_num.high |= ss->gs.hdr[3 + i];
|
| ++ cText.seq_num.low |= ss->gs.hdr[7 + i];
|
| ++ }
|
| ++ }
|
| ++
|
| + cText.buf = &ss->gs.inbuf;
|
| + rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
|
| + }
|
| +Index: net/third_party/nss/ssl/derive.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/derive.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/derive.c (working copy)
|
| +@@ -583,6 +583,8 @@
|
| + * arguments were all valid but the slot cannot be bypassed.
|
| + */
|
| +
|
| ++/* XXX Add SSL_CBP_TLS1_1 and test it in protocolmask when setting isTLS. */
|
| ++
|
| + SECStatus
|
| + SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
|
| + PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites,
|
| +Index: net/third_party/nss/ssl/sslerr.h
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslerr.h (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslerr.h (working copy)
|
| +@@ -215,6 +215,9 @@
|
| +
|
| + SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 121),
|
| +
|
| ++SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 122),
|
| ++SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 123),
|
| ++
|
| + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
|
| + } SSLErrorCodes;
|
| + #endif /* NO_SECURITY_ERROR_ENUM */
|
| +Index: net/third_party/nss/ssl/ssldef.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/ssldef.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/ssldef.c (working copy)
|
| +@@ -138,6 +138,11 @@
|
| + return rv;
|
| + }
|
| + sent += rv;
|
| ++
|
| ++ if (IS_DTLS(ss) && (len > sent)) {
|
| ++ /* We got a partial write so just return it */
|
| ++ return sent;
|
| ++ }
|
| + } while (len > sent);
|
| + ss->lastWriteBlocked = 0;
|
| + return sent;
|
| +Index: net/third_party/nss/ssl/sslimpl.h
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslimpl.h (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslimpl.h (working copy)
|
| +@@ -62,6 +62,7 @@
|
| + #endif
|
| + #include "nssrwlk.h"
|
| + #include "prthread.h"
|
| ++#include "prclist.h"
|
| +
|
| + #include "sslt.h" /* for some formerly private types, now public */
|
| +
|
| +@@ -195,6 +196,10 @@
|
| +
|
| + #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
|
| +
|
| ++#define INITIAL_DTLS_TIMEOUT_MS 1000 /* Default value from RFC 4347 = 1s*/
|
| ++#define MAX_DTLS_TIMEOUT_MS 60000 /* 1 minute */
|
| ++#define DTLS_FINISHED_TIMER_MS 120000 /* Time to wait in FINISHED state */
|
| ++
|
| + typedef struct sslBufferStr sslBuffer;
|
| + typedef struct sslConnectInfoStr sslConnectInfo;
|
| + typedef struct sslGatherStr sslGather;
|
| +@@ -287,6 +292,8 @@
|
| + /* Flags interpreted by ssl send functions. */
|
| + #define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000
|
| + #define ssl_SEND_FLAG_NO_BUFFER 0x20000000
|
| ++#define ssl_SEND_FLAG_USE_EPOCH 0x10000000 /* DTLS only */
|
| ++#define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */
|
| + #define ssl_SEND_FLAG_MASK 0x7f000000
|
| +
|
| + /*
|
| +@@ -448,8 +455,15 @@
|
| + ** The portion of the SSL record header put here always comes off the wire
|
| + ** as plaintext, never ciphertext.
|
| + ** For SSL2, the plaintext portion is two bytes long. For SSl3 it is 5.
|
| ++ ** For DTLS it is 13.
|
| + */
|
| +- unsigned char hdr[5]; /* ssl 2 & 3 */
|
| ++ unsigned char hdr[13]; /* ssl 2 & 3 or dtls */
|
| ++
|
| ++ /* Buffer for DTLS data read off the wire as a single datagram */
|
| ++ sslBuffer dtlsPacket;
|
| ++
|
| ++ /* the start of the buffered DTLS record in dtlsPacket */
|
| ++ unsigned int dtlsPacketOffset;
|
| + };
|
| +
|
| + /* sslGather.state */
|
| +@@ -521,6 +535,10 @@
|
| + PRUint32 low;
|
| + } SSL3SequenceNumber;
|
| +
|
| ++typedef PRUint16 DTLSEpoch;
|
| ++
|
| ++typedef void (*DTLSTimerCb)(sslSocket *);
|
| ++
|
| + #define MAX_MAC_CONTEXT_BYTES 400
|
| + #define MAX_MAC_CONTEXT_LLONGS (MAX_MAC_CONTEXT_BYTES / 8)
|
| +
|
| +@@ -547,6 +565,20 @@
|
| + PRUint64 cipher_context[MAX_CIPHER_CONTEXT_LLONGS];
|
| + } ssl3KeyMaterial;
|
| +
|
| ++/* The DTLS anti-replay window. 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 /* Packets; approximate
|
| ++ * Must be divisible by 8
|
| ++ */
|
| ++typedef struct DTLSRecvdRecordsStr {
|
| ++ unsigned char data[DTLS_RECVD_RECORDS_WINDOW/8];
|
| ++ PRUint64 left;
|
| ++ PRUint64 right;
|
| ++} DTLSRecvdRecords;
|
| ++
|
| + /*
|
| + ** These are the "specs" in the "ssl3" struct.
|
| + ** Access to the pointers to these specs, and all the specs' contents
|
| +@@ -582,6 +614,8 @@
|
| + SECItem srvVirtName; /* for server: name that was negotiated
|
| + * with a client. For client - is
|
| + * always set to NULL.*/
|
| ++ DTLSEpoch epoch;
|
| ++ DTLSRecvdRecords recvdRecords;
|
| + } ssl3CipherSpec;
|
| +
|
| + typedef enum { never_cached,
|
| +@@ -777,6 +811,17 @@
|
| + typedef SECStatus (*sslRestartTarget)(sslSocket *);
|
| +
|
| + /*
|
| ++** A DTLS queued message (potentially to be retransmitted)
|
| ++*/
|
| ++typedef struct DTLSQueuedMessageStr {
|
| ++ PRCList link; /* The linked list link */
|
| ++ DTLSEpoch epoch; /* The epoch to use */
|
| ++ SSL3ContentType type; /* The message type */
|
| ++ unsigned char *data; /* The data */
|
| ++ PRUint16 len; /* The data length */
|
| ++} DTLSQueuedMessage;
|
| ++
|
| ++/*
|
| + ** This is the "hs" member of the "ssl3" struct.
|
| + ** This entire struct is protected by ssl3HandshakeLock
|
| + */
|
| +@@ -831,6 +876,30 @@
|
| + sslRestartTarget restartTarget;
|
| + /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
|
| + PRBool cacheSID;
|
| ++
|
| ++ /* This group of values is used for DTLS */
|
| ++ PRUint16 sendMessageSeq; /* The sending message sequence
|
| ++ * number */
|
| ++ PRCList * lastMessageFlight; /* The last message flight we sent.
|
| ++ * This is a pointer because
|
| ++ * ssl_FreeSocket relocates the
|
| ++ * structure in DEBUG mode, which
|
| ++ * messes up the list macros */
|
| ++ PRUint16 maxMessageSent; /* The largest message we sent */
|
| ++ PRUint16 recvMessageSeq; /* The receiving message sequence
|
| ++ * number */
|
| ++ sslBuffer recvdFragments; /* The fragments we have received in
|
| ++ * a bitmask */
|
| ++ PRInt32 recvdHighWater; /* The high water mark for fragments
|
| ++ * received. -1 means no reassembly
|
| ++ * in progress. */
|
| ++ unsigned char cookie[32]; /* The cookie */
|
| ++ unsigned char cookieLen; /* The length of the 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 */
|
| + } SSL3HandshakeState;
|
| +
|
| +
|
| +@@ -882,11 +951,18 @@
|
| + */
|
| + SECItem nextProto;
|
| + SSLNextProtoState nextProtoState;
|
| ++
|
| ++ PRUint16 mtu; /* Our estimate of the MTU */
|
| + };
|
| +
|
| ++#define DTLS_MAX_MTU 1500 /* Ethernet MTU but without subtracting the
|
| ++ * headers, so slightly larger than expected */
|
| ++#define IS_DTLS(ss) (ss->protocolVariant == ssl_variant_datagram)
|
| ++
|
| + typedef struct {
|
| + SSL3ContentType type;
|
| + SSL3ProtocolVersion version;
|
| ++ SSL3SequenceNumber seq_num; /* DTLS only */
|
| + sslBuffer * buf;
|
| + } SSL3Ciphertext;
|
| +
|
| +@@ -1188,6 +1264,9 @@
|
| + /* True when the current session is a stateless resume. */
|
| + PRBool statelessResume;
|
| + TLSExtensionData xtnData;
|
| ++
|
| ++ /* Whether we are doing stream or datagram mode */
|
| ++ SSLProtocolVariant protocolVariant;
|
| + };
|
| +
|
| +
|
| +@@ -1321,7 +1400,35 @@
|
| + extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
|
| +
|
| + extern PRBool ssl3_CanFalseStart(sslSocket *ss);
|
| ++extern SECStatus
|
| ++ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
|
| ++ PRBool isServer,
|
| ++ PRBool isDTLS,
|
| ++ SSL3ContentType type,
|
| ++ const SSL3Opaque * pIn,
|
| ++ PRUint32 contentLen,
|
| ++ sslBuffer * wrBuf);
|
| ++extern PRInt32 ssl3_SendRecord(sslSocket *ss, DTLSEpoch epoch,
|
| ++ SSL3ContentType type,
|
| ++ const SSL3Opaque* pIn, PRInt32 nIn,
|
| ++ PRInt32 flags);
|
| +
|
| ++#ifdef NSS_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_ENABLE_ZLIB */
|
| ++#define SSL3_COMPRESSION_MAX_EXPANSION 0
|
| ++#endif
|
| ++
|
| ++/*
|
| ++ * make sure there is room in the write buffer for padding and
|
| ++ * other compression and cryptographic expansions.
|
| ++ */
|
| ++#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION
|
| ++
|
| + #define SSL_LOCK_READER(ss) if (ss->recvLock) PZ_Lock(ss->recvLock)
|
| + #define SSL_UNLOCK_READER(ss) if (ss->recvLock) PZ_Unlock(ss->recvLock)
|
| + #define SSL_LOCK_WRITER(ss) if (ss->sendLock) PZ_Lock(ss->sendLock)
|
| +@@ -1417,6 +1524,7 @@
|
| + extern void ssl_FreeSocket(struct sslSocketStr *ssl);
|
| + extern SECStatus SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level,
|
| + SSL3AlertDescription desc);
|
| ++extern SECStatus ssl3_DecodeError(sslSocket *ss);
|
| +
|
| + extern SECStatus ssl3_RestartHandshakeAfterCertReq(sslSocket * ss,
|
| + CERTCertificate * cert,
|
| +@@ -1436,7 +1544,7 @@
|
| + /*
|
| + * SSL3 specific routines
|
| + */
|
| +-SECStatus ssl3_SendClientHello(sslSocket *ss);
|
| ++SECStatus ssl3_SendClientHello(sslSocket *ss, PRBool resending);
|
| +
|
| + /*
|
| + * input into the SSL3 machinery from the actualy network reading code
|
| +@@ -1531,6 +1639,8 @@
|
| + unsigned char *cs, int *size);
|
| +
|
| + extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache);
|
| ++extern SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
|
| ++ PRUint32 length);
|
| +
|
| + extern void ssl3_DestroySSL3Info(sslSocket *ss);
|
| +
|
| +@@ -1556,6 +1666,7 @@
|
| + extern SECStatus ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf,
|
| + unsigned int bufLen, SSL3Hashes *hashes,
|
| + PRBool bypassPKCS11);
|
| ++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);
|
| +@@ -1724,6 +1835,42 @@
|
| + CERTCertList* list);
|
| + #endif /* NSS_PLATFORM_CLIENT_AUTH */
|
| +
|
| ++/**************** DTLS-specific functions **************/
|
| ++extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg);
|
| ++extern void dtls_FreeQueuedMessages(PRCList *lst);
|
| ++extern void dtls_FreeHandshakeMessages(PRCList *lst);
|
| ++
|
| ++extern SECStatus dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf);
|
| ++extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss,
|
| ++ SSL3Opaque *b, PRUint32 length);
|
| ++extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss);
|
| ++extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
|
| ++ const SSL3Opaque *pIn, PRInt32 nIn);
|
| ++extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
|
| ++extern SECStatus dtls_CompressMACEncryptRecord(sslSocket *ss,
|
| ++ DTLSEpoch epoch,
|
| ++ PRBool use_epoch,
|
| ++ SSL3ContentType type,
|
| ++ const SSL3Opaque *pIn,
|
| ++ PRUint32 contentLen,
|
| ++ sslBuffer *wrBuf);
|
| ++SECStatus ssl3_DisableNonDTLSSuites(sslSocket * ss);
|
| ++extern SECStatus dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb);
|
| ++extern SECStatus dtls_RestartTimer(sslSocket *ss, PRBool backoff,
|
| ++ DTLSTimerCb cb);
|
| ++extern void dtls_CheckTimer(sslSocket *ss);
|
| ++extern void dtls_CancelTimer(sslSocket *ss);
|
| ++extern void dtls_FinishedTimerCb(sslSocket *ss);
|
| ++extern void dtls_SetMTU(sslSocket *ss, PRUint16 advertised);
|
| ++extern void dtls_InitRecvdRecords(DTLSRecvdRecords *records);
|
| ++extern int dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq);
|
| ++extern void dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq);
|
| ++extern void dtls_RehandshakeCleanup(sslSocket *ss);
|
| ++extern SSL3ProtocolVersion
|
| ++dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv);
|
| ++extern SSL3ProtocolVersion
|
| ++dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv);
|
| ++
|
| + /********************** misc calls *********************/
|
| +
|
| + extern int ssl_MapLowLevelError(int hiLevelError);
|
| +Index: net/third_party/nss/ssl/manifest.mn
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/manifest.mn (revision 127709)
|
| ++++ net/third_party/nss/ssl/manifest.mn (working copy)
|
| +@@ -51,6 +51,7 @@
|
| +
|
| + CSRCS = \
|
| + derive.c \
|
| ++ dtls1con.c \
|
| + prelib.c \
|
| + ssl3con.c \
|
| + ssl3gthr.c \
|
| +Index: net/third_party/nss/ssl/ssl3prot.h
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/ssl3prot.h (revision 127709)
|
| ++++ net/third_party/nss/ssl/ssl3prot.h (working copy)
|
| +@@ -61,6 +61,9 @@
|
| +
|
| + #define SSL3_RECORD_HEADER_LENGTH 5
|
| +
|
| ++/* SSL3_RECORD_HEADER_LENGTH + epoch/sequence_number */
|
| ++#define DTLS_RECORD_HEADER_LENGTH 13
|
| ++
|
| + #define MAX_FRAGMENT_LENGTH 16384
|
| +
|
| + typedef enum {
|
| +@@ -150,6 +153,7 @@
|
| + hello_request = 0,
|
| + client_hello = 1,
|
| + server_hello = 2,
|
| ++ hello_verify_request = 3,
|
| + new_session_ticket = 4,
|
| + certificate = 11,
|
| + server_key_exchange = 12,
|
| +Index: net/third_party/nss/ssl/sslcon.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslcon.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslcon.c (working copy)
|
| +@@ -1249,7 +1249,12 @@
|
| +
|
| + ssl_GetRecvBufLock(ss);
|
| +
|
| +- if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
|
| ++ /* The special case DTLS logic is needed here because the SSL/TLS
|
| ++ * version wants to auto-detect SSL2 vs. SSL3 on the initial handshake
|
| ++ * (ss->version == 0) but with DTLS it gets confused, so we force the
|
| ++ * SSL3 version.
|
| ++ */
|
| ++ if ((ss->version >= SSL_LIBRARY_VERSION_3_0) || IS_DTLS(ss)) {
|
| + /* Wait for handshake to complete, or application data to arrive. */
|
| + rv = ssl3_GatherCompleteHandshake(ss, 0);
|
| + } else {
|
| +@@ -3120,7 +3125,7 @@
|
| +
|
| + ssl_GetSSL3HandshakeLock(ss);
|
| + ssl_GetXmitBufLock(ss);
|
| +- rv = ssl3_SendClientHello(ss);
|
| ++ rv = ssl3_SendClientHello(ss, PR_FALSE);
|
| + ssl_ReleaseXmitBufLock(ss);
|
| + ssl_ReleaseSSL3HandshakeLock(ss);
|
| +
|
| +Index: net/third_party/nss/ssl/sslsecur.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslsecur.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslsecur.c (working copy)
|
| +@@ -615,6 +615,7 @@
|
| + if (!(flags & PR_MSG_PEEK)) {
|
| + ss->gs.readOffset += amount;
|
| + }
|
| ++ PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset);
|
| + rv = amount;
|
| +
|
| + SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d",
|
| +Index: net/third_party/nss/ssl/sslsock.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslsock.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslsock.c (working copy)
|
| +@@ -194,11 +194,20 @@
|
| + /*
|
| + * default range of enabled SSL/TLS protocols
|
| + */
|
| +-static SSLVersionRange versions_defaults = {
|
| ++static SSLVersionRange versions_defaults_stream = {
|
| + SSL_LIBRARY_VERSION_3_0,
|
| + SSL_LIBRARY_VERSION_TLS_1_0
|
| + };
|
| +
|
| ++static SSLVersionRange versions_defaults_datagram = {
|
| ++ SSL_LIBRARY_VERSION_TLS_1_1,
|
| ++ SSL_LIBRARY_VERSION_TLS_1_1
|
| ++};
|
| ++
|
| ++#define VERSIONS_DEFAULTS(variant) \
|
| ++ (variant == ssl_variant_stream ? &versions_defaults_stream : \
|
| ++ &versions_defaults_datagram)
|
| ++
|
| + sslSessionIDLookupFunc ssl_sid_lookup;
|
| + sslSessionIDCacheFunc ssl_sid_cache;
|
| + sslSessionIDUncacheFunc ssl_sid_uncache;
|
| +@@ -217,7 +226,7 @@
|
| + #define LOCKSTATUS_OFFSET 10 /* offset of ENABLED */
|
| +
|
| + /* forward declarations. */
|
| +-static sslSocket *ssl_NewSocket(PRBool makeLocks);
|
| ++static sslSocket *ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant variant);
|
| + static SECStatus ssl_MakeLocks(sslSocket *ss);
|
| + static void ssl_SetDefaultsFromEnvironment(void);
|
| + static PRStatus ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack,
|
| +@@ -281,7 +290,13 @@
|
| + sslSocket *ss;
|
| + SECStatus rv;
|
| +
|
| +- ss = ssl_NewSocket((PRBool)(!os->opt.noLocks));
|
| ++ /* Not implemented for datagram */
|
| ++ if (IS_DTLS(os)) {
|
| ++ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
|
| ++ return NULL;
|
| ++ }
|
| ++
|
| ++ ss = ssl_NewSocket((PRBool)(!os->opt.noLocks), os->protocolVariant);
|
| + if (ss) {
|
| + ss->opt = os->opt;
|
| + ss->opt.useSocks = PR_FALSE;
|
| +@@ -698,6 +713,13 @@
|
| + break;
|
| +
|
| + case SSL_ENABLE_TLS:
|
| ++ if (IS_DTLS(ss)) {
|
| ++ if (on) {
|
| ++ PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| ++ rv = SECFailure; /* not allowed */
|
| ++ }
|
| ++ break;
|
| ++ }
|
| + ssl_EnableTLS(&ss->vrange, on);
|
| + ss->preferredCipher = NULL;
|
| + if (ss->cipherSpecs) {
|
| +@@ -708,6 +730,13 @@
|
| + break;
|
| +
|
| + case SSL_ENABLE_SSL3:
|
| ++ if (IS_DTLS(ss)) {
|
| ++ if (on) {
|
| ++ PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| ++ rv = SECFailure; /* not allowed */
|
| ++ }
|
| ++ break;
|
| ++ }
|
| + ssl_EnableSSL3(&ss->vrange, on);
|
| + ss->preferredCipher = NULL;
|
| + if (ss->cipherSpecs) {
|
| +@@ -718,6 +747,13 @@
|
| + break;
|
| +
|
| + case SSL_ENABLE_SSL2:
|
| ++ if (IS_DTLS(ss)) {
|
| ++ if (on) {
|
| ++ PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| ++ rv = SECFailure; /* not allowed */
|
| ++ }
|
| ++ break;
|
| ++ }
|
| + ss->opt.enableSSL2 = on;
|
| + if (on) {
|
| + ss->opt.v2CompatibleHello = on;
|
| +@@ -743,6 +779,13 @@
|
| + break;
|
| +
|
| + case SSL_V2_COMPATIBLE_HELLO:
|
| ++ if (IS_DTLS(ss)) {
|
| ++ if (on) {
|
| ++ PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| ++ rv = SECFailure; /* not allowed */
|
| ++ }
|
| ++ break;
|
| ++ }
|
| + ss->opt.v2CompatibleHello = on;
|
| + if (!on) {
|
| + ss->opt.enableSSL2 = on;
|
| +@@ -938,10 +981,10 @@
|
| + case SSL_HANDSHAKE_AS_CLIENT: on = ssl_defaults.handshakeAsClient; break;
|
| + case SSL_HANDSHAKE_AS_SERVER: on = ssl_defaults.handshakeAsServer; break;
|
| + case SSL_ENABLE_TLS:
|
| +- on = versions_defaults.max >= SSL_LIBRARY_VERSION_TLS_1_0;
|
| ++ on = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0;
|
| + break;
|
| + case SSL_ENABLE_SSL3:
|
| +- on = versions_defaults.min == SSL_LIBRARY_VERSION_3_0;
|
| ++ on = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0;
|
| + break;
|
| + case SSL_ENABLE_SSL2: on = ssl_defaults.enableSSL2; break;
|
| + case SSL_NO_CACHE: on = ssl_defaults.noCache; break;
|
| +@@ -1034,11 +1077,11 @@
|
| + break;
|
| +
|
| + case SSL_ENABLE_TLS:
|
| +- ssl_EnableTLS(&versions_defaults, on);
|
| ++ ssl_EnableTLS(&versions_defaults_stream, on);
|
| + break;
|
| +
|
| + case SSL_ENABLE_SSL3:
|
| +- ssl_EnableSSL3(&versions_defaults, on);
|
| ++ ssl_EnableSSL3(&versions_defaults_stream, on);
|
| + break;
|
| +
|
| + case SSL_ENABLE_SSL2:
|
| +@@ -1360,8 +1403,8 @@
|
| +
|
| +
|
| + /* LOCKS ??? XXX */
|
| +-PRFileDesc *
|
| +-SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
|
| ++static PRFileDesc *
|
| ++ssl_ImportFD(PRFileDesc *model, PRFileDesc *fd, SSLProtocolVariant variant)
|
| + {
|
| + sslSocket * ns = NULL;
|
| + PRStatus rv;
|
| +@@ -1374,10 +1417,10 @@
|
| +
|
| + if (model == NULL) {
|
| + /* Just create a default socket if we're given NULL for the model */
|
| +- ns = ssl_NewSocket((PRBool)(!ssl_defaults.noLocks));
|
| ++ ns = ssl_NewSocket((PRBool)(!ssl_defaults.noLocks), variant);
|
| + } else {
|
| + sslSocket * ss = ssl_FindSocket(model);
|
| +- if (ss == NULL) {
|
| ++ if (ss == NULL || ss->protocolVariant != variant) {
|
| + SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ImportFD",
|
| + SSL_GETPID(), model));
|
| + return NULL;
|
| +@@ -1403,6 +1446,18 @@
|
| + return fd;
|
| + }
|
| +
|
| ++PRFileDesc *
|
| ++SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
|
| ++{
|
| ++ return ssl_ImportFD(model, fd, ssl_variant_stream);
|
| ++}
|
| ++
|
| ++PRFileDesc *
|
| ++DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd)
|
| ++{
|
| ++ return ssl_ImportFD(model, fd, ssl_variant_datagram);
|
| ++}
|
| ++
|
| + SECStatus
|
| + SSL_SetNextProtoCallback(PRFileDesc *fd, SSLNextProtoCallback callback,
|
| + void *arg)
|
| +@@ -1667,9 +1722,18 @@
|
| + ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant,
|
| + SSL3ProtocolVersion version)
|
| + {
|
| +- return protocolVariant == ssl_variant_stream &&
|
| +- version >= SSL_LIBRARY_VERSION_3_0 &&
|
| +- version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED;
|
| ++ switch (protocolVariant) {
|
| ++ case ssl_variant_stream:
|
| ++ return (version >= SSL_LIBRARY_VERSION_3_0 &&
|
| ++ version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED);
|
| ++ case ssl_variant_datagram:
|
| ++ return (version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
|
| ++ version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED);
|
| ++ default:
|
| ++ /* Can't get here */
|
| ++ PORT_Assert(PR_FALSE);
|
| ++ return PR_FALSE;
|
| ++ }
|
| + }
|
| +
|
| + /* Returns PR_TRUE if the given version range is valid and
|
| +@@ -1689,13 +1753,24 @@
|
| + SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant,
|
| + SSLVersionRange *vrange)
|
| + {
|
| +- if (protocolVariant != ssl_variant_stream || !vrange) {
|
| ++ if (!vrange) {
|
| + PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| + return SECFailure;
|
| + }
|
| +
|
| +- vrange->min = SSL_LIBRARY_VERSION_3_0;
|
| +- vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
|
| ++ switch (protocolVariant) {
|
| ++ case ssl_variant_stream:
|
| ++ vrange->min = SSL_LIBRARY_VERSION_3_0;
|
| ++ vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
|
| ++ break;
|
| ++ case ssl_variant_datagram:
|
| ++ vrange->min = SSL_LIBRARY_VERSION_TLS_1_1;
|
| ++ vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
|
| ++ break;
|
| ++ default:
|
| ++ PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| ++ return SECFailure;
|
| ++ }
|
| +
|
| + return SECSuccess;
|
| + }
|
| +@@ -1704,12 +1779,13 @@
|
| + SSL_VersionRangeGetDefault(SSLProtocolVariant protocolVariant,
|
| + SSLVersionRange *vrange)
|
| + {
|
| +- if (protocolVariant != ssl_variant_stream || !vrange) {
|
| ++ if ((protocolVariant != ssl_variant_stream &&
|
| ++ protocolVariant != ssl_variant_datagram) || !vrange) {
|
| + PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| + return SECFailure;
|
| + }
|
| +
|
| +- *vrange = versions_defaults;
|
| ++ *vrange = *VERSIONS_DEFAULTS(protocolVariant);
|
| +
|
| + return SECSuccess;
|
| + }
|
| +@@ -1723,7 +1799,7 @@
|
| + return SECFailure;
|
| + }
|
| +
|
| +- versions_defaults = *vrange;
|
| ++ *VERSIONS_DEFAULTS(protocolVariant) = *vrange;
|
| +
|
| + return SECSuccess;
|
| + }
|
| +@@ -2830,7 +2906,7 @@
|
| + ** Create a newsocket structure for a file descriptor.
|
| + */
|
| + static sslSocket *
|
| +-ssl_NewSocket(PRBool makeLocks)
|
| ++ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
|
| + {
|
| + sslSocket *ss;
|
| +
|
| +@@ -2851,7 +2927,7 @@
|
| + ss->opt = ssl_defaults;
|
| + ss->opt.useSocks = PR_FALSE;
|
| + ss->opt.noLocks = !makeLocks;
|
| +- ss->vrange = versions_defaults;
|
| ++ ss->vrange = *VERSIONS_DEFAULTS(protocolVariant);
|
| +
|
| + ss->peerID = NULL;
|
| + ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
|
| +@@ -2907,6 +2983,7 @@
|
| + PORT_Free(ss);
|
| + ss = NULL;
|
| + }
|
| ++ ss->protocolVariant = protocolVariant;
|
| + }
|
| + return ss;
|
| + }
|
| +Index: net/third_party/nss/ssl/ssl3con.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/ssl3con.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/ssl3con.c (working copy)
|
| +@@ -42,6 +42,8 @@
|
| + * ***** END LICENSE BLOCK ***** */
|
| + /* $Id: ssl3con.c,v 1.173 2012/03/18 00:31:19 wtc%google.com Exp $ */
|
| +
|
| ++/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */
|
| ++
|
| + #include "cert.h"
|
| + #include "ssl.h"
|
| + #include "cryptohi.h" /* for DSAU_ stuff */
|
| +@@ -92,6 +94,7 @@
|
| + static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
|
| + const unsigned char *b,
|
| + unsigned int l);
|
| ++static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
|
| +
|
| + static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
|
| + int maxOutputLen, const unsigned char *input,
|
| +@@ -221,22 +224,6 @@
|
| + #endif /* NSS_ENABLE_ECC */
|
| + };
|
| +
|
| +-#ifdef NSS_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_ENABLE_ZLIB */
|
| +-#define SSL3_COMPRESSION_MAX_EXPANSION 0
|
| +-#endif
|
| +-
|
| +-/*
|
| +- * make sure there is room in the write buffer for padding and
|
| +- * other compression and cryptographic expansions.
|
| +- */
|
| +-#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION
|
| +-
|
| + #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
|
| +
|
| +
|
| +@@ -517,6 +504,7 @@
|
| + case hello_request: rv = "hello_request (0)"; break;
|
| + case client_hello: rv = "client_hello (1)"; break;
|
| + case server_hello: rv = "server_hello (2)"; break;
|
| ++ case hello_verify_request: rv = "hello_verify_request (3)"; break;
|
| + case certificate: rv = "certificate (11)"; break;
|
| + case server_key_exchange: rv = "server_key_exchange (12)"; break;
|
| + case certificate_request: rv = "certificate_request (13)"; break;
|
| +@@ -656,7 +644,7 @@
|
| + suite->isPresent = PR_FALSE;
|
| + continue;
|
| + }
|
| +- cipher_alg=bulk_cipher_defs[cipher_def->bulk_cipher_alg ].calg;
|
| ++ cipher_alg = bulk_cipher_defs[cipher_def->bulk_cipher_alg].calg;
|
| + PORT_Assert( alg2Mech[cipher_alg].calg == cipher_alg);
|
| + cipher_mech = alg2Mech[cipher_alg].cmech;
|
| + exchKeyType =
|
| +@@ -1148,7 +1136,7 @@
|
| + ** ssl3_DestroySSL3Info
|
| + ** Caller must hold SpecWriteLock.
|
| + */
|
| +-static void
|
| ++void
|
| + ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
|
| + {
|
| + PRBool freeit = (PRBool)(!spec->bypassCiphers);
|
| +@@ -1228,6 +1216,12 @@
|
| + return SECFailure; /* error code set by ssl_LookupCipherSuiteDef */
|
| + }
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ /* Double-check that we did not pick an RC4 suite */
|
| ++ PORT_Assert((suite_def->bulk_cipher_alg != cipher_rc4) &&
|
| ++ (suite_def->bulk_cipher_alg != cipher_rc4_40) &&
|
| ++ (suite_def->bulk_cipher_alg != cipher_rc4_56));
|
| ++ }
|
| +
|
| + cipher = suite_def->bulk_cipher_alg;
|
| + kea = suite_def->key_exchange_alg;
|
| +@@ -1754,6 +1748,7 @@
|
| + ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms)
|
| + {
|
| + ssl3CipherSpec * pwSpec;
|
| ++ ssl3CipherSpec * cwSpec;
|
| + SECStatus rv;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| +@@ -1763,6 +1758,7 @@
|
| + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
|
| +
|
| + pwSpec = ss->ssl3.pwSpec;
|
| ++ cwSpec = ss->ssl3.cwSpec;
|
| +
|
| + if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) {
|
| + rv = ssl3_DeriveMasterSecret(ss, pms);
|
| +@@ -1794,7 +1790,32 @@
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + rv = SECFailure;
|
| + }
|
| ++ if (rv != SECSuccess) {
|
| ++ goto done;
|
| ++ }
|
| +
|
| ++ /* Generic behaviors -- common to all crypto methods */
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0;
|
| ++ } else {
|
| ++ if (cwSpec->epoch == PR_UINT16_MAX) {
|
| ++ /* The problem here is that we have rehandshaked too many
|
| ++ * times (you are not allowed to wrap the epoch). The
|
| ++ * spec says you should be discarding the connection
|
| ++ * and start over, so not much we can do here. */
|
| ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| ++ rv = SECFailure;
|
| ++ goto done;
|
| ++ }
|
| ++ /* The sequence number has the high 16 bits as the epoch. */
|
| ++ pwSpec->epoch = cwSpec->epoch + 1;
|
| ++ pwSpec->read_seq_num.high = pwSpec->write_seq_num.high =
|
| ++ pwSpec->epoch << 16;
|
| ++
|
| ++ dtls_InitRecvdRecords(&pwSpec->recvdRecords);
|
| ++ }
|
| ++ pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0;
|
| ++
|
| + done:
|
| + ssl_ReleaseSpecWriteLock(ss); /******************************/
|
| + if (rv != SECSuccess)
|
| +@@ -1834,6 +1855,7 @@
|
| + ssl3_ComputeRecordMAC(
|
| + ssl3CipherSpec * spec,
|
| + PRBool useServerMacKey,
|
| ++ PRBool isDTLS,
|
| + SSL3ContentType type,
|
| + SSL3ProtocolVersion version,
|
| + SSL3SequenceNumber seq_num,
|
| +@@ -1871,8 +1893,16 @@
|
| + isTLS = PR_FALSE;
|
| + } else {
|
| + /* New TLS hash includes version. */
|
| +- temp[9] = MSB(version);
|
| +- temp[10] = LSB(version);
|
| ++ if (isDTLS) {
|
| ++ SSL3ProtocolVersion dtls_version;
|
| ++
|
| ++ dtls_version = dtls_TLSVersionToDTLSVersion(version);
|
| ++ temp[9] = MSB(dtls_version);
|
| ++ temp[10] = LSB(dtls_version);
|
| ++ } else {
|
| ++ temp[9] = MSB(version);
|
| ++ temp[10] = LSB(version);
|
| ++ }
|
| + temp[11] = MSB(inputLength);
|
| + temp[12] = LSB(inputLength);
|
| + tempLen = 13;
|
| +@@ -2022,9 +2052,10 @@
|
| + }
|
| +
|
| + /* Caller must hold the spec read lock. */
|
| +-static SECStatus
|
| ++SECStatus
|
| + ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
|
| + PRBool isServer,
|
| ++ PRBool isDTLS,
|
| + SSL3ContentType type,
|
| + const SSL3Opaque * pIn,
|
| + PRUint32 contentLen,
|
| +@@ -2035,10 +2066,12 @@
|
| + PRUint32 macLen = 0;
|
| + PRUint32 fragLen;
|
| + PRUint32 p1Len, p2Len, oddLen = 0;
|
| ++ PRUint16 headerLen;
|
| + int ivLen = 0;
|
| + int cipherBytes = 0;
|
| +
|
| + cipher_def = cwSpec->cipher_def;
|
| ++ headerLen = isDTLS ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
|
| +
|
| + if (cipher_def->type == type_block &&
|
| + cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
|
| +@@ -2048,20 +2081,20 @@
|
| + * record.
|
| + */
|
| + ivLen = cipher_def->iv_size;
|
| +- if (ivLen > wrBuf->space - SSL3_RECORD_HEADER_LENGTH) {
|
| ++ if (ivLen > wrBuf->space - headerLen) {
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +- rv = PK11_GenerateRandom(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, ivLen);
|
| ++ rv = PK11_GenerateRandom(wrBuf->buf + headerLen, ivLen);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
|
| + return rv;
|
| + }
|
| + rv = cwSpec->encode( cwSpec->encodeContext,
|
| +- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH,
|
| ++ wrBuf->buf + headerLen,
|
| + &cipherBytes, /* output and actual outLen */
|
| + ivLen, /* max outlen */
|
| +- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH,
|
| ++ wrBuf->buf + headerLen,
|
| + ivLen); /* input and inputLen*/
|
| + if (rv != SECSuccess || cipherBytes != ivLen) {
|
| + PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
|
| +@@ -2073,20 +2106,20 @@
|
| + int outlen;
|
| + rv = cwSpec->compressor(
|
| + cwSpec->compressContext,
|
| +- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen, &outlen,
|
| +- wrBuf->space - SSL3_RECORD_HEADER_LENGTH - ivLen, pIn, contentLen);
|
| ++ wrBuf->buf + headerLen + ivLen, &outlen,
|
| ++ wrBuf->space - headerLen - ivLen, pIn, contentLen);
|
| + if (rv != SECSuccess)
|
| + return rv;
|
| +- pIn = wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen;
|
| ++ pIn = wrBuf->buf + headerLen + ivLen;
|
| + contentLen = outlen;
|
| + }
|
| +
|
| + /*
|
| + * Add the MAC
|
| + */
|
| +- rv = ssl3_ComputeRecordMAC( cwSpec, isServer,
|
| ++ rv = ssl3_ComputeRecordMAC( cwSpec, isServer, isDTLS,
|
| + type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen,
|
| +- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + contentLen, &macLen);
|
| ++ wrBuf->buf + headerLen + ivLen + contentLen, &macLen);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
|
| + return SECFailure;
|
| +@@ -2113,7 +2146,7 @@
|
| + PORT_Assert((fragLen % cipher_def->block_size) == 0);
|
| +
|
| + /* Pad according to TLS rules (also acceptable to SSL3). */
|
| +- pBuf = &wrBuf->buf[SSL3_RECORD_HEADER_LENGTH + ivLen + fragLen - 1];
|
| ++ pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1];
|
| + for (i = padding_length + 1; i > 0; --i) {
|
| + *pBuf-- = padding_length;
|
| + }
|
| +@@ -2130,13 +2163,12 @@
|
| + p2Len += oddLen;
|
| + PORT_Assert( (cipher_def->block_size < 2) || \
|
| + (p2Len % cipher_def->block_size) == 0);
|
| +- memmove(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len,
|
| +- pIn + p1Len, oddLen);
|
| ++ memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len, oddLen);
|
| + }
|
| + if (p1Len > 0) {
|
| + int cipherBytesPart1 = -1;
|
| + rv = cwSpec->encode( cwSpec->encodeContext,
|
| +- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen, /* output */
|
| ++ wrBuf->buf + headerLen + ivLen, /* output */
|
| + &cipherBytesPart1, /* actual outlen */
|
| + p1Len, /* max outlen */
|
| + pIn, p1Len); /* input, and inputlen */
|
| +@@ -2150,10 +2182,10 @@
|
| + if (p2Len > 0) {
|
| + int cipherBytesPart2 = -1;
|
| + rv = cwSpec->encode( cwSpec->encodeContext,
|
| +- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len,
|
| ++ wrBuf->buf + headerLen + ivLen + p1Len,
|
| + &cipherBytesPart2, /* output and actual outLen */
|
| + p2Len, /* max outlen */
|
| +- wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len,
|
| ++ wrBuf->buf + headerLen + ivLen + p1Len,
|
| + p2Len); /* input and inputLen*/
|
| + PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len);
|
| + if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) {
|
| +@@ -2164,15 +2196,33 @@
|
| + }
|
| + PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024);
|
| +
|
| ++ wrBuf->len = cipherBytes + headerLen;
|
| ++ wrBuf->buf[0] = type;
|
| ++ if (isDTLS) {
|
| ++ SSL3ProtocolVersion version;
|
| ++
|
| ++ version = dtls_TLSVersionToDTLSVersion(cwSpec->version);
|
| ++ wrBuf->buf[1] = MSB(version);
|
| ++ wrBuf->buf[2] = LSB(version);
|
| ++ wrBuf->buf[3] = (unsigned char)(cwSpec->write_seq_num.high >> 24);
|
| ++ wrBuf->buf[4] = (unsigned char)(cwSpec->write_seq_num.high >> 16);
|
| ++ wrBuf->buf[5] = (unsigned char)(cwSpec->write_seq_num.high >> 8);
|
| ++ wrBuf->buf[6] = (unsigned char)(cwSpec->write_seq_num.high >> 0);
|
| ++ wrBuf->buf[7] = (unsigned char)(cwSpec->write_seq_num.low >> 24);
|
| ++ wrBuf->buf[8] = (unsigned char)(cwSpec->write_seq_num.low >> 16);
|
| ++ wrBuf->buf[9] = (unsigned char)(cwSpec->write_seq_num.low >> 8);
|
| ++ wrBuf->buf[10] = (unsigned char)(cwSpec->write_seq_num.low >> 0);
|
| ++ wrBuf->buf[11] = MSB(cipherBytes);
|
| ++ wrBuf->buf[12] = LSB(cipherBytes);
|
| ++ } else {
|
| ++ wrBuf->buf[1] = MSB(cwSpec->version);
|
| ++ wrBuf->buf[2] = LSB(cwSpec->version);
|
| ++ wrBuf->buf[3] = MSB(cipherBytes);
|
| ++ wrBuf->buf[4] = LSB(cipherBytes);
|
| ++ }
|
| ++
|
| + ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);
|
| +
|
| +- wrBuf->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH;
|
| +- wrBuf->buf[0] = type;
|
| +- wrBuf->buf[1] = MSB(cwSpec->version);
|
| +- wrBuf->buf[2] = LSB(cwSpec->version);
|
| +- wrBuf->buf[3] = MSB(cipherBytes);
|
| +- wrBuf->buf[4] = LSB(cipherBytes);
|
| +-
|
| + return SECSuccess;
|
| + }
|
| +
|
| +@@ -2194,10 +2244,13 @@
|
| + * ssl_SEND_FLAG_FORCE_INTO_BUFFER
|
| + * As above, except this suppresses all write attempts, and forces
|
| + * all ciphertext into the pending ciphertext buffer.
|
| ++ * ssl_SEND_FLAG_USE_EPOCH (for DTLS)
|
| ++ * Forces the use of the provided epoch
|
| + *
|
| + */
|
| +-static PRInt32
|
| ++PRInt32
|
| + ssl3_SendRecord( sslSocket * ss,
|
| ++ DTLSEpoch epoch, /* DTLS only */
|
| + SSL3ContentType type,
|
| + const SSL3Opaque * pIn, /* input buffer */
|
| + PRInt32 nIn, /* bytes of input */
|
| +@@ -2269,8 +2322,8 @@
|
| + sslBuffer secondRecord;
|
| +
|
| + rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
|
| +- ss->sec.isServer, type, pIn, 1,
|
| +- wrBuf);
|
| ++ ss->sec.isServer, IS_DTLS(ss),
|
| ++ type, pIn, 1, wrBuf);
|
| + if (rv != SECSuccess)
|
| + goto spec_locked_loser;
|
| +
|
| +@@ -2282,17 +2335,28 @@
|
| + secondRecord.space = wrBuf->space - wrBuf->len;
|
| +
|
| + rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
|
| +- ss->sec.isServer, type, pIn + 1,
|
| +- contentLen - 1, &secondRecord);
|
| ++ ss->sec.isServer, IS_DTLS(ss),
|
| ++ type, pIn + 1, contentLen - 1,
|
| ++ &secondRecord);
|
| + if (rv == SECSuccess) {
|
| + PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
|
| + secondRecord.buf, secondRecord.len));
|
| + wrBuf->len += secondRecord.len;
|
| + }
|
| + } else {
|
| +- rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
|
| +- ss->sec.isServer, type, pIn,
|
| +- contentLen, wrBuf);
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec,
|
| ++ ss->sec.isServer,
|
| ++ IS_DTLS(ss),
|
| ++ type, pIn,
|
| ++ contentLen, wrBuf);
|
| ++ } else {
|
| ++ rv = dtls_CompressMACEncryptRecord(ss, epoch,
|
| ++ !!(flags & ssl_SEND_FLAG_USE_EPOCH),
|
| ++ type, pIn,
|
| ++ contentLen, wrBuf);
|
| ++ }
|
| ++
|
| + if (rv == SECSuccess) {
|
| + PRINT_BUF(50, (ss, "send (encrypted) record data:",
|
| + wrBuf->buf, wrBuf->len));
|
| +@@ -2350,6 +2414,11 @@
|
| + }
|
| + wrBuf->len -= sent;
|
| + if (wrBuf->len) {
|
| ++ if (IS_DTLS(ss)) {
|
| ++ /* DTLS just says no in this case. No buffering */
|
| ++ PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
|
| ++ return SECFailure;
|
| ++ }
|
| + /* now take all the remaining unsent new ciphertext and
|
| + * append it to the buffer of previously unsent ciphertext.
|
| + */
|
| +@@ -2378,6 +2447,9 @@
|
| + PRInt32 discarded = 0;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
|
| ++ /* These flags for internal use only */
|
| ++ PORT_Assert(!(flags & (ssl_SEND_FLAG_USE_EPOCH |
|
| ++ ssl_SEND_FLAG_NO_RETRANSMIT)));
|
| + if (len < 0 || !in) {
|
| + PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
|
| + return SECFailure;
|
| +@@ -2415,7 +2487,11 @@
|
| + ssl_GetXmitBufLock(ss);
|
| + }
|
| + toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH);
|
| +- sent = ssl3_SendRecord(ss, content_application_data,
|
| ++ /*
|
| ++ * Note that the 0 epoch is OK because flags will never require
|
| ++ * its use, as guaranteed by the PORT_Assert above.
|
| ++ */
|
| ++ sent = ssl3_SendRecord(ss, 0, content_application_data,
|
| + in + totalSent, toSend, flags);
|
| + if (sent < 0) {
|
| + if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) {
|
| +@@ -2450,10 +2526,15 @@
|
| + return totalSent + discarded;
|
| + }
|
| +
|
| +-/* Attempt to send the content of sendBuf buffer in an SSL handshake record.
|
| ++/* Attempt to send buffered handshake messages.
|
| + * This function returns SECSuccess or SECFailure, never SECWouldBlock.
|
| + * Always set sendBuf.len to 0, even when returning SECFailure.
|
| + *
|
| ++ * Depending on whether we are doing DTLS or not, this either calls
|
| ++ *
|
| ++ * - ssl3_FlushHandshakeMessages if non-DTLS
|
| ++ * - dtls_FlushHandshakeMessages if DTLS
|
| ++ *
|
| + * Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(),
|
| + * ssl3_AppendHandshake(), ssl3_SendClientHello(),
|
| + * ssl3_SendHelloRequest(), ssl3_SendServerHelloDone(),
|
| +@@ -2462,6 +2543,22 @@
|
| + static SECStatus
|
| + ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags)
|
| + {
|
| ++ if (IS_DTLS(ss)) {
|
| ++ return dtls_FlushHandshakeMessages(ss, flags);
|
| ++ } else {
|
| ++ return ssl3_FlushHandshakeMessages(ss, flags);
|
| ++ }
|
| ++}
|
| ++
|
| ++/* Attempt to send the content of sendBuf buffer in an SSL handshake record.
|
| ++ * This function returns SECSuccess or SECFailure, never SECWouldBlock.
|
| ++ * Always set sendBuf.len to 0, even when returning SECFailure.
|
| ++ *
|
| ++ * Called from ssl3_FlushHandshake
|
| ++ */
|
| ++static SECStatus
|
| ++ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
|
| ++{
|
| + PRInt32 rv = SECSuccess;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| +@@ -2476,7 +2573,7 @@
|
| + PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| + rv = SECFailure;
|
| + } else {
|
| +- rv = ssl3_SendRecord(ss, content_handshake, ss->sec.ci.sendBuf.buf,
|
| ++ rv = ssl3_SendRecord(ss, 0, content_handshake, ss->sec.ci.sendBuf.buf,
|
| + ss->sec.ci.sendBuf.len, flags);
|
| + }
|
| + if (rv < 0) {
|
| +@@ -2593,7 +2690,7 @@
|
| + rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
|
| + if (rv == SECSuccess) {
|
| + PRInt32 sent;
|
| +- sent = ssl3_SendRecord(ss, content_alert, bytes, 2,
|
| ++ sent = ssl3_SendRecord(ss, 0, content_alert, bytes, 2,
|
| + desc == no_certificate
|
| + ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
|
| + rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
|
| +@@ -2667,7 +2764,7 @@
|
| + /*
|
| + * Send handshake_Failure alert. Set generic error number.
|
| + */
|
| +-static SECStatus
|
| ++SECStatus
|
| + ssl3_DecodeError(sslSocket *ss)
|
| + {
|
| + (void)SSL3_SendAlert(ss, alert_fatal,
|
| +@@ -2755,7 +2852,8 @@
|
| + default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break;
|
| + }
|
| + if (level == alert_fatal) {
|
| +- ss->sec.uncache(ss->sec.ci.sid);
|
| ++ if (!ss->opt.noCache)
|
| ++ ss->sec.uncache(ss->sec.ci.sid);
|
| + if ((ss->ssl3.hs.ws == wait_server_hello) &&
|
| + (desc == handshake_failure)) {
|
| + /* XXX This is a hack. We're assuming that any handshake failure
|
| +@@ -2806,17 +2904,22 @@
|
| + if (rv != SECSuccess) {
|
| + return rv; /* error code set by ssl3_FlushHandshake */
|
| + }
|
| +- sent = ssl3_SendRecord(ss, content_change_cipher_spec, &change, 1,
|
| +- ssl_SEND_FLAG_FORCE_INTO_BUFFER);
|
| +- if (sent < 0) {
|
| +- return (SECStatus)sent; /* error code set by ssl3_SendRecord */
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ sent = ssl3_SendRecord(ss, 0, content_change_cipher_spec, &change, 1,
|
| ++ ssl_SEND_FLAG_FORCE_INTO_BUFFER);
|
| ++ if (sent < 0) {
|
| ++ return (SECStatus)sent; /* error code set by ssl3_SendRecord */
|
| ++ }
|
| ++ } else {
|
| ++ rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv;
|
| ++ }
|
| + }
|
| +
|
| + /* swap the pending and current write specs. */
|
| + ssl_GetSpecWriteLock(ss); /**************************************/
|
| + pwSpec = ss->ssl3.pwSpec;
|
| +- pwSpec->write_seq_num.high = 0;
|
| +- pwSpec->write_seq_num.low = 0;
|
| +
|
| + ss->ssl3.pwSpec = ss->ssl3.cwSpec;
|
| + ss->ssl3.cwSpec = pwSpec;
|
| +@@ -2829,7 +2932,14 @@
|
| + * (Both the read and write sides have changed) destroy it.
|
| + */
|
| + if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
|
| +- ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/);
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/);
|
| ++ } else {
|
| ++ /* With DTLS, we need to set a holddown timer in case the final
|
| ++ * message got lost */
|
| ++ ss->ssl3.hs.rtTimeoutMs = DTLS_FINISHED_TIMER_MS;
|
| ++ dtls_StartTimer(ss, dtls_FinishedTimerCb);
|
| ++ }
|
| + }
|
| + ssl_ReleaseSpecWriteLock(ss); /**************************************/
|
| +
|
| +@@ -2878,7 +2988,6 @@
|
| + /* Swap the pending and current read specs. */
|
| + ssl_GetSpecWriteLock(ss); /*************************************/
|
| + prSpec = ss->ssl3.prSpec;
|
| +- prSpec->read_seq_num.high = prSpec->read_seq_num.low = 0;
|
| +
|
| + ss->ssl3.prSpec = ss->ssl3.crSpec;
|
| + ss->ssl3.crSpec = prSpec;
|
| +@@ -2981,6 +3090,11 @@
|
| + if (!isDH && pwSpec->master_secret && ss->opt.detectRollBack) {
|
| + SSL3ProtocolVersion client_version;
|
| + client_version = pms_version.major << 8 | pms_version.minor;
|
| ++
|
| ++ if (IS_DTLS(ss)) {
|
| ++ client_version = dtls_DTLSVersionToTLSVersion(client_version);
|
| ++ }
|
| ++
|
| + if (client_version != ss->clientHelloVersion) {
|
| + /* Destroy it. Version roll-back detected. */
|
| + PK11_FreeSymKey(pwSpec->master_secret);
|
| +@@ -3405,6 +3519,17 @@
|
| + {
|
| + SECStatus rv;
|
| +
|
| ++ /* If we already have a message in place, we need to enqueue it.
|
| ++ * This empties the buffer. This is a convenient place to call
|
| ++ * dtls_StageHandshakeMessage to mark the message boundary.
|
| ++ */
|
| ++ if (IS_DTLS(ss)) {
|
| ++ rv = dtls_StageHandshakeMessage(ss);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv;
|
| ++ }
|
| ++ }
|
| ++
|
| + SSL_TRC(30,("%d: SSL3[%d]: append handshake header: type %s",
|
| + SSL_GETPID(), ss->fd, ssl3_DecodeHandshakeType(t)));
|
| + PRINT_BUF(60, (ss, "MD5 handshake hash:",
|
| +@@ -3417,6 +3542,32 @@
|
| + return rv; /* error code set by AppendHandshake, if applicable. */
|
| + }
|
| + rv = ssl3_AppendHandshakeNumber(ss, length, 3);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv; /* error code set by AppendHandshake, if applicable. */
|
| ++ }
|
| ++
|
| ++ if (IS_DTLS(ss)) {
|
| ++ /* Note that we make an unfragmented message here. We fragment in the
|
| ++ * transmission code, if necessary */
|
| ++ rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.sendMessageSeq, 2);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv; /* error code set by AppendHandshake, if applicable. */
|
| ++ }
|
| ++ ss->ssl3.hs.sendMessageSeq++;
|
| ++
|
| ++ /* 0 is the fragment offset, because it's not fragmented yet */
|
| ++ rv = ssl3_AppendHandshakeNumber(ss, 0, 3);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv; /* error code set by AppendHandshake, if applicable. */
|
| ++ }
|
| ++
|
| ++ /* Fragment length -- set to the packet length because not fragmented */
|
| ++ rv = ssl3_AppendHandshakeNumber(ss, length, 3);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv; /* error code set by AppendHandshake, if applicable. */
|
| ++ }
|
| ++ }
|
| ++
|
| + return rv; /* error code set by AppendHandshake, if applicable. */
|
| + }
|
| +
|
| +@@ -3823,9 +3974,10 @@
|
| + /* Called from ssl3_HandleHelloRequest(),
|
| + * ssl3_RedoHandshake()
|
| + * ssl2_BeginClientHandshake (when resuming ssl3 session)
|
| ++ * dtls_HandleHelloVerifyRequest(with resending=PR_TRUE)
|
| + */
|
| + SECStatus
|
| +-ssl3_SendClientHello(sslSocket *ss)
|
| ++ssl3_SendClientHello(sslSocket *ss, PRBool resending)
|
| + {
|
| + sslSessionID * sid;
|
| + ssl3CipherSpec * cwSpec;
|
| +@@ -3849,6 +4001,7 @@
|
| + return rv; /* ssl3_InitState has set the error code. */
|
| + }
|
| + ss->ssl3.hs.sendingSCSV = PR_FALSE; /* Must be reset every handshake */
|
| ++ PORT_Assert(IS_DTLS(ss) || !resending);
|
| +
|
| + /* We might be starting a session renegotiation in which case we should
|
| + * clear previous state.
|
| +@@ -4008,6 +4161,10 @@
|
| + }
|
| + #endif
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ ssl3_DisableNonDTLSSuites(ss);
|
| ++ }
|
| ++
|
| + /* how many suites are permitted by policy and user preference? */
|
| + num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE);
|
| + if (!num_suites)
|
| +@@ -4027,6 +4184,9 @@
|
| + 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength) +
|
| + 2 + num_suites*sizeof(ssl3CipherSuite) +
|
| + 1 + numCompressionMethods + total_exten_len;
|
| ++ if (IS_DTLS(ss)) {
|
| ++ length += 1 + ss->ssl3.hs.cookieLen;
|
| ++ }
|
| +
|
| + rv = ssl3_AppendHandshakeHeader(ss, client_hello, length);
|
| + if (rv != SECSuccess) {
|
| +@@ -4034,13 +4194,23 @@
|
| + }
|
| +
|
| + ss->clientHelloVersion = ss->version;
|
| +- rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2);
|
| ++ if (IS_DTLS(ss)) {
|
| ++ PRUint16 version;
|
| ++
|
| ++ version = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion);
|
| ++ rv = ssl3_AppendHandshakeNumber(ss, version, 2);
|
| ++ } else {
|
| ++ rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2);
|
| ++ }
|
| + if (rv != SECSuccess) {
|
| + return rv; /* err set by ssl3_AppendHandshake* */
|
| + }
|
| +- rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random);
|
| +- if (rv != SECSuccess) {
|
| +- return rv; /* err set by GetNewRandom. */
|
| ++
|
| ++ if (!resending) { /* Don't re-generate if we are in DTLS re-sending mode */
|
| ++ rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv; /* err set by GetNewRandom. */
|
| ++ }
|
| + }
|
| + rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random,
|
| + SSL3_RANDOM_LENGTH);
|
| +@@ -4057,6 +4227,14 @@
|
| + return rv; /* err set by ssl3_AppendHandshake* */
|
| + }
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ rv = ssl3_AppendHandshakeVariable(
|
| ++ ss, ss->ssl3.hs.cookie, ss->ssl3.hs.cookieLen, 1);
|
| ++ if (rv != SECSuccess) {
|
| ++ return rv; /* err set by ssl3_AppendHandshake* */
|
| ++ }
|
| ++ }
|
| ++
|
| + rv = ssl3_AppendHandshakeNumber(ss, num_suites*sizeof(ssl3CipherSuite), 2);
|
| + if (rv != SECSuccess) {
|
| + return rv; /* err set by ssl3_AppendHandshake* */
|
| +@@ -4180,8 +4358,12 @@
|
| + ss->sec.ci.sid = NULL;
|
| + }
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ dtls_RehandshakeCleanup(ss);
|
| ++ }
|
| ++
|
| + ssl_GetXmitBufLock(ss);
|
| +- rv = ssl3_SendClientHello(ss);
|
| ++ rv = ssl3_SendClientHello(ss, PR_FALSE);
|
| + ssl_ReleaseXmitBufLock(ss);
|
| +
|
| + return rv;
|
| +@@ -5036,6 +5218,23 @@
|
| + }
|
| + version = (SSL3ProtocolVersion)temp;
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ /* RFC 4347 required that you verify that the server versions
|
| ++ * match (Section 4.2.1) in the HelloVerifyRequest and the
|
| ++ * ServerHello.
|
| ++ *
|
| ++ * RFC 6347 suggests (SHOULD) that servers always use 1.0
|
| ++ * in HelloVerifyRequest and allows the versions not to match,
|
| ++ * especially when 1.2 is being negotiated.
|
| ++ *
|
| ++ * Therefore we do not check for matching here.
|
| ++ */
|
| ++ version = dtls_DTLSVersionToTLSVersion(version);
|
| ++ if (version == 0) { /* Insane version number */
|
| ++ goto alert_loser;
|
| ++ }
|
| ++ }
|
| ++
|
| + rv = ssl3_NegotiateVersion(ss, version, PR_FALSE);
|
| + if (rv != SECSuccess) {
|
| + desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
|
| +@@ -6264,6 +6463,7 @@
|
| + SSL3AlertLevel level = alert_fatal;
|
| + SSL3ProtocolVersion version;
|
| + SECItem sidBytes = {siBuffer, NULL, 0};
|
| ++ SECItem cookieBytes = {siBuffer, NULL, 0};
|
| + SECItem suites = {siBuffer, NULL, 0};
|
| + SECItem comps = {siBuffer, NULL, 0};
|
| + PRBool haveSpecWriteLock = PR_FALSE;
|
| +@@ -6281,6 +6481,20 @@
|
| + return rv; /* error code is set. */
|
| + }
|
| +
|
| ++ /* Clearing the handshake pointers so that ssl_Do1stHandshake won't
|
| ++ * call ssl2_HandleMessage.
|
| ++ *
|
| ++ * The issue here is that TLS ordinarily starts out in
|
| ++ * ssl2_HandleV3HandshakeRecord() because of the backward-compatibility
|
| ++ * code paths. That function zeroes these next pointers. But with DTLS,
|
| ++ * we don't even try to do the v2 ClientHello so we skip that function
|
| ++ * and need to reset these values here.
|
| ++ */
|
| ++ if (IS_DTLS(ss)) {
|
| ++ ss->nextHandshake = 0;
|
| ++ ss->securityHandshake = 0;
|
| ++ }
|
| ++
|
| + /* We might be starting session renegotiation in which case we should
|
| + * clear previous state.
|
| + */
|
| +@@ -6306,10 +6520,22 @@
|
| + goto alert_loser;
|
| + }
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ dtls_RehandshakeCleanup(ss);
|
| ++ }
|
| ++
|
| + tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
|
| + if (tmp < 0)
|
| + goto loser; /* malformed, alert already sent */
|
| +- ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;
|
| ++
|
| ++ /* Translate the version */
|
| ++ if (IS_DTLS(ss)) {
|
| ++ ss->clientHelloVersion = version =
|
| ++ dtls_DTLSVersionToTLSVersion((SSL3ProtocolVersion)tmp);
|
| ++ } else {
|
| ++ ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;
|
| ++ }
|
| ++
|
| + rv = ssl3_NegotiateVersion(ss, version, PR_TRUE);
|
| + if (rv != SECSuccess) {
|
| + desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
|
| +@@ -6331,6 +6557,14 @@
|
| + goto loser; /* malformed */
|
| + }
|
| +
|
| ++ /* grab the client's cookie, if present. */
|
| ++ if (IS_DTLS(ss)) {
|
| ++ rv = ssl3_ConsumeHandshakeVariable(ss, &cookieBytes, 1, &b, &length);
|
| ++ if (rv != SECSuccess) {
|
| ++ goto loser; /* malformed */
|
| ++ }
|
| ++ }
|
| ++
|
| + /* grab the list of cipher suites. */
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &suites, 2, &b, &length);
|
| + if (rv != SECSuccess) {
|
| +@@ -6479,6 +6713,10 @@
|
| + ssl3_FilterECCipherSuitesByServerCerts(ss);
|
| + #endif
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ ssl3_DisableNonDTLSSuites(ss);
|
| ++ }
|
| ++
|
| + #ifdef PARANOID
|
| + /* Look for a matching cipher suite. */
|
| + j = ssl3_config_match_init(ss);
|
| +@@ -7166,17 +7404,28 @@
|
| + PRUint32 maxBytes = 65535;
|
| + PRUint32 length;
|
| + PRInt32 extensions_len = 0;
|
| ++ SSL3ProtocolVersion version;
|
| +
|
| + SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(),
|
| + ss->fd));
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| +- PORT_Assert( MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0));
|
| +
|
| +- if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) {
|
| +- PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
|
| +- return SECFailure;
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0));
|
| ++
|
| ++ if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) {
|
| ++ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
|
| ++ return SECFailure;
|
| ++ }
|
| ++ } else {
|
| ++ PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_DTLS_1_0));
|
| ++
|
| ++ if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_DTLS_1_0)) {
|
| ++ PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
|
| ++ return SECFailure;
|
| ++ }
|
| + }
|
| +
|
| + sid = ss->sec.ci.sid;
|
| +@@ -7194,7 +7443,13 @@
|
| + return rv; /* err set by AppendHandshake. */
|
| + }
|
| +
|
| +- rv = ssl3_AppendHandshakeNumber(ss, ss->version, 2);
|
| ++ if (IS_DTLS(ss)) {
|
| ++ version = dtls_TLSVersionToDTLSVersion(ss->version);
|
| ++ } else {
|
| ++ version = ss->version;
|
| ++ }
|
| ++
|
| ++ rv = ssl3_AppendHandshakeNumber(ss, version, 2);
|
| + if (rv != SECSuccess) {
|
| + return rv; /* err set by AppendHandshake. */
|
| + }
|
| +@@ -7379,11 +7634,8 @@
|
| + nnames = ca_list->nnames;
|
| + }
|
| +
|
| +- if (!nnames) {
|
| +- PORT_SetError(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA);
|
| +- return SECFailure;
|
| +- }
|
| +-
|
| ++ /* There used to be a test here to require a CA, but there
|
| ++ * are cases where you want to have no CAs offered. */
|
| + for (i = 0, name = names; i < nnames; i++, name++) {
|
| + calen += 2 + name->len;
|
| + }
|
| +@@ -7551,9 +7803,17 @@
|
| + }
|
| +
|
| + /* Generate the pre-master secret ... */
|
| +- version.major = MSB(ss->clientHelloVersion);
|
| +- version.minor = LSB(ss->clientHelloVersion);
|
| ++ if (IS_DTLS(ss)) {
|
| ++ SSL3ProtocolVersion temp;
|
| +
|
| ++ temp = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion);
|
| ++ version.major = MSB(temp);
|
| ++ version.minor = LSB(temp);
|
| ++ } else {
|
| ++ version.major = MSB(ss->clientHelloVersion);
|
| ++ version.minor = LSB(ss->clientHelloVersion);
|
| ++ }
|
| ++
|
| + param.data = (unsigned char *)&version;
|
| + param.len = sizeof version;
|
| +
|
| +@@ -7635,6 +7895,11 @@
|
| + } else if (ss->opt.detectRollBack) {
|
| + SSL3ProtocolVersion client_version =
|
| + (rsaPmsBuf[0] << 8) | rsaPmsBuf[1];
|
| ++
|
| ++ if (IS_DTLS(ss)) {
|
| ++ client_version = dtls_DTLSVersionToTLSVersion(client_version);
|
| ++ }
|
| ++
|
| + if (client_version != ss->clientHelloVersion) {
|
| + /* Version roll-back detected. ensure failure. */
|
| + rv = PK11_GenerateRandom(rsaPmsBuf, sizeof rsaPmsBuf);
|
| +@@ -8851,6 +9116,10 @@
|
| + }
|
| + }
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ flags |= ssl_SEND_FLAG_NO_RETRANSMIT;
|
| ++ }
|
| ++
|
| + rv = ssl3_SendFinished(ss, flags);
|
| + if (rv != SECSuccess) {
|
| + goto xmit_loser; /* err is set. */
|
| +@@ -8980,13 +9249,14 @@
|
| + * hanshake message.
|
| + * Caller must hold Handshake and RecvBuf locks.
|
| + */
|
| +-static SECStatus
|
| ++SECStatus
|
| + ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| + {
|
| + SECStatus rv = SECSuccess;
|
| + SSL3HandshakeType type = ss->ssl3.hs.msg_type;
|
| + SSL3Hashes hashes; /* computed hashes are put here. */
|
| + PRUint8 hdr[4];
|
| ++ PRUint8 dtlsData[8];
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| +@@ -9032,10 +9302,35 @@
|
| + return rv;
|
| + }
|
| + }
|
| +- /* We should not include hello_request messages in the handshake hashes */
|
| +- if (ss->ssl3.hs.msg_type != hello_request) {
|
| ++ /* We should not include hello_request and hello_verify_request messages
|
| ++ * in the handshake hashes */
|
| ++ if ((ss->ssl3.hs.msg_type != hello_request) &&
|
| ++ (ss->ssl3.hs.msg_type != hello_verify_request)) {
|
| + rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) hdr, 4);
|
| + if (rv != SECSuccess) return rv; /* err code already set. */
|
| ++
|
| ++ /* Extra data to simulate a complete DTLS handshake fragment */
|
| ++ if (IS_DTLS(ss)) {
|
| ++ /* Sequence number */
|
| ++ dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq);
|
| ++ dtlsData[1] = LSB(ss->ssl3.hs.recvMessageSeq);
|
| ++
|
| ++ /* Fragment offset */
|
| ++ dtlsData[2] = 0;
|
| ++ dtlsData[3] = 0;
|
| ++ dtlsData[4] = 0;
|
| ++
|
| ++ /* Fragment length */
|
| ++ dtlsData[5] = (PRUint8)(length >> 16);
|
| ++ dtlsData[6] = (PRUint8)(length >> 8);
|
| ++ dtlsData[7] = (PRUint8)(length );
|
| ++
|
| ++ rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) dtlsData,
|
| ++ sizeof(dtlsData));
|
| ++ if (rv != SECSuccess) return rv; /* err code already set. */
|
| ++ }
|
| ++
|
| ++ /* The message body */
|
| + rv = ssl3_UpdateHandshakeHashes(ss, b, length);
|
| + if (rv != SECSuccess) return rv; /* err code already set. */
|
| + }
|
| +@@ -9071,6 +9366,14 @@
|
| + }
|
| + rv = ssl3_HandleServerHello(ss, b, length);
|
| + break;
|
| ++ case hello_verify_request:
|
| ++ if (!IS_DTLS(ss) || ss->sec.isServer) {
|
| ++ (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
|
| ++ PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST);
|
| ++ return SECFailure;
|
| ++ }
|
| ++ rv = dtls_HandleHelloVerifyRequest(ss, b, length);
|
| ++ break;
|
| + case certificate:
|
| + if (ss->ssl3.hs.may_get_cert_status) {
|
| + /* If we might get a CertificateStatus then we want to postpone the
|
| +@@ -9169,6 +9472,12 @@
|
| + PORT_SetError(SSL_ERROR_RX_UNKNOWN_HANDSHAKE);
|
| + rv = SECFailure;
|
| + }
|
| ++
|
| ++ if (IS_DTLS(ss) && (rv == SECSuccess)) {
|
| ++ /* Increment the expected sequence number */
|
| ++ ss->ssl3.hs.recvMessageSeq++;
|
| ++ }
|
| ++
|
| + return rv;
|
| + }
|
| +
|
| +@@ -9331,6 +9640,7 @@
|
| + SSL3Opaque hash[MAX_MAC_LENGTH];
|
| + sslBuffer *plaintext;
|
| + sslBuffer temp_buf;
|
| ++ PRUint64 dtls_seq_num;
|
| + unsigned int ivLen = 0;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| +@@ -9366,6 +9676,39 @@
|
| + crSpec = ss->ssl3.crSpec;
|
| + cipher_def = crSpec->cipher_def;
|
| +
|
| ++ /*
|
| ++ * 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 (IS_DTLS(ss)) {
|
| ++ DTLSEpoch epoch = (cText->seq_num.high >> 16) & 0xffff;
|
| ++
|
| ++ if (crSpec->epoch != epoch) {
|
| ++ ssl_ReleaseSpecReadLock(ss);
|
| ++ SSL_DBG(("%d: SSL3[%d]: HandleRecord, received packet "
|
| ++ "from irrelevant epoch %d", SSL_GETPID(), ss->fd, epoch));
|
| ++ /* Silently drop the packet */
|
| ++ databuf->len = 0; /* Needed to ensure data not left around */
|
| ++ return SECSuccess;
|
| ++ }
|
| ++
|
| ++ 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_ReleaseSpecReadLock(ss);
|
| ++ SSL_DBG(("%d: SSL3[%d]: HandleRecord, rejecting "
|
| ++ "potentially replayed packet", SSL_GETPID(), ss->fd));
|
| ++ /* Silently drop the packet */
|
| ++ databuf->len = 0; /* Needed to ensure data not left around */
|
| ++ return SECSuccess;
|
| ++ }
|
| ++ }
|
| ++
|
| + if (cipher_def->type == type_block &&
|
| + crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
|
| + /* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states
|
| +@@ -9487,7 +9830,8 @@
|
| + /* compute the MAC */
|
| + rType = cText->type;
|
| + rv = ssl3_ComputeRecordMAC( crSpec, (PRBool)(!ss->sec.isServer),
|
| +- rType, cText->version, crSpec->read_seq_num,
|
| ++ IS_DTLS(ss), rType, cText->version,
|
| ++ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
|
| + plaintext->buf, plaintext->len, hash, &hashBytes);
|
| + if (rv != SECSuccess) {
|
| + padIsBad = PR_TRUE; /* really macIsBad */
|
| +@@ -9499,19 +9843,27 @@
|
| + crSpec->mac_size) != 0) {
|
| + /* must not hold spec lock when calling SSL3_SendAlert. */
|
| + ssl_ReleaseSpecReadLock(ss);
|
| +- SSL3_SendAlert(ss, alert_fatal, bad_record_mac);
|
| +- /* always log mac error, in case attacker can read server logs. */
|
| +- PORT_SetError(SSL_ERROR_BAD_MAC_READ);
|
| +
|
| + SSL_DBG(("%d: SSL3[%d]: mac check failed", SSL_GETPID(), ss->fd));
|
| +
|
| +- return SECFailure;
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ SSL3_SendAlert(ss, alert_fatal, bad_record_mac);
|
| ++ /* always log mac error, in case attacker can read server logs. */
|
| ++ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
|
| ++ return SECFailure;
|
| ++ } else {
|
| ++ /* Silently drop the packet */
|
| ++ databuf->len = 0; /* Needed to ensure data not left around */
|
| ++ return SECSuccess;
|
| ++ }
|
| + }
|
| +
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ ssl3_BumpSequenceNumber(&crSpec->read_seq_num);
|
| ++ } else {
|
| ++ dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num);
|
| ++ }
|
| +
|
| +-
|
| +- ssl3_BumpSequenceNumber(&crSpec->read_seq_num);
|
| +-
|
| + ssl_ReleaseSpecReadLock(ss); /*****************************************/
|
| +
|
| + /*
|
| +@@ -9615,7 +9967,11 @@
|
| + rv = ssl3_HandleAlert(ss, databuf);
|
| + break;
|
| + case content_handshake:
|
| +- rv = ssl3_HandleHandshake(ss, databuf);
|
| ++ if (!IS_DTLS(ss)) {
|
| ++ rv = ssl3_HandleHandshake(ss, databuf);
|
| ++ } else {
|
| ++ rv = dtls_HandleHandshake(ss, databuf);
|
| ++ }
|
| + break;
|
| + /*
|
| + case content_application_data is handled before this switch
|
| +@@ -9675,6 +10031,9 @@
|
| + spec->read_seq_num.high = 0;
|
| + spec->read_seq_num.low = 0;
|
| +
|
| ++ spec->epoch = 0;
|
| ++ dtls_InitRecvdRecords(&spec->recvdRecords);
|
| ++
|
| + spec->version = ss->vrange.max;
|
| + }
|
| +
|
| +@@ -9716,6 +10075,21 @@
|
| +
|
| + PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
|
| +
|
| ++ if (IS_DTLS(ss)) {
|
| ++ ss->ssl3.hs.sendMessageSeq = 0;
|
| ++ ss->ssl3.hs.recvMessageSeq = 0;
|
| ++ ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS;
|
| ++ ss->ssl3.hs.rtRetries = 0;
|
| ++
|
| ++ /* Have to allocate this because ssl_FreeSocket relocates
|
| ++ * this structure in DEBUG mode */
|
| ++ if (!(ss->ssl3.hs.lastMessageFlight = PORT_New(PRCList)))
|
| ++ return SECFailure;
|
| ++ ss->ssl3.hs.recvdHighWater = -1;
|
| ++ PR_INIT_CLIST(ss->ssl3.hs.lastMessageFlight);
|
| ++ dtls_SetMTU(ss, 0); /* Set the MTU to the highest plateau */
|
| ++ }
|
| ++
|
| + rv = ssl3_NewHandshakeHashes(ss);
|
| + if (rv == SECSuccess) {
|
| + ss->ssl3.initialized = PR_TRUE;
|
| +@@ -9968,6 +10342,11 @@
|
| + PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
|
| + return SECFailure;
|
| + }
|
| ++
|
| ++ if (IS_DTLS(ss)) {
|
| ++ dtls_RehandshakeCleanup(ss);
|
| ++ }
|
| ++
|
| + if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
|
| + PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
|
| + return SECFailure;
|
| +@@ -9982,7 +10361,7 @@
|
| +
|
| + /* start off a new handshake. */
|
| + rv = (ss->sec.isServer) ? ssl3_SendHelloRequest(ss)
|
| +- : ssl3_SendClientHello(ss);
|
| ++ : ssl3_SendClientHello(ss, PR_FALSE);
|
| +
|
| + ssl_ReleaseXmitBufLock(ss); /**************************************/
|
| + return rv;
|
| +@@ -10042,6 +10421,17 @@
|
| + ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE/*freeSrvName*/);
|
| + ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/);
|
| +
|
| ++ /* Destroy the DTLS data */
|
| ++ if (IS_DTLS(ss)) {
|
| ++ if (ss->ssl3.hs.lastMessageFlight) {
|
| ++ dtls_FreeHandshakeMessages(ss->ssl3.hs.lastMessageFlight);
|
| ++ PORT_Free(ss->ssl3.hs.lastMessageFlight);
|
| ++ }
|
| ++ if (ss->ssl3.hs.recvdFragments.buf) {
|
| ++ PORT_Free(ss->ssl3.hs.recvdFragments.buf);
|
| ++ }
|
| ++ }
|
| ++
|
| + ss->ssl3.initialized = PR_FALSE;
|
| +
|
| + SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
| +Index: net/third_party/nss/ssl/sslgathr.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslgathr.c (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslgathr.c (working copy)
|
| +@@ -434,6 +434,8 @@
|
| + gs->state = GS_INIT;
|
| + gs->writeOffset = 0;
|
| + gs->readOffset = 0;
|
| ++ gs->dtlsPacketOffset = 0;
|
| ++ gs->dtlsPacket.len = 0;
|
| + status = sslBuffer_Grow(&gs->buf, 4096);
|
| + return status;
|
| + }
|
| +@@ -445,6 +447,7 @@
|
| + if (gs) { /* the PORT_*Free functions check for NULL pointers. */
|
| + PORT_ZFree(gs->buf.buf, gs->buf.space);
|
| + PORT_Free(gs->inbuf.buf);
|
| ++ PORT_Free(gs->dtlsPacket.buf);
|
| + }
|
| + }
|
| +
|
| +Index: net/third_party/nss/ssl/dtls1con.c
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/dtls1con.c (revision 0)
|
| ++++ net/third_party/nss/ssl/dtls1con.c (revision 0)
|
| +@@ -0,0 +1,1163 @@
|
| ++/*
|
| ++ * DTLS Protocol
|
| ++ *
|
| ++ * ***** BEGIN LICENSE BLOCK *****
|
| ++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
| ++ *
|
| ++ * The contents of this file are subject to the Mozilla Public License Version
|
| ++ * 1.1 (the "License"); you may not use this file except in compliance with
|
| ++ * the License. You may obtain a copy of the License at
|
| ++ * http://www.mozilla.org/MPL/
|
| ++ *
|
| ++ * Software distributed under the License is distributed on an "AS IS" basis,
|
| ++ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
| ++ * for the specific language governing rights and limitations under the
|
| ++ * License.
|
| ++ *
|
| ++ * The Original Code is the Netscape security libraries.
|
| ++ *
|
| ++ * The Initial Developer of the Original Code is
|
| ++ * Netscape Communications Corporation.
|
| ++ * Portions created by the Initial Developer are Copyright (C) 1994-2000
|
| ++ * the Initial Developer. All Rights Reserved.
|
| ++ *
|
| ++ * Contributor(s):
|
| ++ * Eric Rescorla <ekr@rtfm.com>
|
| ++ *
|
| ++ * Alternatively, the contents of this file may be used under the terms of
|
| ++ * either the GNU General Public License Version 2 or later (the "GPL"), or
|
| ++ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
| ++ * in which case the provisions of the GPL or the LGPL are applicable instead
|
| ++ * of those above. If you wish to allow use of your version of this file only
|
| ++ * under the terms of either the GPL or the LGPL, and not to allow others to
|
| ++ * use your version of this file under the terms of the MPL, indicate your
|
| ++ * decision by deleting the provisions above and replace them with the notice
|
| ++ * and other provisions required by the GPL or the LGPL. If you do not delete
|
| ++ * the provisions above, a recipient may use your version of this file under
|
| ++ * the terms of any one of the MPL, the GPL or the LGPL.
|
| ++ *
|
| ++ * ***** END LICENSE BLOCK ***** */
|
| ++/* $Id: $ */
|
| ++
|
| ++#include "ssl.h"
|
| ++#include "sslimpl.h"
|
| ++#include "sslproto.h"
|
| ++
|
| ++#ifndef PR_ARRAY_SIZE
|
| ++#define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
| ++#endif
|
| ++
|
| ++static SECStatus dtls_TransmitMessageFlight(sslSocket *ss);
|
| ++static void dtls_RetransmitTimerExpiredCb(sslSocket *ss);
|
| ++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 */
|
| ++};
|
| ++
|
| ++#define DTLS_COOKIE_BYTES 32
|
| ++
|
| ++/* List copied from ssl3con.c:cipherSuites */
|
| ++static const ssl3CipherSuite nonDTLSSuites[] = {
|
| ++#ifdef NSS_ENABLE_ECC
|
| ++ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
| ++ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
| ++#endif /* NSS_ENABLE_ECC */
|
| ++ TLS_DHE_DSS_WITH_RC4_128_SHA,
|
| ++#ifdef NSS_ENABLE_ECC
|
| ++ TLS_ECDH_RSA_WITH_RC4_128_SHA,
|
| ++ TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
|
| ++#endif /* NSS_ENABLE_ECC */
|
| ++ SSL_RSA_WITH_RC4_128_MD5,
|
| ++ SSL_RSA_WITH_RC4_128_SHA,
|
| ++ TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
|
| ++ SSL_RSA_EXPORT_WITH_RC4_40_MD5,
|
| ++ 0 /* End of list marker */
|
| ++};
|
| ++
|
| ++/* Map back and forth between TLS and DTLS versions in wire format.
|
| ++ * Mapping table is:
|
| ++ *
|
| ++ * TLS DTLS
|
| ++ * 1.1 (0302) 1.0 (feff)
|
| ++ */
|
| ++SSL3ProtocolVersion
|
| ++dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv)
|
| ++{
|
| ++ /* Anything other than TLS 1.1 is an error, so return
|
| ++ * the invalid version ffff. */
|
| ++ if (tlsv != SSL_LIBRARY_VERSION_TLS_1_1)
|
| ++ return 0xffff;
|
| ++
|
| ++ return SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
|
| ++}
|
| ++
|
| ++/* Map known DTLS versions to known TLS versions.
|
| ++ * - Invalid versions (< 1.0) return a version of 0
|
| ++ * - Versions > known return a version one higher than we know of
|
| ++ * to accomodate a theoretically newer version */
|
| ++SSL3ProtocolVersion
|
| ++dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv)
|
| ++{
|
| ++ if (MSB(dtlsv) == 0xff) {
|
| ++ return 0;
|
| ++ }
|
| ++
|
| ++ if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_0_WIRE)
|
| ++ return SSL_LIBRARY_VERSION_TLS_1_1;
|
| ++
|
| ++ /* Return a fictional higher version than we know of */
|
| ++ return SSL_LIBRARY_VERSION_TLS_1_1 + 1;
|
| ++}
|
| ++
|
| ++/* On this socket, Disable non-DTLS cipher suites in the argument's list */
|
| ++SECStatus
|
| ++ssl3_DisableNonDTLSSuites(sslSocket * ss)
|
| ++{
|
| ++ const ssl3CipherSuite * suite;
|
| ++
|
| ++ for (suite = nonDTLSSuites; *suite; ++suite) {
|
| ++ SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE);
|
| ++
|
| ++ PORT_Assert(rv == SECSuccess); /* else is coding error */
|
| ++ }
|
| ++ return SECSuccess;
|
| ++}
|
| ++
|
| ++/* Allocate a DTLSQueuedMessage.
|
| ++ *
|
| ++ * Called from dtls_QueueMessage()
|
| ++ */
|
| ++static DTLSQueuedMessage *
|
| ++dtls_AllocQueuedMessage(PRUint16 epoch, SSL3ContentType type,
|
| ++ const unsigned char *data, PRUint32 len)
|
| ++{
|
| ++ DTLSQueuedMessage *msg = NULL;
|
| ++
|
| ++ msg = PORT_ZAlloc(sizeof(DTLSQueuedMessage));
|
| ++ if (!msg)
|
| ++ return NULL;
|
| ++
|
| ++ msg->data = PORT_Alloc(len);
|
| ++ if (!msg->data) {
|
| ++ PORT_Free(msg);
|
| ++ return NULL;
|
| ++ }
|
| ++ PORT_Memcpy(msg->data, data, len);
|
| ++
|
| ++ msg->len = len;
|
| ++ msg->epoch = epoch;
|
| ++ msg->type = type;
|
| ++
|
| ++ return msg;
|
| ++}
|
| ++
|
| ++/*
|
| ++ * Free a handshake message
|
| ++ *
|
| ++ * Called from dtls_FreeHandshakeMessages()
|
| ++ */
|
| ++static void
|
| ++dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg)
|
| ++{
|
| ++ if (!msg)
|
| ++ return;
|
| ++
|
| ++ PORT_ZFree(msg->data, msg->len);
|
| ++ PORT_Free(msg);
|
| ++}
|
| ++
|
| ++/*
|
| ++ * Free a list of handshake messages
|
| ++ *
|
| ++ * Called from:
|
| ++ * dtls_HandleHandshake()
|
| ++ * ssl3_DestroySSL3Info()
|
| ++ */
|
| ++void
|
| ++dtls_FreeHandshakeMessages(PRCList *list)
|
| ++{
|
| ++ PRCList *cur_p;
|
| ++
|
| ++ while (!PR_CLIST_IS_EMPTY(list)) {
|
| ++ cur_p = PR_LIST_TAIL(list);
|
| ++ PR_REMOVE_LINK(cur_p);
|
| ++ dtls_FreeHandshakeMessage((DTLSQueuedMessage *)cur_p);
|
| ++ }
|
| ++}
|
| ++
|
| ++/* Called only from ssl3_HandleRecord, for each (deciphered) DTLS record.
|
| ++ * origBuf is the decrypted ssl record content and is expected to contain
|
| ++ * complete handshake records
|
| ++ * Caller must hold the handshake and RecvBuf locks.
|
| ++ *
|
| ++ * Note that this code uses msg_len for two purposes:
|
| ++ *
|
| ++ * (1) To pass the length to ssl3_HandleHandshakeMessage()
|
| ++ * (2) To carry the length of a message currently being reassembled
|
| ++ *
|
| ++ * However, unlike ssl3_HandleHandshake(), it is not used to carry
|
| ++ * 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))
|
| ++
|
| ++SECStatus
|
| ++dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| ++{
|
| ++ /* XXX OK for now.
|
| ++ * This doesn't work properly with asynchronous certificate validation.
|
| ++ * because that returns a WOULDBLOCK error. The current DTLS
|
| ++ * applications do not need asynchronous validation, but in the
|
| ++ * future we will need to add this.
|
| ++ */
|
| ++ sslBuffer buf = *origBuf;
|
| ++ SECStatus rv = SECSuccess;
|
| ++
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| ++
|
| ++ while (buf.len > 0) {
|
| ++ PRUint8 type;
|
| ++ PRUint32 message_length;
|
| ++ PRUint16 message_seq;
|
| ++ PRUint32 fragment_offset;
|
| ++ PRUint32 fragment_length;
|
| ++ PRUint32 offset;
|
| ++
|
| ++ if (buf.len < 12) {
|
| ++ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
| ++ rv = SECFailure;
|
| ++ break;
|
| ++ }
|
| ++
|
| ++ /* Parse the header */
|
| ++ type = buf.buf[0];
|
| ++ message_length = (buf.buf[1] << 16) | (buf.buf[2] << 8) | buf.buf[3];
|
| ++ message_seq = (buf.buf[4] << 8) | buf.buf[5];
|
| ++ 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 */
|
| ++ if (message_length > MAX_HANDSHAKE_MSG_LEN) {
|
| ++ (void)ssl3_DecodeError(ss);
|
| ++ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
|
| ++ return SECFailure;
|
| ++ }
|
| ++#undef MAX_HANDSHAKE_MSG_LEN
|
| ++
|
| ++ buf.buf += 12;
|
| ++ buf.len -= 12;
|
| ++
|
| ++ /* This fragment must be complete */
|
| ++ if (buf.len < fragment_length) {
|
| ++ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
| ++ rv = SECFailure;
|
| ++ break;
|
| ++ }
|
| ++
|
| ++ /* Sanity check the packet contents */
|
| ++ if ((fragment_length + fragment_offset) > message_length) {
|
| ++ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
| ++ rv = SECFailure;
|
| ++ break;
|
| ++ }
|
| ++
|
| ++ /* There are three ways we could not be ready for this packet.
|
| ++ *
|
| ++ * 1. It's a partial next message.
|
| ++ * 2. It's a partial or complete message beyond the next
|
| ++ * 3. It's a message we've already seen
|
| ++ *
|
| ++ * 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)) {
|
| ++ /* Complete next message. Process immediately */
|
| ++ ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
|
| ++ ss->ssl3.hs.msg_len = message_length;
|
| ++
|
| ++ /* At this point we are advancing our state machine, so
|
| ++ * we can free our last flight of messages */
|
| ++ dtls_FreeHandshakeMessages(ss->ssl3.hs.lastMessageFlight);
|
| ++ ss->ssl3.hs.recvdHighWater = -1;
|
| ++ dtls_CancelTimer(ss);
|
| ++
|
| ++ /* Reset the timer to the initial value if the retry counter
|
| ++ * is 0, per Sec. 4.2.4.1 */
|
| ++ if (ss->ssl3.hs.rtRetries == 0) {
|
| ++ ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS;
|
| ++ }
|
| ++
|
| ++ rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len);
|
| ++ if (rv == SECFailure) {
|
| ++ /* Do not attempt to process rest of messages in this record */
|
| ++ break;
|
| ++ }
|
| ++ } else {
|
| ++ if (message_seq < ss->ssl3.hs.recvMessageSeq) {
|
| ++ /* Case 3: we do an immediate retransmit if we're
|
| ++ * in a waiting state*/
|
| ++ if (ss->ssl3.hs.rtTimerCb == NULL) {
|
| ++ /* Ignore */
|
| ++ } else if (ss->ssl3.hs.rtTimerCb ==
|
| ++ dtls_RetransmitTimerExpiredCb) {
|
| ++ SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected",
|
| ++ SSL_GETPID(), ss->fd));
|
| ++ /* Check to see if we retransmitted recently. If so,
|
| ++ * suppress the triggered retransmit. This avoids
|
| ++ * retransmit wars after packet loss.
|
| ++ * This is not in RFC 5346 but should be
|
| ++ */
|
| ++ 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;
|
| ++ }
|
| ++ } 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.
|
| ++ * The spec isn't clear and my reasoning is that this
|
| ++ * may be a re-ordered packet rather than slowness,
|
| ++ * so let's be aggressive. */
|
| ++ dtls_CancelTimer(ss);
|
| ++ rv = dtls_TransmitMessageFlight(ss);
|
| ++ if (rv == SECSuccess) {
|
| ++ rv = dtls_StartTimer(ss, dtls_FinishedTimerCb);
|
| ++ }
|
| ++ if (rv != SECSuccess)
|
| ++ return rv;
|
| ++ break;
|
| ++ }
|
| ++ } else if (message_seq > ss->ssl3.hs.recvMessageSeq) {
|
| ++ /* Case 2
|
| ++ *
|
| ++ * Ignore this message. This means we don't handle out of
|
| ++ * order complete messages that well, but we're still
|
| ++ * compliant and this probably does not happen often
|
| ++ *
|
| ++ * XXX OK for now. Maybe do something smarter at some point?
|
| ++ */
|
| ++ } else {
|
| ++ /* Case 1
|
| ++ *
|
| ++ * Buffer the fragment for reassembly
|
| ++ */
|
| ++ /* Make room for the message */
|
| ++ if (ss->ssl3.hs.recvdHighWater == -1) {
|
| ++ PRUint32 map_length = OFFSET_BYTE(message_length) + 1;
|
| ++
|
| ++ rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length);
|
| ++ if (rv != SECSuccess)
|
| ++ break;
|
| ++ /* Make room for the fragment map */
|
| ++ rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments,
|
| ++ map_length);
|
| ++ if (rv != SECSuccess)
|
| ++ break;
|
| ++
|
| ++ /* Reset the reassembly map */
|
| ++ ss->ssl3.hs.recvdHighWater = 0;
|
| ++ PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0,
|
| ++ ss->ssl3.hs.recvdFragments.space);
|
| ++ ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
|
| ++ ss->ssl3.hs.msg_len = message_length;
|
| ++ }
|
| ++
|
| ++ /* If we have a message length mismatch, abandon the reassembly
|
| ++ * in progress and hope that the next retransmit will give us
|
| ++ * something sane
|
| ++ */
|
| ++ if (message_length != ss->ssl3.hs.msg_len) {
|
| ++ ss->ssl3.hs.recvdHighWater = -1;
|
| ++ PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
| ++ rv = SECFailure;
|
| ++ break;
|
| ++ }
|
| ++
|
| ++ /* Now copy this fragment into the buffer */
|
| ++ PORT_Assert((fragment_offset + fragment_length) <=
|
| ++ ss->ssl3.hs.msg_body.space);
|
| ++ PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset,
|
| ++ buf.buf, fragment_length);
|
| ++
|
| ++ /* This logic is a bit tricky. We have two values for
|
| ++ * reassembly state:
|
| ++ *
|
| ++ * - recvdHighWater contains the highest contiguous number of
|
| ++ * bytes received
|
| ++ * - recvdFragments contains a bitmask of packets received
|
| ++ * above recvdHighWater
|
| ++ *
|
| ++ * This avoids having to fill in the bitmask in the common
|
| ++ * case of adjacent fragments received in sequence
|
| ++ */
|
| ++ if (fragment_offset <= ss->ssl3.hs.recvdHighWater) {
|
| ++ /* Either this is the adjacent fragment or an overlapping
|
| ++ * fragment */
|
| ++ ss->ssl3.hs.recvdHighWater = fragment_offset +
|
| ++ fragment_length;
|
| ++ } else {
|
| ++ for (offset = fragment_offset;
|
| ++ offset < fragment_offset + fragment_length;
|
| ++ offset++) {
|
| ++ ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |=
|
| ++ OFFSET_MASK(offset);
|
| ++ }
|
| ++ }
|
| ++
|
| ++ /* Now figure out the new high water mark if appropriate */
|
| ++ for (offset = ss->ssl3.hs.recvdHighWater;
|
| ++ offset < ss->ssl3.hs.msg_len; offset++) {
|
| ++ /* Note that this loop is not efficient, since it counts
|
| ++ * bit by bit. If we have a lot of out-of-order packets,
|
| ++ * we should optimize this */
|
| ++ if (ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] &
|
| ++ OFFSET_MASK(offset)) {
|
| ++ ss->ssl3.hs.recvdHighWater++;
|
| ++ } else {
|
| ++ break;
|
| ++ }
|
| ++ }
|
| ++
|
| ++ /* If we have all the bytes, then we are good to go */
|
| ++ if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) {
|
| ++ ss->ssl3.hs.recvdHighWater = -1;
|
| ++
|
| ++ rv = ssl3_HandleHandshakeMessage(ss,
|
| ++ ss->ssl3.hs.msg_body.buf,
|
| ++ ss->ssl3.hs.msg_len);
|
| ++ if (rv == SECFailure)
|
| ++ break; /* Skip rest of record */
|
| ++
|
| ++ /* At this point we are advancing our state machine, so
|
| ++ * we can free our last flight of messages */
|
| ++ dtls_FreeHandshakeMessages(ss->ssl3.hs.lastMessageFlight);
|
| ++ dtls_CancelTimer(ss);
|
| ++
|
| ++ /* If there have been no retries this time, reset the
|
| ++ * timer value to the default per Section 4.2.4.1 */
|
| ++ if (ss->ssl3.hs.rtRetries == 0) {
|
| ++ ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS;
|
| ++ }
|
| ++ }
|
| ++ }
|
| ++ }
|
| ++
|
| ++ buf.buf += fragment_length;
|
| ++ buf.len -= fragment_length;
|
| ++ }
|
| ++
|
| ++ 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 */
|
| ++ return rv;
|
| ++}
|
| ++
|
| ++/* Enqueue a message (either handshake or CCS)
|
| ++ *
|
| ++ * Called from:
|
| ++ * dtls_StageHandshakeMessage()
|
| ++ * ssl3_SendChangeCipherSpecs()
|
| ++ */
|
| ++SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type,
|
| ++ const SSL3Opaque *pIn, PRInt32 nIn)
|
| ++{
|
| ++ SECStatus rv = SECSuccess;
|
| ++ DTLSQueuedMessage *msg = NULL;
|
| ++
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| ++
|
| ++ msg = dtls_AllocQueuedMessage(ss->ssl3.cwSpec->epoch, type, pIn, nIn);
|
| ++
|
| ++ if (!msg) {
|
| ++ PORT_SetError(SEC_ERROR_NO_MEMORY);
|
| ++ rv = SECFailure;
|
| ++ } else {
|
| ++ PR_APPEND_LINK(&msg->link, ss->ssl3.hs.lastMessageFlight);
|
| ++ }
|
| ++
|
| ++ return rv;
|
| ++}
|
| ++
|
| ++/* Add DTLS handshake message to the pending queue
|
| ++ * Empty the sendBuf buffer.
|
| ++ * This function returns SECSuccess or SECFailure, never SECWouldBlock.
|
| ++ * Always set sendBuf.len to 0, even when returning SECFailure.
|
| ++ *
|
| ++ * Called from:
|
| ++ * ssl3_AppendHandshakeHeader()
|
| ++ * dtls_FlushHandshake()
|
| ++ */
|
| ++SECStatus
|
| ++dtls_StageHandshakeMessage(sslSocket *ss)
|
| ++{
|
| ++ SECStatus rv = SECSuccess;
|
| ++
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| ++
|
| ++ /* This function is sometimes called when no data is actually to
|
| ++ * be staged, so just return SECSuccess. */
|
| ++ if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
|
| ++ return rv;
|
| ++
|
| ++ rv = dtls_QueueMessage(ss, content_handshake,
|
| ++ ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len);
|
| ++
|
| ++ /* Whether we succeeded or failed, toss the old handshake data. */
|
| ++ ss->sec.ci.sendBuf.len = 0;
|
| ++ return rv;
|
| ++}
|
| ++
|
| ++/* Enqueue the handshake message in sendBuf (if any) and then
|
| ++ * transmit the resulting flight of handshake messages.
|
| ++ *
|
| ++ * Called from:
|
| ++ * ssl3_FlushHandshake()
|
| ++ */
|
| ++SECStatus
|
| ++dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
|
| ++{
|
| ++ SECStatus rv = SECSuccess;
|
| ++
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| ++
|
| ++ rv = dtls_StageHandshakeMessage(ss);
|
| ++ if (rv != SECSuccess)
|
| ++ return rv;
|
| ++
|
| ++ if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
|
| ++ rv = dtls_TransmitMessageFlight(ss);
|
| ++ if (rv != SECSuccess)
|
| ++ return rv;
|
| ++
|
| ++ if (!(flags & ssl_SEND_FLAG_NO_RETRANSMIT)) {
|
| ++ ss->ssl3.hs.rtRetries = 0;
|
| ++ rv = dtls_StartTimer(ss, dtls_RetransmitTimerExpiredCb);
|
| ++ }
|
| ++ }
|
| ++
|
| ++ return rv;
|
| ++}
|
| ++
|
| ++/* The callback for when the retransmit timer expires
|
| ++ *
|
| ++ * Called from:
|
| ++ * dtls_CheckTimer()
|
| ++ * dtls_HandleHandshake()
|
| ++ */
|
| ++static void
|
| ++dtls_RetransmitTimerExpiredCb(sslSocket *ss)
|
| ++{
|
| ++ SECStatus rv = SECFailure;
|
| ++
|
| ++ ss->ssl3.hs.rtRetries++;
|
| ++
|
| ++ if (!(ss->ssl3.hs.rtRetries % 3)) {
|
| ++ /* If one of the messages was potentially greater than > MTU,
|
| ++ * then downgrade. Do this every time we have retransmitted a
|
| ++ * message twice, per RFC 6347 Sec. 4.1.1 */
|
| ++ dtls_SetMTU(ss, ss->ssl3.hs.maxMessageSent - 1);
|
| ++ }
|
| ++
|
| ++ rv = dtls_TransmitMessageFlight(ss);
|
| ++ if (rv == SECSuccess) {
|
| ++
|
| ++ /* Re-arm the timer */
|
| ++ rv = dtls_RestartTimer(ss, PR_TRUE, dtls_RetransmitTimerExpiredCb);
|
| ++ }
|
| ++
|
| ++ if (rv == SECFailure) {
|
| ++ /* XXX OK for now. In future maybe signal the stack that we couldn't
|
| ++ * transmit. For now, let the read handle any real network errors */
|
| ++ }
|
| ++}
|
| ++
|
| ++/* Transmit a flight of handshake messages, stuffing them
|
| ++ * into as few records as seems reasonable
|
| ++ *
|
| ++ * Called from:
|
| ++ * dtls_FlushHandshake()
|
| ++ * dtls_RetransmitTimerExpiredCb()
|
| ++ */
|
| ++static SECStatus
|
| ++dtls_TransmitMessageFlight(sslSocket *ss)
|
| ++{
|
| ++ SECStatus rv = SECSuccess;
|
| ++ PRCList *msg_p;
|
| ++ PRUint16 room_left = ss->ssl3.mtu;
|
| ++ PRInt32 sent;
|
| ++
|
| ++ ssl_GetXmitBufLock(ss);
|
| ++ ssl_GetSpecReadLock(ss);
|
| ++
|
| ++ /* DTLS does not buffer its handshake messages in
|
| ++ * ss->pendingBuf, but rather in the lastMessageFlight
|
| ++ * structure. This is just a sanity check that
|
| ++ * some programming error hasn't inadvertantly
|
| ++ * stuffed something in ss->pendingBuf
|
| ++ */
|
| ++ PORT_Assert(!ss->pendingBuf.len);
|
| ++ for (msg_p = PR_LIST_HEAD(ss->ssl3.hs.lastMessageFlight);
|
| ++ msg_p != ss->ssl3.hs.lastMessageFlight;
|
| ++ msg_p = PR_NEXT_LINK(msg_p)) {
|
| ++ DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p;
|
| ++
|
| ++ /* The logic here is:
|
| ++ *
|
| ++ * 1. If this is a message that will not fit into the remaining
|
| ++ * space, then flush.
|
| ++ * 2. If the message will now fit into the remaining space,
|
| ++ * encrypt, buffer, and loop.
|
| ++ * 3. If the message will not fit, then fragment.
|
| ++ *
|
| ++ * At the end of the function, flush.
|
| ++ */
|
| ++ if ((msg->len + SSL3_BUFFER_FUDGE) > room_left) {
|
| ++ /* The message will not fit into the remaining space, so flush */
|
| ++ rv = dtls_SendSavedWriteData(ss);
|
| ++ if (rv != SECSuccess)
|
| ++ break;
|
| ++
|
| ++ room_left = ss->ssl3.mtu;
|
| ++ }
|
| ++
|
| ++ if ((msg->len + SSL3_BUFFER_FUDGE) <= room_left) {
|
| ++ /* The message will fit, so encrypt and then continue with the
|
| ++ * next packet */
|
| ++ sent = ssl3_SendRecord(ss, msg->epoch, msg->type,
|
| ++ msg->data, msg->len,
|
| ++ ssl_SEND_FLAG_FORCE_INTO_BUFFER |
|
| ++ ssl_SEND_FLAG_USE_EPOCH);
|
| ++ if (sent != msg->len) {
|
| ++ rv = SECFailure;
|
| ++ if (sent != -1) {
|
| ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| ++ }
|
| ++ break;
|
| ++ }
|
| ++
|
| ++ room_left = ss->ssl3.mtu - ss->pendingBuf.len;
|
| ++ } else {
|
| ++ /* The message will not fit, so fragment.
|
| ++ *
|
| ++ * XXX OK for now. Arrange to coalesce the last fragment
|
| ++ * of this message with the next message if possible.
|
| ++ * That would be more efficient.
|
| ++ */
|
| ++ PRUint32 fragment_offset = 0;
|
| ++ unsigned char fragment[DTLS_MAX_MTU]; /* >= than largest
|
| ++ * plausible MTU */
|
| ++
|
| ++ /* Assert that we have already flushed */
|
| ++ PORT_Assert(room_left == ss->ssl3.mtu);
|
| ++
|
| ++ /* Case 3: We now need to fragment this message
|
| ++ * DTLS only supports fragmenting handshaking messages */
|
| ++ PORT_Assert(msg->type == content_handshake);
|
| ++
|
| ++ /* The headers consume 12 bytes so the smalles possible
|
| ++ * message (i.e., an empty one) is 12 bytes
|
| ++ */
|
| ++ PORT_Assert(msg->len >= 12);
|
| ++
|
| ++ while ((fragment_offset + 12) < msg->len) {
|
| ++ PRUint32 fragment_len;
|
| ++ const unsigned char *content = msg->data + 12;
|
| ++ PRUint32 content_len = msg->len - 12;
|
| ++
|
| ++ /* The reason we use 8 here is that that's the length of
|
| ++ * the new DTLS data that we add to the header */
|
| ++ fragment_len = PR_MIN(room_left - (SSL3_BUFFER_FUDGE + 8),
|
| ++ content_len - fragment_offset);
|
| ++ PORT_Assert(fragment_len < DTLS_MAX_MTU - 12);
|
| ++ /* Make totally sure that we are within the buffer.
|
| ++ * Note that the only way that fragment len could get
|
| ++ * adjusted here is if
|
| ++ *
|
| ++ * (a) we are in release mode so the PORT_Assert is compiled out
|
| ++ * (b) either the MTU table is inconsistent with DTLS_MAX_MTU
|
| ++ * or ss->ssl3.mtu has become corrupt.
|
| ++ */
|
| ++ fragment_len = PR_MIN(fragment_len, DTLS_MAX_MTU - 12);
|
| ++
|
| ++ /* Construct an appropriate-sized fragment */
|
| ++ /* Type, length, sequence */
|
| ++ PORT_Memcpy(fragment, msg->data, 6);
|
| ++
|
| ++ /* Offset */
|
| ++ fragment[6] = (fragment_offset >> 16) & 0xff;
|
| ++ fragment[7] = (fragment_offset >> 8) & 0xff;
|
| ++ fragment[8] = (fragment_offset) & 0xff;
|
| ++
|
| ++ /* Fragment length */
|
| ++ fragment[9] = (fragment_len >> 16) & 0xff;
|
| ++ fragment[10] = (fragment_len >> 8) & 0xff;
|
| ++ fragment[11] = (fragment_len) & 0xff;
|
| ++
|
| ++ PORT_Memcpy(fragment + 12, content + fragment_offset,
|
| ++ fragment_len);
|
| ++
|
| ++ /*
|
| ++ * Send the record. We do this in two stages
|
| ++ * 1. Encrypt
|
| ++ */
|
| ++ sent = ssl3_SendRecord(ss, msg->epoch, msg->type,
|
| ++ fragment, fragment_len + 12,
|
| ++ ssl_SEND_FLAG_FORCE_INTO_BUFFER |
|
| ++ ssl_SEND_FLAG_USE_EPOCH);
|
| ++ if (sent != (fragment_len + 12)) {
|
| ++ rv = SECFailure;
|
| ++ if (sent != -1) {
|
| ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| ++ }
|
| ++ break;
|
| ++ }
|
| ++
|
| ++ /* 2. Flush */
|
| ++ rv = dtls_SendSavedWriteData(ss);
|
| ++ if (rv != SECSuccess)
|
| ++ break;
|
| ++
|
| ++ fragment_offset += fragment_len;
|
| ++ }
|
| ++ }
|
| ++ }
|
| ++
|
| ++ /* Finally, we need to flush */
|
| ++ if (rv == SECSuccess)
|
| ++ rv = dtls_SendSavedWriteData(ss);
|
| ++
|
| ++ /* Give up the locks */
|
| ++ ssl_ReleaseSpecReadLock(ss);
|
| ++ ssl_ReleaseXmitBufLock(ss);
|
| ++
|
| ++ return rv;
|
| ++}
|
| ++
|
| ++/* Flush the data in the pendingBuf and update the max message sent
|
| ++ * so we can adjust the MTU estimate if we need to.
|
| ++ * Wrapper for ssl_SendSavedWriteData.
|
| ++ *
|
| ++ * Called from dtls_TransmitMessageFlight()
|
| ++ */
|
| ++static
|
| ++SECStatus dtls_SendSavedWriteData(sslSocket *ss)
|
| ++{
|
| ++ PRInt32 sent;
|
| ++
|
| ++ sent = ssl_SendSavedWriteData(ss);
|
| ++ if (sent < 0)
|
| ++ return SECFailure;
|
| ++
|
| ++ /* We should always have complete writes b/c datagram sockets
|
| ++ * don't really block */
|
| ++ if (ss->pendingBuf.len > 0) {
|
| ++ ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
|
| ++ return SECFailure;
|
| ++ }
|
| ++
|
| ++ /* Update the largest message sent so we can adjust the MTU
|
| ++ * estimate if necessary */
|
| ++ if (sent > ss->ssl3.hs.maxMessageSent)
|
| ++ ss->ssl3.hs.maxMessageSent = sent;
|
| ++
|
| ++ return SECSuccess;
|
| ++}
|
| ++
|
| ++/* Compress, MAC, encrypt a DTLS record. Allows specification of
|
| ++ * the epoch using epoch value. If use_epoch is PR_TRUE then
|
| ++ * we use the provided epoch. If use_epoch is PR_FALSE then
|
| ++ * whatever the current value is in effect is used.
|
| ++ *
|
| ++ * Called from ssl3_SendRecord()
|
| ++ */
|
| ++SECStatus
|
| ++dtls_CompressMACEncryptRecord(sslSocket * ss,
|
| ++ DTLSEpoch epoch,
|
| ++ PRBool use_epoch,
|
| ++ SSL3ContentType type,
|
| ++ const SSL3Opaque * pIn,
|
| ++ PRUint32 contentLen,
|
| ++ sslBuffer * wrBuf)
|
| ++{
|
| ++ SECStatus rv = SECFailure;
|
| ++ ssl3CipherSpec * cwSpec;
|
| ++
|
| ++ 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.,
|
| ++ *
|
| ++ * ClientKeyExchange (epoch = 0)
|
| ++ * ChangeCipherSpec (epoch = 0)
|
| ++ * Finished (epoch = 1)
|
| ++ *
|
| ++ * Thus, each record needs a different cipher spec. The information
|
| ++ * about which epoch to use is carried with the record.
|
| ++ */
|
| ++ if (use_epoch) {
|
| ++ if (ss->ssl3.cwSpec->epoch == epoch)
|
| ++ cwSpec = ss->ssl3.cwSpec;
|
| ++ else if (ss->ssl3.pwSpec->epoch == epoch)
|
| ++ cwSpec = ss->ssl3.pwSpec;
|
| ++ else
|
| ++ cwSpec = NULL;
|
| ++ } else {
|
| ++ cwSpec = ss->ssl3.cwSpec;
|
| ++ }
|
| ++
|
| ++ if (cwSpec) {
|
| ++ rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE,
|
| ++ type, pIn, contentLen, wrBuf);
|
| ++ } else {
|
| ++ PR_NOT_REACHED("Couldn't find a cipher spec matching epoch");
|
| ++ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| ++ }
|
| ++ ssl_ReleaseSpecReadLock(ss); /************************************/
|
| ++
|
| ++ return rv;
|
| ++}
|
| ++
|
| ++/* Start a timer
|
| ++ *
|
| ++ * Called from:
|
| ++ * dtls_HandleHandshake()
|
| ++ * dtls_FlushHAndshake()
|
| ++ * dtls_RestartTimer()
|
| ++ */
|
| ++SECStatus
|
| ++dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb)
|
| ++{
|
| ++ PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL);
|
| ++
|
| ++ ss->ssl3.hs.rtTimerStarted = PR_IntervalNow();
|
| ++ ss->ssl3.hs.rtTimerCb = cb;
|
| ++
|
| ++ return SECSuccess;
|
| ++}
|
| ++
|
| ++/* Restart a timer with optional backoff
|
| ++ *
|
| ++ * Called from dtls_RetransmitTimerExpiredCb()
|
| ++ */
|
| ++SECStatus
|
| ++dtls_RestartTimer(sslSocket *ss, PRBool backoff, DTLSTimerCb cb)
|
| ++{
|
| ++ if (backoff) {
|
| ++ ss->ssl3.hs.rtTimeoutMs *= 2;
|
| ++ if (ss->ssl3.hs.rtTimeoutMs > MAX_DTLS_TIMEOUT_MS)
|
| ++ ss->ssl3.hs.rtTimeoutMs = MAX_DTLS_TIMEOUT_MS;
|
| ++ }
|
| ++
|
| ++ return dtls_StartTimer(ss, cb);
|
| ++}
|
| ++
|
| ++/* Cancel a pending timer
|
| ++ *
|
| ++ * Called from:
|
| ++ * dtls_HandleHandshake()
|
| ++ * dtls_CheckTimer()
|
| ++ */
|
| ++void
|
| ++dtls_CancelTimer(sslSocket *ss)
|
| ++{
|
| ++ PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
|
| ++
|
| ++ ss->ssl3.hs.rtTimerCb = NULL;
|
| ++}
|
| ++
|
| ++/* Check the pending timer and fire the callback if it expired
|
| ++ *
|
| ++ * Called from ssl3_GatherCompleteHandshake()
|
| ++ */
|
| ++void
|
| ++dtls_CheckTimer(sslSocket *ss)
|
| ++{
|
| ++ if (!ss->ssl3.hs.rtTimerCb)
|
| ++ return;
|
| ++
|
| ++ if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) >
|
| ++ PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) {
|
| ++ /* Timer has expired */
|
| ++ DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb;
|
| ++
|
| ++ /* Cancel the timer so that we can call the CB safely */
|
| ++ dtls_CancelTimer(ss);
|
| ++
|
| ++ /* Now call the CB */
|
| ++ cb(ss);
|
| ++ }
|
| ++}
|
| ++
|
| ++/* The callback to fire when the holddown timer for the Finished
|
| ++ * message expires and we can delete it
|
| ++ *
|
| ++ * Called from dtls_CheckTimer()
|
| ++ */
|
| ++void
|
| ++dtls_FinishedTimerCb(sslSocket *ss)
|
| ++{
|
| ++ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE);
|
| ++}
|
| ++
|
| ++/* Cancel the Finished hold-down timer and destroy the
|
| ++ * pending cipher spec. Note that this means that
|
| ++ * successive rehandshakes will fail if the Finished is
|
| ++ * lost.
|
| ++ *
|
| ++ * XXX OK for now. Figure out how to handle the combination
|
| ++ * of Finished lost and rehandshake
|
| ++ */
|
| ++void
|
| ++dtls_RehandshakeCleanup(sslSocket *ss)
|
| ++{
|
| ++ dtls_CancelTimer(ss);
|
| ++ ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE);
|
| ++ ss->ssl3.hs.sendMessageSeq = 0;
|
| ++}
|
| ++
|
| ++/* Set the MTU to the next step less than or equal to the
|
| ++ * advertised value. Also used to downgrade the MTU by
|
| ++ * doing dtls_SetMTU(ss, biggest packet set).
|
| ++ *
|
| ++ * Passing 0 means set this to the largest MTU known
|
| ++ * (effectively resetting the PMTU backoff value).
|
| ++ *
|
| ++ * Called by:
|
| ++ * ssl3_InitState()
|
| ++ * dtls_RetransmitTimerExpiredCb()
|
| ++ */
|
| ++void
|
| ++dtls_SetMTU(sslSocket *ss, PRUint16 advertised)
|
| ++{
|
| ++ int i;
|
| ++
|
| ++ if (advertised == 0) {
|
| ++ ss->ssl3.mtu = COMMON_MTU_VALUES[0];
|
| ++ SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu));
|
| ++ return;
|
| ++ }
|
| ++
|
| ++ for (i = 0; i < PR_ARRAY_SIZE(COMMON_MTU_VALUES); i++) {
|
| ++ if (COMMON_MTU_VALUES[i] <= advertised) {
|
| ++ ss->ssl3.mtu = COMMON_MTU_VALUES[i];
|
| ++ SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu));
|
| ++ return;
|
| ++ }
|
| ++ }
|
| ++
|
| ++ /* Fallback */
|
| ++ ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES)-1];
|
| ++ SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu));
|
| ++}
|
| ++
|
| ++/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a
|
| ++ * DTLS hello_verify_request
|
| ++ * Caller must hold Handshake and RecvBuf locks.
|
| ++ */
|
| ++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;
|
| ++
|
| ++ SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake",
|
| ++ 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;
|
| ++ goto alert_loser;
|
| ++ }
|
| ++
|
| ++ /* The version */
|
| ++ temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
|
| ++ if (temp < 0) {
|
| ++ goto loser; /* alert has been sent */
|
| ++ }
|
| ++
|
| ++ if (temp != SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) {
|
| ++ /* Note: this will need adjustment for DTLS 1.2 per Section 4.2.1 */
|
| ++ goto alert_loser;
|
| ++ }
|
| ++
|
| ++ /* The cookie */
|
| ++ rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length);
|
| ++ if (rv != SECSuccess) {
|
| ++ goto loser; /* alert has been sent */
|
| ++ }
|
| ++ if (cookie.len > DTLS_COOKIE_BYTES) {
|
| ++ desc = decode_error;
|
| ++ goto alert_loser; /* malformed. */
|
| ++ }
|
| ++
|
| ++ PORT_Memcpy(ss->ssl3.hs.cookie, cookie.data, cookie.len);
|
| ++ ss->ssl3.hs.cookieLen = cookie.len;
|
| ++
|
| ++
|
| ++ ssl_GetXmitBufLock(ss); /*******************************/
|
| ++
|
| ++ /* Now re-send the client hello */
|
| ++ rv = ssl3_SendClientHello(ss, PR_TRUE);
|
| ++
|
| ++ ssl_ReleaseXmitBufLock(ss); /*******************************/
|
| ++
|
| ++ if (rv == SECSuccess)
|
| ++ return rv;
|
| ++
|
| ++alert_loser:
|
| ++ (void)SSL3_SendAlert(ss, alert_fatal, desc);
|
| ++
|
| ++loser:
|
| ++ errCode = ssl_MapLowLevelError(errCode);
|
| ++ return SECFailure;
|
| ++}
|
| ++
|
| ++/* Initialize the DTLS anti-replay window
|
| ++ *
|
| ++ * Called from:
|
| ++ * ssl3_SetupPendingCipherSpec()
|
| ++ * ssl3_InitCipherSpec()
|
| ++ */
|
| ++void
|
| ++dtls_InitRecvdRecords(DTLSRecvdRecords *records)
|
| ++{
|
| ++ PORT_Memset(records->data, 0, sizeof(records->data));
|
| ++ records->left = 0;
|
| ++ records->right = DTLS_RECVD_RECORDS_WINDOW - 1;
|
| ++}
|
| ++
|
| ++/*
|
| ++ * Has this DTLS record been received? Return values are:
|
| ++ * -1 -- out of range to the left
|
| ++ * 0 -- not received yet
|
| ++ * 1 -- replay
|
| ++ *
|
| ++ * Called from: dtls_HandleRecord()
|
| ++ */
|
| ++int
|
| ++dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
|
| ++{
|
| ++ PRUint64 offset;
|
| ++
|
| ++ /* Out of range to the left */
|
| ++ if (seq < records->left) {
|
| ++ return -1;
|
| ++ }
|
| ++
|
| ++ /* Out of range to the right; since we advance the window on
|
| ++ * receipt, that means that this packet has not been received
|
| ++ * yet */
|
| ++ if (seq > records->right)
|
| ++ return 0;
|
| ++
|
| ++ offset = seq % DTLS_RECVD_RECORDS_WINDOW;
|
| ++
|
| ++ return !!(records->data[offset / 8] & (1 << (offset % 8)));
|
| ++}
|
| ++
|
| ++/* Update the DTLS anti-replay window
|
| ++ *
|
| ++ * Called from ssl3_HandleRecord()
|
| ++ */
|
| ++void
|
| ++dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq)
|
| ++{
|
| ++ PRUint64 offset;
|
| ++
|
| ++ if (seq < records->left)
|
| ++ return;
|
| ++
|
| ++ if (seq > records->right) {
|
| ++ PRUint64 new_left;
|
| ++ PRUint64 new_right;
|
| ++ PRUint64 right;
|
| ++
|
| ++ /* Slide to the right; this is the tricky part
|
| ++ *
|
| ++ * 1. new_top is set to have room for seq, on the
|
| ++ * next byte boundary by setting the right 8
|
| ++ * bits of seq
|
| ++ * 2. new_left is set to compensate.
|
| ++ * 3. Zero all bits between top and new_top. Since
|
| ++ * this is a ring, this zeroes everything as-yet
|
| ++ * unseen. Because we always operate on byte
|
| ++ * boundaries, we can zero one byte at a time
|
| ++ */
|
| ++ new_right = seq | 0x07;
|
| ++ new_left = (new_right - DTLS_RECVD_RECORDS_WINDOW) + 1;
|
| ++
|
| ++ for (right = records->right + 8; right <= new_right; right += 8) {
|
| ++ offset = right % DTLS_RECVD_RECORDS_WINDOW;
|
| ++ records->data[offset / 8] = 0;
|
| ++ }
|
| ++
|
| ++ records->right = new_right;
|
| ++ records->left = new_left;
|
| ++ }
|
| ++
|
| ++ offset = seq % DTLS_RECVD_RECORDS_WINDOW;
|
| ++
|
| ++ records->data[offset / 8] |= (1 << (offset % 8));
|
| ++}
|
| ++
|
| ++SECStatus
|
| ++DTLS_GetTimeout(PRFileDesc *socket, PRIntervalTime *timeout)
|
| ++{
|
| ++ sslSocket * ss = NULL;
|
| ++ PRIntervalTime elapsed;
|
| ++ PRIntervalTime desired;
|
| ++
|
| ++ ss = ssl_FindSocket(socket);
|
| ++
|
| ++ if (!ss)
|
| ++ return SECFailure;
|
| ++
|
| ++ if (!IS_DTLS(ss))
|
| ++ return SECFailure;
|
| ++
|
| ++ if (!ss->ssl3.hs.rtTimerCb)
|
| ++ return SECFailure;
|
| ++
|
| ++ elapsed = PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted;
|
| ++ desired = PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs);
|
| ++ if (elapsed > desired) {
|
| ++ /* Timer expired */
|
| ++ *timeout = PR_INTERVAL_NO_WAIT;
|
| ++ } else {
|
| ++ *timeout = desired - elapsed;
|
| ++ }
|
| ++
|
| ++ return SECSuccess;
|
| ++}
|
| +
|
| +Property changes on: net/third_party/nss/ssl/dtls1con.c
|
| +___________________________________________________________________
|
| +Added: svn:eol-style
|
| + + LF
|
| +
|
| +Index: net/third_party/nss/ssl/sslproto.h
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslproto.h (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslproto.h (working copy)
|
| +@@ -49,10 +49,15 @@
|
| + #define SSL_LIBRARY_VERSION_3_0 0x0300
|
| + #define SSL_LIBRARY_VERSION_TLS_1_0 0x0301
|
| + #define SSL_LIBRARY_VERSION_TLS_1_1 0x0302
|
| ++/* Note: this is the internal format, not the wire format */
|
| ++#define SSL_LIBRARY_VERSION_DTLS_1_0 0x0302
|
| +
|
| + /* deprecated old name */
|
| + #define SSL_LIBRARY_VERSION_3_1_TLS SSL_LIBRARY_VERSION_TLS_1_0
|
| +
|
| ++/* The DTLS version used in the spec */
|
| ++#define SSL_LIBRARY_VERSION_DTLS_1_0_WIRE ((~0x0100) & 0xffff)
|
| ++
|
| + /* Header lengths of some of the messages */
|
| + #define SSL_HL_ERROR_HBYTES 3
|
| + #define SSL_HL_CLIENT_HELLO_HBYTES 9
|
| +Index: net/third_party/nss/ssl/sslt.h
|
| +===================================================================
|
| +--- net/third_party/nss/ssl/sslt.h (revision 127709)
|
| ++++ net/third_party/nss/ssl/sslt.h (working copy)
|
| +@@ -190,7 +190,8 @@
|
| + } SSLCipherSuiteInfo;
|
| +
|
| + typedef enum {
|
| +- ssl_variant_stream = 0
|
| ++ ssl_variant_stream = 0,
|
| ++ ssl_variant_datagram = 1
|
| + } SSLProtocolVariant;
|
| +
|
| + typedef struct SSLVersionRangeStr {
|
|
|