Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1292)

Unified Diff: net/third_party/nss/patches/dtls.patch

Issue 11275240: Update net/third_party/nss/ssl to NSS 3.14. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Upload before commit Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/third_party/nss/patches/didhandshakeresume.patch ('k') | net/third_party/nss/patches/dtlssrtp.patch » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/third_party/nss/patches/dtls.patch
===================================================================
--- net/third_party/nss/patches/dtls.patch (revision 166942)
+++ net/third_party/nss/patches/dtls.patch (working copy)
@@ -1,3322 +0,0 @@
-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_GetHandshakeTimeout(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,1164 @@
-+/*
-+ * 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;
-+ ss->ssl3.hs.recvMessageSeq = 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_GetHandshakeTimeout(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 {
« no previous file with comments | « net/third_party/nss/patches/didhandshakeresume.patch ('k') | net/third_party/nss/patches/dtlssrtp.patch » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698