diff --git a/mozilla/security/nss/lib/ssl/fnv1a64.c b/mozilla/security/nss/lib/ssl/fnv1a64.c
new file mode 100644
index 0000000..c7c4b08
--- /dev/null
+++ b/mozilla/security/nss/lib/ssl/fnv1a64.c
@@ -0,0 +1,72 @@
+/*
+ * FNV1A64 Hash
+ * http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
+ *
+ * ***** 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):
+ *   Adam Langley, Google Inc.
+ *
+ * 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: fnv1a64.c,v 1.0 2010/08/09 13:00:00 agl%google.com Exp $ */
+
+#include "prtypes.h"
+#include "prnetdb.h"
+
+/* Older versions of Visual C++ don't support the 'ull' suffix. */
+#ifdef _MSC_VER
+static const PRUint64 FNV1A64_OFFSET_BASIS = 14695981039346656037ui64;
+static const PRUint64 FNV1A64_PRIME = 1099511628211ui64;
+#else
+static const PRUint64 FNV1A64_OFFSET_BASIS = 14695981039346656037ull;
+static const PRUint64 FNV1A64_PRIME = 1099511628211ull;
+#endif
+
+void FNV1A64_Init(PRUint64* digest) {
+    *digest = FNV1A64_OFFSET_BASIS;
+}
+
+void FNV1A64_Update(PRUint64* digest, const unsigned char *data,
+                    unsigned int length) {
+    unsigned int i;
+
+    for (i = 0; i < length; i++) {
+        *digest ^= data[i];
+        *digest *= FNV1A64_PRIME;
+    }
+}
+
+void FNV1A64_Final(PRUint64 *digest) {
+    *digest = PR_htonll(*digest);
+}
diff --git a/mozilla/security/nss/lib/ssl/snapstart.c b/mozilla/security/nss/lib/ssl/snapstart.c
new file mode 100644
index 0000000..ca2cafa
--- /dev/null
+++ b/mozilla/security/nss/lib/ssl/snapstart.c
@@ -0,0 +1,1062 @@
+/*
+ * TLS Snap Start
+ *
+ * ***** 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):
+ *   Adam Langley, Google Inc.
+ *
+ * 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: ssl3snap.c,v 1.0 2010/08/09 13:00:00 agl%google.com Exp $ */
+
+
+/* TODO(agl): Refactor ssl3_CompressMACEncryptRecord so that it can write to
+** |sendBuf| directly and fix ssl3_AppendSnapStartHandshakeRecord and
+**  ssl3_AppendSnapStartApplicationData.
+*/
+
+/* TODO(agl): Add support for snap starting with compression. */
+
+/* TODO(agl): Free snapStartApplicationData as soon as the handshake has
+** completed.
+*/
+
+#include "pk11pub.h"
+#include "ssl.h"
+#include "sslimpl.h"
+#include "sslproto.h"
+
+static unsigned int GetBE16(const void *in)
+{
+    const unsigned char *p = in;
+    return ((unsigned) p[0]) << 8 |
+                       p[1];
+}
+
+static unsigned int GetBE24(const void *in)
+{
+    const unsigned char *p = in;
+    return ((unsigned) p[0]) << 16 |
+           ((unsigned) p[1]) << 8 |
+                       p[2];
+}
+
+static void PutBE16(void *out, unsigned int value)
+{
+    unsigned char *p = out;
+    p[0] = value >> 8;
+    p[1] = value;
+}
+
+static void PutBE24(void *out, unsigned int value)
+{
+    unsigned char *p = out;
+    p[0] = value >> 16;
+    p[1] = value >> 8;
+    p[2] = value;
+}
+
+/* ssl3_ForEachExtension calls a callback for each TLS extension in |extensions|
+**   extensions: points to a block of extensions which includes the two prefix
+**       length bytes
+**   is_resuming: if true, certain extensions will be omitted
+**   f: a function which is called with the data of each extension, which
+**      includes the four type and length bytes at the beginning.
+*/
+static PRBool
+ssl3_ForEachExtension(const SECItem *extensions, PRBool is_resuming,
+                      void (*f) (const unsigned char *data, unsigned int length,
+                                 void *ctx),
+                      void *ctx) {
+    unsigned int extensions_len, offset;
+
+    if (extensions->len == 0)
+        return PR_TRUE;
+
+    if (extensions->len < 2)
+        goto loser;
+
+    extensions_len = GetBE16(extensions->data);
+    offset = 2;
+
+    if (extensions->len != 2 + extensions_len)
+        goto loser;
+
+    while (extensions_len) {
+        unsigned int extension_num, extension_len;
+
+        if (extensions->len - offset < 4)
+            goto loser;
+
+        extension_num = GetBE16(extensions->data + offset);
+        extension_len = GetBE16(extensions->data + offset + 2);
+
+        if (extensions->len - offset < 4 + extension_len)
+            goto loser;
+
+        /* When resuming, the server will omit some extensions from the
+         * previous non-resume ServerHello. */
+        if (!is_resuming ||
+            (extension_num != ssl_server_name_xtn &&
+             extension_num != ssl_session_ticket_xtn)) {
+            f(extensions->data + offset, 4 + extension_len, ctx);
+        }
+
+        offset += 4 + extension_len;
+        extensions_len -= 4 + extension_len;
+    }
+
+    return PR_TRUE;
+
+loser:
+    PORT_SetError(SEC_ERROR_INPUT_LEN);
+    return PR_FALSE;
+}
+
+static void
+ssl3_AccumlateLengths(const unsigned char *data, unsigned int length, void *ptr)
+{
+    unsigned int *sum = (unsigned int *) ptr;
+    *sum += length;
+}
+
+/* ssl3_PredictServerResponse predicts the contents of the server's
+** ServerHello...ServerHelloDone (inclusive) and progressively calls a callback
+** with the contents of those messages.
+**   previous_server_hello: the contents of a previous ServerHello from the
+**       server where the 'random' field has been replaced with our suggested
+**       server random.
+**   is_resuming: if false, Certificate and ServerHelloDone messages will be
+**      predicted
+**   hashUpdate: a callback which is called repeated with the contents of the
+**      predicted messages.
+*/
+static PRBool
+ssl3_PredictServerResponse(
+        sslSocket *ss, SECItem *previous_server_hello, PRBool is_resuming,
+        void (*hashUpdate) (const unsigned char *data, unsigned int length,
+                            void *ctx),
+        void *ctx) {
+    unsigned int old_session_id_length, old_extensions_len;
+    unsigned int extensions_len, server_hello_len;
+    unsigned char session_id_len, header[4];
+    SECItem extensions;
+
+    /* Keep the structure of a ServerHello in mind when reading the following:
+     *
+     * struct ServerHello {
+     *   uint16_t version;
+     *   uint8_t  random[32];
+     *   uint8_t  session_id_len;
+     *   uint8_t  session_id[session_id_len];
+     *   uint16_t cipher
+     *   uint8_t  compression
+     *
+     *   // Optional:
+     *   uint16_t extensions_len;
+     *   struct Extension {
+     *     uint16_t num;
+     *     uint16_t len;
+     *     uint8_t  payload[len];
+     *   }
+     */
+
+    /* 38 bytes is the shortest possible ServerHello with a zero-length
+     * session_id and no extensions. */
+    if (previous_server_hello->len < 38) {
+        PORT_SetError(SEC_ERROR_INPUT_LEN);
+        return PR_FALSE;
+    }
+
+    /* First we need to figure out the length of the predicted ServerHello. Any
+     * session id in |previous_server_hello| needs to be removed
+     * (or replaced). */
+    old_session_id_length = previous_server_hello->data[34];
+
+    extensions.len = 0;
+
+    if (previous_server_hello->len >= 35 + old_session_id_length + 3 + 2) {
+        /* Extensions present */
+        unsigned int offset = 35 + old_session_id_length + 3;
+        extensions.data = previous_server_hello->data + offset;
+        extensions.len = previous_server_hello->len - offset;
+    }
+
+    /* Sum the lengths of all the extensions that we wish to include */
+    extensions_len = 0;
+    if (!ssl3_ForEachExtension(&extensions, is_resuming, ssl3_AccumlateLengths,
+                               &extensions_len)) {
+        return PR_FALSE;
+    }
+
+    old_extensions_len =
+        (previous_server_hello->len - 35 - old_session_id_length - 3 - 2);
+
+    session_id_len = 0;
+    if (ss->sec.ci.sid)
+        session_id_len = ss->sec.ci.sid->u.ssl3.sessionIDLength;
+    server_hello_len = previous_server_hello->len +
+                       session_id_len - old_session_id_length +
+                       extensions_len - old_extensions_len;
+
+    header[0] = server_hello;
+    PutBE24(header + 1, server_hello_len);
+    hashUpdate(header, 4, ctx);
+
+    hashUpdate(previous_server_hello->data, 34, ctx);
+    hashUpdate(&session_id_len, sizeof(session_id_len), ctx);
+    if (session_id_len)
+        hashUpdate(ss->sec.ci.sid->u.ssl3.sessionID, session_id_len, ctx);
+    hashUpdate(previous_server_hello->data + 35 + old_session_id_length, 3,
+               ctx);
+
+    if (extensions.len) {
+        PutBE16(header, extensions_len);
+        hashUpdate(header, 2, ctx);
+
+        if (!ssl3_ForEachExtension(&extensions, is_resuming, hashUpdate, ctx))
+            return PR_FALSE;
+    }
+
+    if (!is_resuming) {
+        unsigned int certificate_message_len = 3, i;
+        for (i = 0; ss->ssl3.predictedCertChain[i]; i++) {
+            certificate_message_len += 3;
+            certificate_message_len +=
+                ss->ssl3.predictedCertChain[i]->derCert.len;
+        }
+
+        header[0] = certificate;
+        PutBE24(header + 1, certificate_message_len);
+        hashUpdate(header, 4, ctx);
+
+        PutBE24(header, certificate_message_len - 3);
+        hashUpdate(header, 3, ctx);
+
+        for (i = 0; ss->ssl3.predictedCertChain[i]; i++) {
+            unsigned int len = ss->ssl3.predictedCertChain[i]->derCert.len;
+            PutBE24(header, len);
+            hashUpdate(header, 3, ctx);
+            hashUpdate(ss->ssl3.predictedCertChain[i]->derCert.data, len, ctx);
+        }
+
+        header[0] = server_hello_done;
+        header[1] = header[2] = header[3] = 0;
+        hashUpdate(header, 4, ctx);
+    }
+
+    return PR_TRUE;
+}
+
+/* ssl3_SnapStartHash is called with the contents of the server's predicted
+ * response and updates both the Finished hash and an FNV641a hash. */
+static void
+ssl3_SnapStartHash(const unsigned char *data, unsigned int len, void *ctx)
+{
+    SECStatus rv;
+    void **ptrs = (void **) ctx;
+    sslSocket *ss = ptrs[0];
+    PRUint64 *fnv = ptrs[1];
+
+    FNV1A64_Update(fnv, data, len);
+    rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *) data, len);
+    if (rv != SECSuccess)
+        PR_Assert("rv == SECSuccess", __FILE__, __LINE__);
+}
+
+static PRInt32
+ssl3_SendEmptySnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+{
+    SECStatus rv;
+
+    if (maxBytes < 4)
+        return 0;
+
+    if (append) {
+        rv = ssl3_AppendHandshakeNumber(ss, ssl_snap_start_xtn, 2);
+        if (rv != SECSuccess)
+            return -1;
+        rv = ssl3_AppendHandshakeNumber(ss, 0 /* empty extension */, 2);
+        if (rv != SECSuccess)
+            return -1;
+        if (!ss->sec.isServer) {
+            TLSExtensionData *xtnData = &ss->xtnData;
+            xtnData->advertised[xtnData->numAdvertised++] = ssl_snap_start_xtn;
+        }
+    }
+    return 4;
+}
+
+static SECStatus
+ssl3_BufferEnsure(sslBuffer *buf, unsigned int extra_bytes)
+{
+    if (buf->space < buf->len + extra_bytes)
+        return sslBuffer_Grow(buf, buf->len + extra_bytes);
+    return SECSuccess;
+}
+
+/* ssl3_AppendSnapStartRecordHeader appends a 5 byte TLS record header to the
+ * sendBuf of the given sslSocket. */
+static SECStatus
+ssl3_AppendSnapStartRecordHeader(sslSocket *ss, SSL3ContentType type,
+                                 unsigned int len)
+{
+    SECStatus rv;
+
+    rv = ssl3_BufferEnsure(&ss->sec.ci.sendBuf, 5);
+    if (rv != SECSuccess)
+        return rv;
+    ss->sec.ci.sendBuf.buf[ss->sec.ci.sendBuf.len + 0] = type;
+    PutBE16(&ss->sec.ci.sendBuf.buf[ss->sec.ci.sendBuf.len + 1], ss->version);
+    PutBE16(&ss->sec.ci.sendBuf.buf[ss->sec.ci.sendBuf.len + 3], len);
+    ss->sec.ci.sendBuf.len += 5;
+    return SECSuccess;
+}
+
+/* ssl3_AppendSnapStartHandshakeRecord appends a (possibly encrypted) record to
+** the sendBuf of the given sslSocket.
+**   f: a function which will append the bytes of the record (not including the
+**      5 byte header) to the sendBuf.
+*/
+static SECStatus
+ssl3_AppendSnapStartHandshakeRecord(sslSocket *ss, SECStatus (*f) (sslSocket*),
+                                    PRBool encrypt)
+{
+    SECStatus rv;
+    unsigned int record_offset, record_len;
+
+    /* ssl3_CompressMACEncryptRecord will deal with the record header if we are
+     * encrypting. */
+    if (!encrypt) {
+        /* The zero length argument here is a dummy value. We write the real
+         * length once we know it, below. */
+        rv = ssl3_AppendSnapStartRecordHeader(ss, content_handshake, 0);
+        if (rv != SECSuccess)
+            return rv;
+    }
+
+    record_offset = ss->sec.ci.sendBuf.len;
+    rv = f(ss);
+    if (rv != SECSuccess)
+        return rv;
+    record_len = ss->sec.ci.sendBuf.len - record_offset;
+    if (!encrypt) {
+        PutBE16(&ss->sec.ci.sendBuf.buf[record_offset - 2], record_len);
+    } else {
+        /* ssl3_CompressMACEncryptRecord writes to |ss->sec.writeBuf|
+         * so we copy it back to |ss->sec.ci.sendBuf| */
+        /* TODO(agl): the buffer copy here is a bodge. See TODO at the top of
+         * the file. */
+        rv = ssl3_CompressMACEncryptRecord(
+            ss, content_handshake,
+            &ss->sec.ci.sendBuf.buf[record_offset], record_len);
+        if (rv != SECSuccess)
+            return rv;
+        ss->sec.ci.sendBuf.len -= record_len;
+        ssl3_BufferEnsure(&ss->sec.ci.sendBuf, ss->sec.writeBuf.len);
+        memcpy(&ss->sec.ci.sendBuf.buf[record_offset], ss->sec.writeBuf.buf,
+               ss->sec.writeBuf.len);
+        ss->sec.ci.sendBuf.len += ss->sec.writeBuf.len;
+        ss->sec.writeBuf.len = 0;
+    }
+
+    return SECSuccess;
+}
+
+/* ssl3_AppendSnapStartApplicationData appends an encrypted Application Data
+** record the sendBuf of the given sslSocket.
+*/
+static SECStatus ssl3_AppendSnapStartApplicationData(
+    sslSocket *ss, const SSL3Opaque *data, unsigned int len)
+{
+    SECStatus rv;
+
+    /* TODO(agl): the buffer copy here is a bodge. See TODO at the top of the
+     * file. */
+    rv = ssl3_CompressMACEncryptRecord(ss, content_application_data, data, len);
+    if (rv != SECSuccess)
+        return rv;
+    rv = ssl3_BufferEnsure(&ss->sec.ci.sendBuf, ss->sec.writeBuf.len);
+    if (rv != SECSuccess)
+        return rv;
+    memcpy(&ss->sec.ci.sendBuf.buf[ss->sec.ci.sendBuf.len],
+           ss->sec.writeBuf.buf, ss->sec.writeBuf.len);
+    ss->sec.ci.sendBuf.len += ss->sec.writeBuf.len;
+    ss->sec.writeBuf.len = 0;
+
+    return SECSuccess;
+}
+
+static SECStatus ssl3_SendSnapStartFinished(sslSocket *ss)
+{
+    /* We use ssl_SEND_FLAG_NO_FLUSH here because this finished message is
+     * going to end up in the middle of the Snap Start extension. So
+     * transmitting |sendBuf| at this point would result in an incomplete
+     * ClientHello. */
+    return ssl3_SendFinished(ss, ssl_SEND_FLAG_NO_FLUSH);
+}
+
+/* ssl3_FindOrbit is called for each extension in a ServerHello message. It
+** tests for a Snap Start extension and records the server's orbit when found.
+**   data: the extension data (including the four type and length bytes)
+**   length: the length, in bytes, of |data|
+**   ptr: a pointer to a uint8_t[9]. The orbit, if found, is copied into the
+**       first 8 bytes and then the ninth byte is set to one.
+*/
+static void
+ssl3_FindOrbit(const unsigned char *data, unsigned int length, void *ptr)
+{
+    unsigned char *orbit = (unsigned char *) ptr;
+
+    unsigned int extension_num = GetBE16(data);
+    if (extension_num == ssl_snap_start_xtn &&
+        length == 4 + 8 /* orbit */ + 2 /* snap start cipher suite */) {
+        memcpy(orbit, data + 4, 8);
+        /* A last byte of 1 indicates that the previous eight are valid. */
+        orbit[8] = 1;
+    }
+}
+
+/* ssl3_CanSnapStart returns true if we are able to perform Snap Start on
+** the given socket.
+**   extensions: on successful return, this is filled in with the contents of
+**       the server's predicted extensions. This points within
+**       |ss->ssl3.serverHelloPredictionData|.
+**   resuming: PR_TRUE iff we wish to attempt a Snap Start resume
+**   out_orbit: if this function returns PR_TRUE, then |out_orbit| is filled
+**       with the server's predicted orbit value.
+** The |hs.cipher_suite|, |hs.cipher_def| and |hs.compression| fields of |ss|
+** are set to match the predicted ServerHello on successful exit (and may still
+** be modified on failure).
+*/
+static PRBool
+ssl3_CanSnapStart(sslSocket *ss, SECItem *extensions, PRBool resuming,
+                  unsigned char out_orbit[8]) {
+    const unsigned char *server_hello;
+    unsigned int server_hello_len, session_id_len, cipher_suite_offset;
+    unsigned int extensions_offset, cipher_suite, compression_method;
+    unsigned char orbit[9];
+    SECStatus rv;
+    SSL3ProtocolVersion version;
+
+    /* If we don't have the information needed then we can't perform a Snap
+     * Start. */
+    if (!ss->ssl3.predictedCertChain || !ss->ssl3.serverHelloPredictionData.data)
+        return PR_FALSE;
+
+    /* When the sizes of the fields in the ClientHello are calculated, they'll
+     * take the length of the Snap Start extension to be zero, so currently
+     * it's as if this extension didn't exist, which is the state that we
+     * need. */
+
+    server_hello = ss->ssl3.serverHelloPredictionData.data;
+    server_hello_len = ss->ssl3.serverHelloPredictionData.len;
+
+    if (server_hello_len < 2 + 32 + 1)
+        return PR_FALSE;
+    session_id_len = server_hello[2 + 32];
+    cipher_suite_offset = 2 + 32 + 1 + session_id_len;
+    if (server_hello_len < cipher_suite_offset + 3)
+        return PR_FALSE;
+    extensions_offset = cipher_suite_offset + 3;
+
+    version = (SSL3ProtocolVersion) GetBE16(server_hello);
+    if (MSB(version) < MSB(SSL_LIBRARY_VERSION_3_0))
+        return PR_FALSE;
+    rv = ssl3_NegotiateVersion(ss, version);
+    if (rv != SECSuccess)
+        return PR_FALSE;
+
+    cipher_suite = GetBE16(&server_hello[cipher_suite_offset]);
+    ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)cipher_suite;
+    ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
+    if (!ss->ssl3.hs.suite_def)
+        return PR_FALSE;
+    compression_method = server_hello[cipher_suite_offset + 2];
+    if (compression_method != ssl_compression_null) {
+        /* TODO(agl): support compression. */
+        return PR_FALSE;
+    }
+    ss->ssl3.hs.compression = ssl_compression_null;
+
+    extensions->data = (unsigned char *) server_hello + extensions_offset;
+    extensions->len = server_hello_len - extensions_offset;
+
+    /* The last byte is used to indictate that the previous eight are valid. */
+    orbit[8] = 0;
+    if (!ssl3_ForEachExtension(extensions, resuming, ssl3_FindOrbit, orbit))
+        return PR_FALSE;
+
+    if (!orbit[8])
+        return PR_FALSE;
+
+    memcpy(out_orbit, orbit, 8);
+
+    return PR_TRUE;
+}
+
+/* ssl3_UpdateClientHelloLengths rewrites the handshake header length and
+** extensions length in the ClientHello to reflect the addition of the Snap
+** Start extension.
+**   snap_start_extension_len_offset: the number of bytes of the ClientHello to
+**       skip in order to find the embedded length of the Snap Start extension.
+*/
+static void
+ssl3_UpdateClientHelloLengths(sslSocket *ss,
+                              unsigned int snap_start_extension_len_offset,
+                              sslSessionID *sid) {
+    unsigned int extension_length, old_length, new_length, new_session_id_len;
+    unsigned int offset, ciphers_length, compressions_len;
+
+    extension_length =
+        ss->sec.ci.sendBuf.len - snap_start_extension_len_offset - 2;
+    PutBE16(&ss->sec.ci.sendBuf.buf[snap_start_extension_len_offset],
+            extension_length);
+
+    /* The length in the handshake header is short by extension_length + 4
+     * bytes. */
+    old_length = GetBE24(&ss->sec.ci.sendBuf.buf[1]);
+    new_length = old_length + extension_length + 4;
+    PutBE24(&ss->sec.ci.sendBuf.buf[1], new_length);
+
+    /* The length of the extensions block is similarly wrong. */
+    new_session_id_len = 0;
+    if (sid)
+        new_session_id_len = sid->u.ssl3.sessionIDLength;
+    offset = 4 + 2 + 32 + 1 + new_session_id_len;
+    ciphers_length = GetBE16(&ss->sec.ci.sendBuf.buf[offset]);
+    offset += 2 + ciphers_length;
+    compressions_len = ss->sec.ci.sendBuf.buf[offset];
+    offset += 1 + compressions_len;
+    old_length = GetBE16(&ss->sec.ci.sendBuf.buf[offset]);
+    new_length = old_length + extension_length + 4;
+    PutBE16(&ss->sec.ci.sendBuf.buf[offset], new_length);
+}
+
+/* ssl3_FindServerNPNExtension is a callback function for ssl3_ForEachExtension.
+ * It looks for a Next Protocol Negotiation and saves the payload of the
+ * extension in the given SECItem */
+static void
+ssl3_FindServerNPNExtension(const unsigned char* data, unsigned int length,
+                            void *ctx)
+{
+    SECItem *server_npn_extension = (SECItem*) ctx;
+
+    unsigned int extension_num = GetBE16(data);
+    if (extension_num == ssl_next_proto_neg_xtn && length >= 4) {
+        server_npn_extension->data = (unsigned char*)data + 4;
+        server_npn_extension->len = length - 4;
+    }
+}
+
+/* ssl3_MaybeWriteNextProtocol deals with the interaction of Next Protocol
+ * Negotiation and Snap Start. It's called just before we serialise the embedded
+ * Finished message in the extension. At this point, if NPN is enabled, we have
+ * to include a NextProtocol message. */
+static SECStatus
+ssl3_MaybeWriteNextProtocol(sslSocket *ss, SECItem *server_hello_extensions)
+{
+    PRUint16 i16;
+    SECItem server_npn_extension;
+
+    for (i16 = 0; i16 < ss->xtnData.numAdvertised; i16++) {
+        if (ss->xtnData.advertised[i16] == ssl_next_proto_neg_xtn)
+            break;
+    }
+
+    if (i16 == ss->xtnData.numAdvertised) {
+        /* We didn't send an NPN extension, so no need to do anything here. */
+        return SECSuccess;
+    }
+
+    memset(&server_npn_extension, 0, sizeof(server_npn_extension));
+
+    ssl3_ForEachExtension(
+        server_hello_extensions, PR_FALSE /* is_resuming: value doesn't matter
+        in this case */, ssl3_FindServerNPNExtension, &server_npn_extension);
+
+    if (server_npn_extension.data == NULL) {
+        /* We predicted that the server doesn't support NPN, so nothing to do
+         * here. */
+        return SECSuccess;
+    }
+
+    ssl3_ClientHandleNextProtoNegoXtn(ss, ssl_next_proto_neg_xtn,
+                                      &server_npn_extension);
+
+    if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NO_SUPPORT) {
+        /* The server's predicted NPN extension was malformed. We're didn't pick
+         * a protocol so we won't send a NextProtocol message. However, this is
+         * probably fatal to the connection. */
+        return SECSuccess;
+    }
+
+    return ssl3_AppendSnapStartHandshakeRecord(ss, ssl3_SendNextProto,
+                                               PR_TRUE /* encrypt */);
+}
+
+/* ssl3_SendSnapStartXtn appends a Snap Start extension. It assumes that the
+ * inchoate ClientHello is in |ss->sec.ci.sendBuf|. */
+PRInt32
+ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+{
+    unsigned char orbit[8];
+    PRBool resuming = PR_FALSE;
+    unsigned char suggested_server_random[32];
+    SECStatus rv;
+    PRUint64 fnv;
+    /* The context for |ssl3_SnapStartHash|. The first pointer points to |ss|
+     * and the second to the running FNV1A64 hash of the predicted server
+     * response. */
+    void *ctx[2];
+    unsigned int snap_start_extension_len_offset, original_sendbuf_len;
+    ssl3CipherSpec *temp;
+    sslSessionID *sid;
+    SECItem server_extensions;
+
+    if (!ss->opt.enableSnapStart)
+        return 0;
+
+    original_sendbuf_len = ss->sec.ci.sendBuf.len;
+
+    /* This function is called twice for each ClientHello emitted. The first
+     * time around is to calculate the sizes of the extension (|append| is
+     * false). The second time around is to actually write out the bytes
+     * (|append| is true).
+     *
+     * We always return 0 bytes in each case because we want to be able to hash
+     * the inchoate ClientHello as if this extension was missing: that's why
+     * it's important that this always be the last extension serialised. */
+    sid = ss->sec.ci.sid;
+
+    if (!ss->opt.enableSessionTickets || ss->sec.isServer)
+        return 0;
+
+    /* If we are sending a SessionTicket then the first time around
+     * ticketTimestampVerified will be true but it's reset after serialising
+     * the session ticket extension, so we have
+     * |clientSentNonEmptySessionTicket|. */
+    if (ss->xtnData.clientSentNonEmptySessionTicket) {
+        resuming = PR_TRUE;
+    } else if (sid->u.ssl3.sessionTicket.ticket.data &&
+               ss->xtnData.ticketTimestampVerified) {
+        resuming = PR_TRUE;
+    }
+
+    if (!ssl3_CanSnapStart(ss, &server_extensions, resuming, orbit))
+        return ssl3_SendEmptySnapStartXtn(ss, append, maxBytes);
+
+    /* At this point we are happy that we are going to send a non-empty Snap
+     * Start extension. If we are still calculating length then we lie and
+     * return 0 so that everything is set up as if the extension didn't exist
+     * when this function is called again later. */
+
+    if (!append)
+        return 0;
+
+    /* |ss->sec.ci.sendBuf.buf| contains the inchoate ClientHello. This copies
+     * the ClientHello's gmt_unix_time into the suggested server random. */
+    memcpy(suggested_server_random, ss->sec.ci.sendBuf.buf + 6, 4);
+    memcpy(suggested_server_random + 4, orbit, 8);
+    rv = PK11_GenerateRandom(suggested_server_random + 12, 20);
+    if (rv != SECSuccess)
+        goto loser;
+    memcpy(ss->ssl3.serverHelloPredictionData.data + 2, suggested_server_random,
+           32);
+
+    memcpy(&ss->ssl3.hs.server_random, suggested_server_random, 32);
+
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+    rv = ssl3_SetupPendingCipherSpec(ss);
+    if (rv != SECSuccess)
+        goto loser;
+    ss->ssl3.hs.isResuming = resuming;
+
+    FNV1A64_Init(&fnv);
+    ctx[0] = ss;
+    ctx[1] = &fnv;
+
+    if (!ssl3_PredictServerResponse(ss, &ss->ssl3.serverHelloPredictionData,
+                                    resuming, ssl3_SnapStartHash, ctx)) {
+        /* It's not a fatal error if the predicted ServerHello was invalid. */
+        return 0;
+    }
+    FNV1A64_Final(&fnv);
+
+    /* Now we grow the send buffer to accomodate the extension type and length,
+     * orbit, suggested random and predicted server response hash without
+     * calling ssl3_AppendHandshake (which would also update the Finished
+     * hash). */
+    if (ssl3_BufferEnsure(&ss->sec.ci.sendBuf, 4 + 8 + 20 + 8) != SECSuccess)
+        goto loser;
+
+    PutBE16(&ss->sec.ci.sendBuf.buf[ss->sec.ci.sendBuf.len],
+            ssl_snap_start_xtn);
+    ss->sec.ci.sendBuf.len += 2;
+    /* Skip over the length for now. */
+    snap_start_extension_len_offset = ss->sec.ci.sendBuf.len;
+    ss->sec.ci.sendBuf.len += 2;
+    memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, orbit, 8);
+    ss->sec.ci.sendBuf.len += 8;
+    memcpy(&ss->sec.ci.sendBuf.buf[ss->sec.ci.sendBuf.len],
+           suggested_server_random + 12, 20);
+    ss->sec.ci.sendBuf.len += 20;
+    memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, &fnv, 8);
+    ss->sec.ci.sendBuf.len += 8;
+
+    if (!resuming) {
+        /* Write ClientKeyExchange */
+        ss->sec.peerCert =
+            CERT_DupCertificate(ss->ssl3.predictedCertChain[0]);
+        rv = ssl3_AppendSnapStartHandshakeRecord(
+                ss, ssl3_SendClientKeyExchange, PR_FALSE /* do not encrypt */);
+        if (rv != SECSuccess)
+            goto loser;
+    } else {
+        SSL3Finished hashes;
+        TLSFinished tlsFinished;
+        unsigned char hdr[4];
+
+        rv = ssl3_SetupMasterSecretFromSessionID(ss);
+        if (rv == SECFailure)
+            goto loser;
+
+        if (sid->peerCert != NULL) {
+            ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+            ssl3_CopyPeerCertsFromSID(ss, sid);
+        }
+
+        rv = ssl3_InitPendingCipherSpec(ss, NULL /* re-use master secret */);
+        if (rv != SECSuccess)
+            goto loser;
+
+        /* Need to add the server's predicted Finished message to our handshake
+         * hash in order to be able to produce our own Finished message. */
+        rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes,
+                                         0 /* only for SSL3 */);
+        if (rv != SECSuccess)
+            goto loser;
+
+        rv = ssl3_ComputeTLSFinished(ss->ssl3.pwSpec, PR_TRUE /* isServer */,
+                                     &hashes, &tlsFinished);
+        if (rv != SECSuccess)
+            goto loser;
+
+        hdr[0] = (unsigned char) finished;
+        hdr[1] = hdr[2] = 0;
+        hdr[3] = sizeof(tlsFinished.verify_data);
+        ssl3_UpdateHandshakeHashes(ss, hdr, sizeof(hdr));
+        ssl3_UpdateHandshakeHashes(ss, tlsFinished.verify_data,
+                                   sizeof(tlsFinished.verify_data));
+
+        /* Store the Finished message so that we can verify it later */
+        memcpy(&ss->ssl3.hs.finishedMsgs.tFinished[1], tlsFinished.verify_data,
+               sizeof(tlsFinished.verify_data));
+    }
+
+    /* Write ChangeCipherSpec */
+    rv = ssl3_AppendSnapStartRecordHeader(ss, content_change_cipher_spec, 1);
+    if (rv != SECSuccess)
+        goto loser;
+    rv = ssl3_BufferEnsure(&ss->sec.ci.sendBuf, 1);
+    if (rv != SECSuccess)
+        goto loser;
+    ss->sec.ci.sendBuf.buf[ss->sec.ci.sendBuf.len] = change_cipher_spec_choice;
+    ss->sec.ci.sendBuf.len++;
+
+    /* We swap |cwSpec| and |pwSpec| temporarily in order to encrypt some
+     * records before switching them back so that the whole ClientHello doesn't
+     * get encrypted. */
+    ssl_GetSpecWriteLock(ss);
+    temp = ss->ssl3.cwSpec;
+    ss->ssl3.cwSpec = ss->ssl3.pwSpec;
+    ss->ssl3.pwSpec = temp;
+    ss->ssl3.cwSpec->write_seq_num.high = 0;
+    ss->ssl3.cwSpec->write_seq_num.low  = 0;
+    ssl_ReleaseSpecWriteLock(ss);
+
+    rv = ssl3_MaybeWriteNextProtocol(ss, &server_extensions);
+    if (rv != SECSuccess)
+        goto loser;
+
+    /* Write Finished */
+    rv = ssl3_AppendSnapStartHandshakeRecord(ss, ssl3_SendSnapStartFinished,
+                                             PR_TRUE /* encrypt */);
+    if (rv != SECSuccess)
+        goto loser;
+
+    /* Write application data */
+    if (ss->ssl3.snapStartApplicationData.data) {
+        rv = ssl3_AppendSnapStartApplicationData(
+                 ss, ss->ssl3.snapStartApplicationData.data,
+                 ss->ssl3.snapStartApplicationData.len);
+        if (rv != SECSuccess)
+            goto loser;
+    }
+
+    /* Revert the write cipher spec because the ClientHello will get encrypted
+     * with it otherwise. */
+    ssl_GetSpecWriteLock(ss);
+    temp = ss->ssl3.cwSpec;
+    ss->ssl3.cwSpec = ss->ssl3.pwSpec;
+    ss->ssl3.pwSpec = temp;
+    ssl_ReleaseSpecWriteLock(ss);
+
+    /* Update the lengths in the ClientHello to reflect this extension. */
+    ssl3_UpdateClientHelloLengths(ss, snap_start_extension_len_offset, sid);
+
+    /* Keep a copy of the ClientHello around so that we can hash it in the case
+     * the the Snap Start handshake is rejected. */
+
+    if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.origClientHello,
+                          ss->sec.ci.sendBuf.len) == NULL) {
+        goto loser;
+    }
+    memcpy(ss->ssl3.hs.origClientHello.data, ss->sec.ci.sendBuf.buf,
+           ss->sec.ci.sendBuf.len);
+    ss->ssl3.hs.origClientHello.len = ss->sec.ci.sendBuf.len;
+
+    ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ssl_snap_start_xtn;
+
+    if (resuming) {
+        ss->ssl3.hs.snapStartType = snap_start_resume;
+    } else {
+        ss->ssl3.hs.snapStartType = snap_start_full;
+    }
+
+    return 0;
+
+loser:
+    /* In the case of an error we revert the length of the sendBuf to remove
+     * any partial data that we may have appended. */
+    ss->sec.ci.sendBuf.len = original_sendbuf_len;
+    return -1;
+}
+
+SECStatus ssl3_ClientHandleSnapStartXtn(sslSocket *ss, PRUint16 ex_type,
+                                        SECItem *data) {
+    /* The work of saving the ServerHello is done in ssl3_HandleServerHello,
+     * where its contents are available. Here we renognise that the saved
+     * ServerHello message contains a Snap Start extension and mark it as
+     * valid. */
+    ss->ssl3.serverHelloPredictionDataValid = PR_TRUE;
+    return SECSuccess;
+}
+
+SECStatus
+SSL_SetPredictedPeerCertificates(PRFileDesc *fd, CERTCertificate **certs,
+                                 unsigned int numCerts)
+{
+    sslSocket *ss;
+    unsigned int i;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetPredictedPeerCertificates",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    ss->ssl3.predictedCertChain =
+        PORT_NewArray(CERTCertificate*, numCerts + 1);
+    if (!ss->ssl3.predictedCertChain)
+        return SECFailure;        /* error code was set */
+    for (i = 0; i < numCerts; i++)
+        ss->ssl3.predictedCertChain[i] = CERT_DupCertificate(certs[i]);
+    ss->ssl3.predictedCertChain[numCerts] = NULL;
+
+    return SECSuccess;
+}
+
+void
+ssl3_CleanupPredictedPeerCertificates(sslSocket *ss) {
+    unsigned int i;
+
+    if (!ss->ssl3.predictedCertChain)
+        return;
+
+    for (i = 0; ss->ssl3.predictedCertChain[i]; i++) {
+        CERT_DestroyCertificate(ss->ssl3.predictedCertChain[i]);
+    }
+
+    PORT_Free(ss->ssl3.predictedCertChain);
+    ss->ssl3.predictedCertChain = NULL;
+}
+
+SECStatus
+SSL_GetPredictedServerHelloData(PRFileDesc *fd, const unsigned char **data,
+                                unsigned int *data_len)
+{
+    sslSocket *ss;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetPredictedServerHelloData",
+                 SSL_GETPID(), fd));
+        *data = NULL;
+        *data_len = 0;
+        return SECFailure;
+    }
+
+    if (!ss->ssl3.serverHelloPredictionDataValid) {
+        *data = NULL;
+        *data_len = 0;
+    } else {
+        *data = ss->ssl3.serverHelloPredictionData.data;
+        *data_len = ss->ssl3.serverHelloPredictionData.len;
+    }
+    return SECSuccess;
+}
+
+SECStatus
+SSL_SetPredictedServerHelloData(PRFileDesc *fd, const unsigned char *data,
+                                unsigned int data_len)
+{
+    sslSocket *ss;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetPredictedServerHelloData",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    if (ss->ssl3.serverHelloPredictionData.data)
+        SECITEM_FreeItem(&ss->ssl3.serverHelloPredictionData, PR_FALSE);
+    if (!SECITEM_AllocItem(NULL, &ss->ssl3.serverHelloPredictionData, data_len))
+        return SECFailure;
+    memcpy(ss->ssl3.serverHelloPredictionData.data, data, data_len);
+    return SECSuccess;
+}
+
+SECStatus
+SSL_SetSnapStartApplicationData(PRFileDesc *fd, const unsigned char *data,
+                                unsigned int data_len)
+{
+    sslSocket *ss;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSnapStartApplicationData",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    if (ss->ssl3.snapStartApplicationData.data)
+        SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE);
+    if (!SECITEM_AllocItem(NULL, &ss->ssl3.snapStartApplicationData, data_len))
+        return SECFailure;
+    memcpy(ss->ssl3.snapStartApplicationData.data, data, data_len);
+    return SECSuccess;
+}
+
+SECStatus
+SSL_GetSnapStartResult(PRFileDesc *fd, SSLSnapStartResult *result)
+{
+    sslSocket *ss;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetSnapStartResult",
+                 SSL_GETPID(), fd));
+        return SECFailure;
+    }
+
+    switch (ss->ssl3.hs.snapStartType) {
+        case snap_start_full:
+            *result = SSL_SNAP_START_FULL;
+            break;
+        case snap_start_recovery:
+            *result = SSL_SNAP_START_RECOVERY;
+            break;
+        case snap_start_resume:
+            *result = SSL_SNAP_START_RESUME;
+            break;
+        case snap_start_resume_recovery:
+            *result = SSL_SNAP_START_RESUME_RECOVERY;
+            break;
+        default:
+            PORT_Assert(ss->ssl3.hs.snapStartType == snap_start_none);
+            *result = SSL_SNAP_START_NONE;
+            break;
+    }
+
+    return SECSuccess;
+}
+
+/* Called form ssl3_HandleServerHello in the case that we sent a Snap Start
+** ClientHello but received a ServerHello in reply.
+*/
+SECStatus
+ssl3_ResetForSnapStartRecovery(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+    PRUint8 hdr[4];
+
+    ss->ssl3.hs.ws = wait_server_hello;
+
+    /* Need to reset the Finished hashes to include the full ClientHello
+     * message. */
+
+    rv = ssl3_RestartHandshakeHashes(ss);
+    if (rv != SECSuccess)
+        return rv;
+    rv = ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.origClientHello.data,
+                                    ss->ssl3.hs.origClientHello.len);
+    SECITEM_FreeItem(&ss->ssl3.hs.origClientHello, PR_FALSE);
+    if (rv != SECSuccess)
+        return rv;
+
+    hdr[0] = (PRUint8)server_hello;
+    hdr[1] = (PRUint8)(length >> 16);
+    hdr[2] = (PRUint8)(length >>  8);
+    hdr[3] = (PRUint8)(length      );
+
+    rv = ssl3_UpdateHandshakeHashes(ss, hdr, sizeof(hdr));
+    if (rv != SECSuccess)
+        return rv;
+    rv = ssl3_UpdateHandshakeHashes(ss, b, length);
+    if (rv != SECSuccess)
+        return rv;
+
+    if (ss->ssl3.hs.snapStartType == snap_start_full) {
+        ss->ssl3.hs.snapStartType = snap_start_recovery;
+    } else {
+        ss->ssl3.hs.snapStartType = snap_start_resume_recovery;
+    }
+
+    ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_TRUE/*freeSrvName*/);
+
+    return SECSuccess;
+}
diff --git a/mozilla/security/nss/lib/ssl/ssl.def b/mozilla/security/nss/lib/ssl/ssl.def
index a1f4b51..effc35d 100644
--- a/mozilla/security/nss/lib/ssl/ssl.def
+++ b/mozilla/security/nss/lib/ssl/ssl.def
@@ -159,3 +159,13 @@ SSL_SetNextProtoNego;
 ;+    local:
 ;+*;
 ;+};
+;+NSS_3.13 {      # NSS 3.13 release
+;+    global:
+SSL_GetPredictedServerHelloData;
+SSL_GetSnapStartResult;
+SSL_SetPredictedPeerCertificates;
+SSL_SetPredictedServerHelloData;
+SSL_SetSnapStartApplicationData;
+;+    local:
+;+*;
+;+};
diff --git a/mozilla/security/nss/lib/ssl/ssl.h b/mozilla/security/nss/lib/ssl/ssl.h
index d87ae56..8217d2e 100644
--- a/mozilla/security/nss/lib/ssl/ssl.h
+++ b/mozilla/security/nss/lib/ssl/ssl.h
@@ -139,6 +139,15 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
 /* occur on RSA or DH ciphersuites where the cipher's key length is >= 80   */
 /* bits. The advantage of False Start is that it saves a round trip for     */
 /* client-speaks-first protocols when performing a full handshake.          */
+#define SSL_ENABLE_SNAP_START          23 /* Enable SSL snap start (off by  */
+                                          /* default, applies only to       */
+                                          /* clients). Snap start is a way  */
+/* of performing TLS handshakes with no round trips. The client's entire    */
+/* handshake is included in the first handshake message, along with         */
+/* optional application data. In order to do this, information from a       */
+/* previous connection to the same server is required. See                  */
+/* SSL_GetPredictedServerHelloData, SSL_SetPredictedPeerCertificates and    */
+/* SSL_SetSnapStartApplicationData.                                         */
 
 #ifdef SSL_DEPRECATED_FUNCTION 
 /* Old deprecated function names */
@@ -376,6 +385,49 @@ SSL_IMPORT SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f,
 				     void *arg);
 
 /*
+** Set the predicted chain of certificates for the peer. This is used for the
+** TLS Snap Start extension. Note that the SSL_ENABLE_SNAP_START option must
+** be set for this to occur.
+**
+** This function takes a reference to each of the given certificates.
+*/
+SSL_IMPORT SECStatus SSL_SetPredictedPeerCertificates(
+	PRFileDesc *fd, CERTCertificate **certs,
+	unsigned int numCerts);
+
+/*
+** Get the data needed to predict the server's hello message in the future. On
+** return, |*data| will either be NULL (in which case no data is available and
+** |*data_len| will be zero) or it will point to a buffer within the internal
+** data of |fd| and |*data_len| will contain the number of bytes available. If
+** non-NULL, |*data| will persist at least until the next handshake on |fd|.
+*/
+SSL_IMPORT SECStatus SSL_GetPredictedServerHelloData(
+	PRFileDesc *fd, const unsigned char **data,
+	unsigned int *data_len);
+
+/*
+** Set the predicted server hello data. This is used for the TLS Snap Start
+** extension. Note that the SSL_ENABLE_SNAP_START option must be set for this
+** to occur.
+*/
+SSL_IMPORT SECStatus SSL_SetPredictedServerHelloData(
+	PRFileDesc *fd, const unsigned char *data, unsigned int data_len);
+
+/* Set the application data which will be transmitted in a Snap Start
+** handshake. If the Snap Start handshake fails, this data will be
+* retransmitted automatically. */
+SSL_IMPORT SECStatus SSL_SetSnapStartApplicationData(
+	PRFileDesc *fd, const unsigned char *data, unsigned int data_len);
+
+/* Get the result of a Snap Start handshake. It's valid to call then even if
+** SSL_ENABLE_SNAP_START hasn't been set, although the result will always be
+** SSL_SNAP_START_NONE.
+*/
+SSL_IMPORT SECStatus SSL_GetSnapStartResult(PRFileDesc* socket,
+                                            SSLSnapStartResult* result);
+
+/*
 ** Configure SSL socket for running a secure server. Needs the
 ** certificate for the server and the servers private key. The arguments
 ** are copied.
diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/ssl/ssl3con.c
index 64c3452..9ab2a1c 100644
--- a/mozilla/security/nss/lib/ssl/ssl3con.c
+++ b/mozilla/security/nss/lib/ssl/ssl3con.c
@@ -72,7 +72,8 @@
 #endif
 
 static void      ssl3_CleanupPeerCerts(sslSocket *ss);
-static void      ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid);
+static void      ssl3_CopyPeerCertsToSID(ssl3CertNode *certs,
+                                         sslSessionID *sid);
 static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
                                        PK11SlotInfo * serverKeySlot);
 static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms);
@@ -82,14 +83,10 @@ static SECStatus ssl3_InitState(             sslSocket *ss);
 static SECStatus ssl3_SendCertificate(       sslSocket *ss);
 static SECStatus ssl3_SendEmptyCertificate(  sslSocket *ss);
 static SECStatus ssl3_SendCertificateRequest(sslSocket *ss);
-static SECStatus ssl3_SendNextProto(         sslSocket *ss);
-static SECStatus ssl3_SendFinished(          sslSocket *ss, PRInt32 flags);
 static SECStatus ssl3_SendServerHello(       sslSocket *ss);
 static SECStatus ssl3_SendServerHelloDone(   sslSocket *ss);
 static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss);
 static SECStatus ssl3_NewHandshakeHashes(    sslSocket *ss);
-static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss, unsigned char *b, 
-                                             unsigned int l);
 
 static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
 			     int maxOutputLen, const unsigned char *input,
@@ -583,7 +580,7 @@ void SSL_AtomicIncrementLong(long * x)
 
 /* return pointer to ssl3CipherSuiteDef for suite, or NULL */
 /* XXX This does a linear search.  A binary search would be better. */
-static const ssl3CipherSuiteDef *
+const ssl3CipherSuiteDef *
 ssl_LookupCipherSuiteDef(ssl3CipherSuite suite)
 {
     int cipher_suite_def_len =
@@ -1169,7 +1166,7 @@ ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat)
 **             ssl3_DestroySSL3Info
 ** Caller must hold SpecWriteLock.
 */
-static void
+void
 ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
 {
     PRBool freeit = (PRBool)(!spec->bypassCiphers);
@@ -1211,7 +1208,7 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName)
 ** Caller must hold the ssl3 handshake lock.
 ** Acquires & releases SpecWriteLock.
 */
-static SECStatus
+SECStatus
 ssl3_SetupPendingCipherSpec(sslSocket *ss)
 {
     ssl3CipherSpec *          pwSpec;
@@ -2039,7 +2036,7 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) {
     return isPresent;
 }
 
-static SECStatus
+SECStatus
 ssl3_CompressMACEncryptRecord(sslSocket *        ss,
                               SSL3ContentType    type,
 		              const SSL3Opaque * pIn,
@@ -3097,7 +3094,7 @@ loser:
     return SECFailure;
 }
 
-static SECStatus 
+SECStatus
 ssl3_RestartHandshakeHashes(sslSocket *ss)
 {
     SECStatus rv = SECSuccess;
@@ -3175,7 +3172,7 @@ loser:
 **		ssl3_HandleHandshakeMessage()
 ** Caller must hold the ssl3Handshake lock.
 */
-static SECStatus
+SECStatus
 ssl3_UpdateHandshakeHashes(sslSocket *ss, unsigned char *b, unsigned int l)
 {
     SECStatus  rv = SECSuccess;
@@ -3434,7 +3431,7 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes,
  * Caller must hold a read or write lock on the Spec R/W lock.
  *	(There is presently no way to assert on a Read lock.)
  */
-static SECStatus
+SECStatus
 ssl3_ComputeHandshakeHashes(sslSocket *     ss,
                             ssl3CipherSpec *spec,   /* uses ->master_secret */
 			    SSL3Hashes *    hashes, /* output goes here. */
@@ -4032,7 +4029,18 @@ ssl3_SendClientHello(sslSocket *ss)
 	return rv;	/* error code set by ssl3_FlushHandshake */
     }
 
-    ss->ssl3.hs.ws = wait_server_hello;
+    switch (ss->ssl3.hs.snapStartType) {
+    case snap_start_full:
+	ss->ssl3.hs.ws = wait_new_session_ticket;
+	break;
+    case snap_start_resume:
+	ss->ssl3.hs.ws = wait_change_cipher;
+	break;
+    default:
+	ss->ssl3.hs.ws = wait_server_hello;
+	break;
+    }
+
     return rv;
 }
 
@@ -4723,7 +4731,7 @@ loser:
 
 
 /* Called from ssl3_HandleServerHelloDone(). */
-static SECStatus
+SECStatus
 ssl3_SendClientKeyExchange(sslSocket *ss)
 {
     SECKEYPublicKey *	serverKey 	= NULL;
@@ -4862,6 +4870,94 @@ done:
     return rv;
 }
 
+/* Called from ssl3_HandleServerHello to set up the master secret in
+ * ss->ssl3.pwSpec and the auth algorithm and kea type in ss->sec in the case
+ * of a successful session resumption. */
+SECStatus ssl3_SetupMasterSecretFromSessionID(sslSocket* ss) {
+    sslSessionID *sid = ss->sec.ci.sid;
+    ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
+    SECItem wrappedMS;   /* wrapped master secret. */
+
+    ss->sec.authAlgorithm = sid->authAlgorithm;
+    ss->sec.authKeyBits   = sid->authKeyBits;
+    ss->sec.keaType       = sid->keaType;
+    ss->sec.keaKeyBits    = sid->keaKeyBits;
+
+    /* 3 cases here:
+     * a) key is wrapped (implies using PKCS11)
+     * b) key is unwrapped, but we're still using PKCS11
+     * c) key is unwrapped, and we're bypassing PKCS11.
+     */
+    if (sid->u.ssl3.keys.msIsWrapped) {
+	PK11SlotInfo *slot;
+	PK11SymKey *  wrapKey;     /* wrapping key */
+	CK_FLAGS      keyFlags      = 0;
+
+	if (ss->opt.bypassPKCS11) {
+	    /* we cannot restart a non-bypass session in a
+	    ** bypass socket.
+	    */
+	    return SECFailure;
+	}
+	/* unwrap master secret with PKCS11 */
+	slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
+				 sid->u.ssl3.masterSlotID);
+	if (slot == NULL) {
+	    return SECFailure;
+	}
+	if (!PK11_IsPresent(slot)) {
+	    PK11_FreeSlot(slot);
+	    return SECFailure;
+	}
+	wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex,
+				  sid->u.ssl3.masterWrapMech,
+				  sid->u.ssl3.masterWrapSeries,
+				  ss->pkcs11PinArg);
+	PK11_FreeSlot(slot);
+	if (wrapKey == NULL) {
+	    return SECFailure;
+	}
+
+	if (ss->version > SSL_LIBRARY_VERSION_3_0) {	/* isTLS */
+	    keyFlags = CKF_SIGN | CKF_VERIFY;
+	}
+
+	wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+	wrappedMS.len  = sid->u.ssl3.keys.wrapped_master_secret_len;
+	pwSpec->master_secret =
+	    PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
+			NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
+			CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags);
+	PK11_FreeSymKey(wrapKey);
+	if (pwSpec->master_secret == NULL) {
+	    return SECFailure;
+	}
+    } else if (ss->opt.bypassPKCS11) {
+	/* MS is not wrapped */
+	wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+	wrappedMS.len  = sid->u.ssl3.keys.wrapped_master_secret_len;
+	memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len);
+	pwSpec->msItem.data = pwSpec->raw_master_secret;
+	pwSpec->msItem.len  = wrappedMS.len;
+    } else {
+	/* We CAN restart a bypass session in a non-bypass socket. */
+	/* need to import the raw master secret to session object */
+	PK11SlotInfo *slot = PK11_GetInternalSlot();
+	wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
+	wrappedMS.len  = sid->u.ssl3.keys.wrapped_master_secret_len;
+	pwSpec->master_secret =
+	    PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE,
+			      PK11_OriginUnwrap, CKA_ENCRYPT,
+			      &wrappedMS, NULL);
+	PK11_FreeSlot(slot);
+	if (pwSpec->master_secret == NULL) {
+	    return SECFailure;
+	}
+    }
+
+    return SECSuccess;
+}
+
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 ServerHello message.
  * Caller must hold Handshake and RecvBuf locks.
@@ -4886,6 +4982,14 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
+    if (ss->ssl3.hs.snapStartType == snap_start_full ||
+	ss->ssl3.hs.snapStartType == snap_start_resume) {
+	/* Snap Start handshake was rejected. */
+        rv = ssl3_ResetForSnapStartRecovery(ss, b, length);
+        if (rv != SECSuccess)
+            return rv;
+    }
+
     rv = ssl3_InitState(ss);
     if (rv != SECSuccess) {
 	errCode = PORT_GetError(); /* ssl3_InitState has set the error code. */
@@ -4897,6 +5001,21 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 	goto alert_loser;
     }
 
+    if (!ss->ssl3.serverHelloPredictionData.data) {
+        /* If this allocation fails it will only stop the application from
+	 * recording the ServerHello information and performing future Snap
+	 * Starts. */
+	if (SECITEM_AllocItem(NULL, &ss->ssl3.serverHelloPredictionData,
+			      length))
+	    memcpy(ss->ssl3.serverHelloPredictionData.data, b, length);
+	/* ss->ssl3.serverHelloPredictionDataValid is still false at this
+	 * point. We have to record the contents of the ServerHello here
+	 * because we don't have a pointer to the whole message when handling
+	 * the extensions. However, we wait until the Snap Start extenion
+	 * handler to recognise that the server supports Snap Start and to set
+	 * serverHelloPredictionDataValid. */
+    }
+
     temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
     if (temp < 0) {
     	goto loser; 	/* alert has been sent */
@@ -5037,118 +5156,40 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 
     if (sid_match &&
 	sid->version == ss->version &&
-	sid->u.ssl3.cipherSuite == ss->ssl3.hs.cipher_suite) do {
-	ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
-
-	SECItem       wrappedMS;   /* wrapped master secret. */
+	sid->u.ssl3.cipherSuite == ss->ssl3.hs.cipher_suite) {
+	rv = ssl3_SetupMasterSecretFromSessionID(ss);
+	/* Failure of ssl3_SetupMasterSecretFromSessionID not considered an
+	 * error.  Continue with a full handshake. */
+	if (rv == SECSuccess) {
+	    /* Got a Match */
+	    SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_hits );
 
-	ss->sec.authAlgorithm = sid->authAlgorithm;
-	ss->sec.authKeyBits   = sid->authKeyBits;
-	ss->sec.keaType       = sid->keaType;
-	ss->sec.keaKeyBits    = sid->keaKeyBits;
+	    /* If we sent a session ticket, then this is a stateless resume. */
+	    if (sid->version > SSL_LIBRARY_VERSION_3_0 &&
+		sid->u.ssl3.sessionTicket.ticket.data != NULL)
+		SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_stateless_resumes );
 
-	/* 3 cases here:
-	 * a) key is wrapped (implies using PKCS11)
-	 * b) key is unwrapped, but we're still using PKCS11
-	 * c) key is unwrapped, and we're bypassing PKCS11.
-	 */
-	if (sid->u.ssl3.keys.msIsWrapped) {
-	    PK11SlotInfo *slot;
-	    PK11SymKey *  wrapKey;     /* wrapping key */
-	    CK_FLAGS      keyFlags      = 0;
+	    if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
+		ss->ssl3.hs.ws = wait_new_session_ticket;
+	    else
+		ss->ssl3.hs.ws = wait_change_cipher;
 
-	    if (ss->opt.bypassPKCS11) {
-		/* we cannot restart a non-bypass session in a 
-		** bypass socket.
-		*/
-		break;  
-	    }
-	    /* unwrap master secret with PKCS11 */
-	    slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
-				     sid->u.ssl3.masterSlotID);
-	    if (slot == NULL) {
-		break;		/* not considered an error. */
-	    }
-	    if (!PK11_IsPresent(slot)) {
-		PK11_FreeSlot(slot);
-		break;		/* not considered an error. */
-	    }
-	    wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex,
-				      sid->u.ssl3.masterWrapMech,
-				      sid->u.ssl3.masterWrapSeries,
-				      ss->pkcs11PinArg);
-	    PK11_FreeSlot(slot);
-	    if (wrapKey == NULL) {
-		break;		/* not considered an error. */
-	    }
+	    ss->ssl3.hs.isResuming = PR_TRUE;
 
-	    if (ss->version > SSL_LIBRARY_VERSION_3_0) {	/* isTLS */
-		keyFlags = CKF_SIGN | CKF_VERIFY;
+	    /* copy the peer cert from the SID */
+	    if (sid->peerCert != NULL) {
+		ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
+		ssl3_CopyPeerCertsFromSID(ss, sid);
 	    }
 
-	    wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
-	    wrappedMS.len  = sid->u.ssl3.keys.wrapped_master_secret_len;
-	    pwSpec->master_secret =
-		PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, 
-			    NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE,
-			    CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags);
-	    errCode = PORT_GetError();
-	    PK11_FreeSymKey(wrapKey);
-	    if (pwSpec->master_secret == NULL) {
-		break;	/* errorCode set just after call to UnwrapSymKey. */
-	    }
-	} else if (ss->opt.bypassPKCS11) {
-	    /* MS is not wrapped */
-	    wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
-	    wrappedMS.len  = sid->u.ssl3.keys.wrapped_master_secret_len;
-	    memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len);
-	    pwSpec->msItem.data = pwSpec->raw_master_secret;
-	    pwSpec->msItem.len  = wrappedMS.len;
-	} else {
-	    /* We CAN restart a bypass session in a non-bypass socket. */
-	    /* need to import the raw master secret to session object */
-	    PK11SlotInfo *slot = PK11_GetInternalSlot();
-	    wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
-	    wrappedMS.len  = sid->u.ssl3.keys.wrapped_master_secret_len;
-	    pwSpec->master_secret =  
-		PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, 
-				  PK11_OriginUnwrap, CKA_ENCRYPT, 
-				  &wrappedMS, NULL);
-	    PK11_FreeSlot(slot);
-	    if (pwSpec->master_secret == NULL) {
-		break; 
+	    /* NULL value for PMS signifies re-use of the old MS */
+	    rv = ssl3_InitPendingCipherSpec(ss,  NULL);
+	    if (rv != SECSuccess) {
+		goto alert_loser;
 	    }
+	    return SECSuccess;
 	}
-
-	/* Got a Match */
-	SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_hits );
-
-	/* If we sent a session ticket, then this is a stateless resume. */
-	if (sid->version > SSL_LIBRARY_VERSION_3_0 &&
-	    sid->u.ssl3.sessionTicket.ticket.data != NULL)
-	    SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_stateless_resumes );
-
-	if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
-	    ss->ssl3.hs.ws = wait_new_session_ticket;
-	else
-	    ss->ssl3.hs.ws = wait_change_cipher;
-
-	ss->ssl3.hs.isResuming = PR_TRUE;
-
-	/* copy the peer cert from the SID */
-	if (sid->peerCert != NULL) {
-	    ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
-	    ssl3_CopyPeerCertsFromSID(ss, sid);
-	}
-
-
-	/* NULL value for PMS signifies re-use of the old MS */
-	rv = ssl3_InitPendingCipherSpec(ss,  NULL);
-	if (rv != SECSuccess) {
-	    goto alert_loser;	/* err code was set */
-	}
-	return SECSuccess;
-    } while (0);
+    }
 
     if (sid_match)
 	SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_not_ok );
@@ -6116,7 +6157,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
      * ticket extension, but sent an empty ticket.
      */
     if (!ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) ||
-	ss->xtnData.emptySessionTicket) {
+	ss->xtnData.serverReceivedEmptySessionTicket) {
 	if (sidBytes.len > 0 && !ss->opt.noCache) {
 	    SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x",
 			SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0],
@@ -7569,6 +7610,12 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 	return SECFailure;  /* malformed */
     }
 
+    if (ss->sec.ci.sid->peerCert == NULL) {
+	ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
+	ssl3_CopyPeerCertsToSID((ssl3CertNode *)ss->ssl3.peerCertChain,
+				ss->sec.ci.sid);
+    }
+
     rv = ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &session_ticket);
     if (rv != SECSuccess) {
 	(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
@@ -7760,7 +7807,7 @@ ssl3_CleanupPeerCerts(sslSocket *ss)
     ss->ssl3.peerCertChain = NULL;
 }
 
-static void
+void
 ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid)
 {
     PRArenaPool *arena;
@@ -8163,7 +8210,7 @@ ssl3_RestartHandshakeAfterServerCert(sslSocket *ss)
     return rv;
 }
 
-static SECStatus
+SECStatus
 ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
 			PRBool          isServer,
                 const   SSL3Finished *  hashes,
@@ -8211,7 +8258,7 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
 
 /* called from ssl3_HandleServerHelloDone
  */
-static SECStatus
+SECStatus
 ssl3_SendNextProto(sslSocket *ss)
 {
     SECStatus rv;
@@ -8247,7 +8294,7 @@ ssl3_SendNextProto(sslSocket *ss)
  *             ssl3_HandleClientHello
  *             ssl3_HandleFinished
  */
-static SECStatus
+SECStatus
 ssl3_SendFinished(sslSocket *ss, PRInt32 flags)
 {
     ssl3CipherSpec *cwSpec;
@@ -8300,10 +8347,27 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags)
 	if (rv != SECSuccess) 
 	    goto fail; 		/* err set by AppendHandshake. */
     }
-    rv = ssl3_FlushHandshake(ss, flags);
-    if (rv != SECSuccess) {
-	goto fail;	/* error code set by ssl3_FlushHandshake */
+    if ((flags & ssl_SEND_FLAG_NO_FLUSH) == 0) {
+	rv = ssl3_FlushHandshake(ss, flags);
+	if (rv != SECSuccess) {
+	    goto fail;	/* error code set by ssl3_FlushHandshake */
+	}
     }
+
+    if ((ss->ssl3.hs.snapStartType == snap_start_recovery ||
+         ss->ssl3.hs.snapStartType == snap_start_resume_recovery) &&
+	ss->ssl3.snapStartApplicationData.data) {
+	/* In the event that the server ignored the application data in our
+	 * snap start extension, we need to retransmit it now. */
+	PRInt32 sent = ssl3_SendRecord(ss, content_application_data,
+                                       ss->ssl3.snapStartApplicationData.data,
+                                       ss->ssl3.snapStartApplicationData.len,
+                                       flags);
+	SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE);
+	if (sent < 0)
+	    return (SECStatus)sent;	/* error code set by ssl3_SendRecord */
+    }
+
     return SECSuccess;
 
 fail:
@@ -8420,6 +8484,16 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
 	return SECFailure;
     }
 
+    if (ss->ssl3.hs.snapStartType == snap_start_full ||
+        ss->ssl3.hs.snapStartType == snap_start_resume) {
+	/* Snap Start handshake was successful. Switch the cipher spec. */
+	ssl_GetSpecWriteLock(ss);
+	ssl3_DestroyCipherSpec(ss->ssl3.cwSpec, PR_TRUE/*freeSrvName*/);
+	ss->ssl3.cwSpec = ss->ssl3.pwSpec;
+	ss->ssl3.pwSpec = NULL;
+	ssl_ReleaseSpecWriteLock(ss);
+    }
+
     isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0);
     if (isTLS) {
 	TLSFinished tlsFinished;
@@ -8429,12 +8503,21 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
 	    PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
 	    return SECFailure;
 	}
-	rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer, 
-	                             hashes, &tlsFinished);
-	if (!isServer)
-	    ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
-	else
-	    ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
+
+	if (ss->ssl3.hs.snapStartType == snap_start_resume) {
+	    /* In this case we have already advanced the Finished hash past the
+	     * server's verify_data because we needed to predict the server's
+	     * Finished message in order to compute our own (which includes
+	     * it). When we did this, we stored a copy in tFinished[1]. */
+            tlsFinished = ss->ssl3.hs.finishedMsgs.tFinished[1];
+	} else {
+	    rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer,
+					 hashes, &tlsFinished);
+	    if (!isServer)
+		ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
+	    else
+		ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
+	}
 	ss->ssl3.hs.finishedBytes = sizeof tlsFinished;
 	if (rv != SECSuccess ||
 	    0 != NSS_SecureMemcmp(&tlsFinished, b, length)) {
@@ -8465,8 +8548,9 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
 
     ssl_GetXmitBufLock(ss);	/*************************************/
 
-    if ((isServer && !ss->ssl3.hs.isResuming) ||
-	(!isServer && ss->ssl3.hs.isResuming)) {
+    if (ss->ssl3.hs.snapStartType != snap_start_resume &&
+	((isServer && !ss->ssl3.hs.isResuming) ||
+	 (!isServer && ss->ssl3.hs.isResuming))) {
 	PRInt32 flags = 0;
 
 	/* Send a NewSessionTicket message if the client sent us
@@ -8582,7 +8666,10 @@ xmit_loser:
     ss->ssl3.hs.ws = idle_handshake;
 
     /* Do the handshake callback for sslv3 here, if we cannot false start. */
-    if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) {
+    if (ss->handshakeCallback != NULL &&
+        (!ssl3_CanFalseStart(ss) ||
+         ss->ssl3.hs.snapStartType == snap_start_full ||
+         ss->ssl3.hs.snapStartType == snap_start_resume)) {
 	(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
     }
 
@@ -8643,8 +8730,13 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 	    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 messages in the handshake hashes.
+     * Likewise, for Finished messages from the server during a Snap Start
+     * resume, we have already predicted and included the message in our
+     * Finished hash. */
+    if (ss->ssl3.hs.msg_type != hello_request &&
+	!(ss->ssl3.hs.msg_type == finished &&
+	 ss->ssl3.hs.snapStartType == snap_start_resume)) {
 	rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) hdr, 4);
 	if (rv != SECSuccess) return rv;	/* err code already set. */
 	rv = ssl3_UpdateHandshakeHashes(ss, b, length);
@@ -9545,6 +9637,15 @@ ssl3_DestroySSL3Info(sslSocket *ss)
        ss->ssl3.clientCertChain = NULL;
     }
 
+    if (ss->ssl3.predictedCertChain != NULL)
+	ssl3_CleanupPredictedPeerCertificates(ss);
+
+    if (ss->ssl3.serverHelloPredictionData.data)
+	SECITEM_FreeItem(&ss->ssl3.serverHelloPredictionData, PR_FALSE);
+
+    if (ss->ssl3.snapStartApplicationData.data)
+	SECITEM_FreeItem(&ss->ssl3.snapStartApplicationData, PR_FALSE);
+
     /* clean up handshake */
     if (ss->opt.bypassPKCS11) {
 	SHA1_DestroyContext((SHA1Context *)ss->ssl3.hs.sha_cx, PR_FALSE);
@@ -9562,6 +9663,9 @@ ssl3_DestroySSL3Info(sslSocket *ss)
 	ss->ssl3.hs.messages.len = 0;
 	ss->ssl3.hs.messages.space = 0;
     }
+    if (ss->ssl3.hs.origClientHello.data) {
+	SECITEM_FreeItem(&ss->ssl3.hs.origClientHello, PR_FALSE);
+    }
 
     /* free the SSL3Buffer (msg_body) */
     PORT_Free(ss->ssl3.hs.msg_body.buf);
diff --git a/mozilla/security/nss/lib/ssl/ssl3ext.c b/mozilla/security/nss/lib/ssl/ssl3ext.c
index fbd5a91..a7ae062 100644
--- a/mozilla/security/nss/lib/ssl/ssl3ext.c
+++ b/mozilla/security/nss/lib/ssl/ssl3ext.c
@@ -247,6 +247,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
     { ssl_session_ticket_xtn,     &ssl3_ClientHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { ssl_next_proto_neg_xtn,     &ssl3_ClientHandleNextProtoNegoXtn },
+    { ssl_snap_start_xtn,         &ssl3_ClientHandleSnapStartXtn },
     { -1, NULL }
 };
 
@@ -270,7 +271,9 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = {
     { ssl_ec_point_formats_xtn,   &ssl3_SendSupportedPointFormatsXtn },
 #endif
     { ssl_session_ticket_xtn,     &ssl3_SendSessionTicketXtn },
-    { ssl_next_proto_neg_xtn,     &ssl3_ClientSendNextProtoNegoXtn }
+    { ssl_next_proto_neg_xtn,     &ssl3_ClientSendNextProtoNegoXtn },
+    { ssl_snap_start_xtn,         &ssl3_SendSnapStartXtn }
+    /* NOTE: The Snap Start sender MUST be the last extension in the list. */
     /* any extra entries will appear as { 0, NULL }    */
 };
 
@@ -298,7 +301,7 @@ ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type) {
 	                          xtnData->numNegotiated, ex_type);
 }
 
-static PRBool
+PRBool
 ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type) {
     TLSExtensionData *xtnData = &ss->xtnData;
     return arrayContainsExtension(xtnData->advertised,
@@ -515,6 +518,8 @@ ssl3_SendSessionTicketXtn(
 	    rv = ssl3_AppendHandshakeVariable(ss, session_ticket->ticket.data,
 		session_ticket->ticket.len, 2);
 	    ss->xtnData.ticketTimestampVerified = PR_FALSE;
+	    if (!ss->sec.isServer)
+		ss->xtnData.clientSentNonEmptySessionTicket = PR_TRUE;
 	} else {
 	    rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
 	}
@@ -573,7 +578,7 @@ ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned short length)
 
 SECStatus
 ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
-                                 SECItem *data)
+                                  SECItem *data)
 {
     unsigned int i, j;
     SECStatus rv;
@@ -1021,7 +1026,7 @@ ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
      * instead of terminating the current connection.
      */
     if (data->len == 0) {
-	ss->xtnData.emptySessionTicket = PR_TRUE;
+	ss->xtnData.serverReceivedEmptySessionTicket = PR_TRUE;
     } else {
 	int                    i;
 	SECItem                extension_data;
diff --git a/mozilla/security/nss/lib/ssl/sslimpl.h b/mozilla/security/nss/lib/ssl/sslimpl.h
index fe7ac7a..f708696 100644
--- a/mozilla/security/nss/lib/ssl/sslimpl.h
+++ b/mozilla/security/nss/lib/ssl/sslimpl.h
@@ -278,6 +278,7 @@ struct sslSocketOpsStr {
 /* 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_NO_FLUSH		0x10000000
 #define ssl_SEND_FLAG_MASK		0x7f000000
 
 /*
@@ -339,6 +340,7 @@ typedef struct sslOptionsStr {
     unsigned int enableRenegotiation    : 2;  /* 20-21 */
     unsigned int requireSafeNegotiation : 1;  /* 22 */
     unsigned int enableFalseStart       : 1;  /* 23 */
+    unsigned int enableSnapStart        : 1;  /* 24 */
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
@@ -743,7 +745,8 @@ struct TLSExtensionDataStr {
 
     /* SessionTicket Extension related data. */
     PRBool ticketTimestampVerified;
-    PRBool emptySessionTicket;
+    PRBool serverReceivedEmptySessionTicket;
+    PRBool clientSentNonEmptySessionTicket;
 
     /* SNI Extension related data
      * Names data is not coppied from the input buffer. It can not be
@@ -753,6 +756,14 @@ struct TLSExtensionDataStr {
     PRUint32 sniNameArrSize;
 };
 
+typedef enum {
+    snap_start_none = 0,
+    snap_start_full,
+    snap_start_recovery,
+    snap_start_resume,
+    snap_start_resume_recovery
+} TLSSnapStartType;
+
 /*
 ** This is the "hs" member of the "ssl3" struct.
 ** This entire struct is protected by ssl3HandshakeLock
@@ -791,6 +802,14 @@ const ssl3CipherSuiteDef *suite_def;
 	SSL3Hashes        sFinished[2];
 	SSL3Opaque        data[72];
     }                     finishedMsgs;
+
+    TLSSnapStartType      snapStartType;
+    /* When we perform a Snap Start handshake, we hash our ClientHello as if
+     * the Snap Start extension wasn't included. However, if the server rejects
+     * our Snap Start attempt, then it will hash the whole ClientHello. Thus we
+     * store the original ClientHello that we sent in case we need to reset our
+     * Finished hash to cover it. */
+    SECItem               origClientHello;
 #ifdef NSS_ENABLE_ECC
     PRUint32              negotiatedECCurves; /* bit mask */
 #endif /* NSS_ENABLE_ECC */
@@ -823,6 +842,17 @@ struct ssl3StateStr {
     CERTCertificateList *clientCertChain;    /* used by client */
     PRBool               sendEmptyCert;      /* used by client */
 
+    /* TLS Snap Start: */
+    CERTCertificate **   predictedCertChain;
+			    /* An array terminated with a NULL. */
+    SECItem		 serverHelloPredictionData;
+    PRBool		 serverHelloPredictionDataValid;
+			    /* data needed to predict the ServerHello from
+			     * this server. */
+    SECItem		 snapStartApplicationData;
+			    /* the application data to include in the Snap
+			     * Start extension. */
+
     int                  policy;
 			/* This says what cipher suites we can do, and should 
 			 * be either SSL_ALLOWED or SSL_RESTRICTED 
@@ -1258,10 +1288,13 @@ extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
 extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, 
                                    const char *peerID, const char *urlSvrName);
 extern void      ssl_FreeSID(sslSessionID *sid);
+extern void      ssl3_CopyPeerCertsFromSID(sslSocket *ss, sslSessionID *sid);
 
 extern int       ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
 				          int len, int flags);
 
+extern SECStatus ssl3_RestartHandshakeHashes(sslSocket *ss);
+
 extern PRBool    ssl_FdIsBlocking(PRFileDesc *fd);
 
 extern PRBool    ssl_SocketIsBlocking(sslSocket *ss);
@@ -1434,6 +1467,9 @@ ECName	ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
 
 #endif /* NSS_ENABLE_ECC */
 
+extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket* ss, unsigned char *b,
+                                            unsigned int l);
+
 extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
 extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on);
 extern SECStatus ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
@@ -1454,6 +1490,7 @@ extern void      ssl3_InitSocketPolicy(sslSocket *ss);
 
 extern SECStatus ssl3_ConstructV2CipherSpecsHack(sslSocket *ss,
 						 unsigned char *cs, int *size);
+extern void ssl3_DestroyCipherSpec(ssl3CipherSpec* spec, PRBool freeSrvName);
 
 extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache);
 
@@ -1503,6 +1540,31 @@ extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash,
 extern SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss,
 			sslSessionID *sid, ssl3CipherSpec *spec,
 			SSL3KEAType effectiveExchKeyType);
+extern void ssl3_CleanupPredictedPeerCertificates(sslSocket *ss);
+extern const ssl3CipherSuiteDef* ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
+extern SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss);
+extern SECStatus ssl3_SendClientKeyExchange(sslSocket *ss);
+extern SECStatus ssl3_SendNextProto(sslSocket *ss);
+extern SECStatus ssl3_SendFinished(sslSocket *ss, PRInt32 flags);
+extern SECStatus ssl3_CompressMACEncryptRecord
+	(sslSocket *        ss,
+	 SSL3ContentType    type,
+	 const SSL3Opaque * pIn,
+	 PRUint32           contentLen);
+extern PRBool ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type);
+extern SECStatus ssl3_SetupMasterSecretFromSessionID(sslSocket* ss);
+extern SECStatus ssl3_ComputeHandshakeHashes(
+	sslSocket *     ss,
+	ssl3CipherSpec *spec,   /* uses ->master_secret */
+	SSL3Hashes *    hashes, /* output goes here. */
+	PRUint32        sender);
+extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket* ss, unsigned char *b,
+					    unsigned int l);
+extern SECStatus ssl3_ComputeTLSFinished(
+	ssl3CipherSpec *spec,
+	PRBool          isServer,
+	const   SSL3Finished *  hashes,
+	TLSFinished  *  tlsFinished);
 
 /* Functions that handle ClientHello and ServerHello extensions. */
 extern SECStatus ssl3_HandleServerNameXtn(sslSocket * ss,
@@ -1532,6 +1594,13 @@ extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
  */
 extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
                      PRUint32 maxBytes);
+extern PRInt32 ssl3_SendSnapStartXtn(sslSocket *ss, PRBool append,
+                     PRUint32 maxBytes);
+extern SECStatus ssl3_ClientHandleSnapStartXtn(sslSocket *ss, PRUint16 ex_type,
+                     SECItem *data);
+
+extern SECStatus ssl3_ResetForSnapStartRecovery(sslSocket *ss,
+                      SSL3Opaque *b, PRUint32 length);
 
 /* Assigns new cert, cert chain and keys to ss->serverCerts
  * struct. If certChain is NULL, tries to find one. Aborts if
@@ -1635,6 +1704,12 @@ SECStatus SSL_DisableDefaultExportCipherSuites(void);
 SECStatus SSL_DisableExportCipherSuites(PRFileDesc * fd);
 PRBool    SSL_IsExportCipherSuite(PRUint16 cipherSuite);
 
+/********************** FNV hash  *********************/
+
+void FNV1A64_Init(PRUint64 *digest);
+void FNV1A64_Update(PRUint64 *digest, const unsigned char *data,
+                    unsigned int length);
+void FNV1A64_Final(PRUint64 *digest);
 
 #ifdef TRACE
 #define SSL_TRACE(msg) ssl_Trace msg
diff --git a/mozilla/security/nss/lib/ssl/sslsock.c b/mozilla/security/nss/lib/ssl/sslsock.c
index ca0d714..2898b88 100644
--- a/mozilla/security/nss/lib/ssl/sslsock.c
+++ b/mozilla/security/nss/lib/ssl/sslsock.c
@@ -738,6 +738,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
 	ss->opt.enableFalseStart = on;
 	break;
 
+      case SSL_ENABLE_SNAP_START:
+	ss->opt.enableSnapStart = on;
+	break;
+
       default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	rv = SECFailure;
@@ -802,6 +806,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
     case SSL_REQUIRE_SAFE_NEGOTIATION: 
                                   on = ss->opt.requireSafeNegotiation; break;
     case SSL_ENABLE_FALSE_START:  on = ss->opt.enableFalseStart;   break;
+    case SSL_ENABLE_SNAP_START:   on = ss->opt.enableSnapStart;    break;
 
     default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -853,6 +858,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
                                   on = ssl_defaults.requireSafeNegotiation; 
 				  break;
     case SSL_ENABLE_FALSE_START:  on = ssl_defaults.enableFalseStart;   break;
+    case SSL_ENABLE_SNAP_START:   on = ssl_defaults.enableSnapStart;   break;
 
     default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -1000,6 +1006,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
 	ssl_defaults.enableFalseStart = on;
 	break;
 
+      case SSL_ENABLE_SNAP_START:
+	ssl_defaults.enableSnapStart = on;
+	break;
+
       default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return SECFailure;
diff --git a/mozilla/security/nss/lib/ssl/sslt.h b/mozilla/security/nss/lib/ssl/sslt.h
index f6e0b62..68cbf87 100644
--- a/mozilla/security/nss/lib/ssl/sslt.h
+++ b/mozilla/security/nss/lib/ssl/sslt.h
@@ -204,9 +204,23 @@ typedef enum {
 #endif
     ssl_session_ticket_xtn           = 35,
     ssl_next_proto_neg_xtn           = 13172,
+    ssl_snap_start_xtn               = 13174,
     ssl_renegotiation_info_xtn       = 0xff01	/* experimental number */
 } SSLExtensionType;
 
-#define SSL_MAX_EXTENSIONS             6
+#define SSL_MAX_EXTENSIONS             7
+
+typedef enum {
+    /* No Snap Start handshake was attempted. */
+    SSL_SNAP_START_NONE = 0,
+    /* A Snap Start full handshake was completed. */
+    SSL_SNAP_START_FULL = 1,
+    /* A Snap Start full handshake was attempted, but failed. */
+    SSL_SNAP_START_RECOVERY = 2,
+    /* A Snap Start resume handshake was completed. */
+    SSL_SNAP_START_RESUME = 3,
+    /* A Snap Start resume handshake was attempted, but failed. */
+    SSL_SNAP_START_RESUME_RECOVERY = 4
+} SSLSnapStartResult;
 
 #endif /* __sslt_h_ */