| Index: net/third_party/nss/patches/snapstart.patch
|
| ===================================================================
|
| --- net/third_party/nss/patches/snapstart.patch (revision 88407)
|
| +++ net/third_party/nss/patches/snapstart.patch (working copy)
|
| @@ -1,2131 +0,0 @@
|
| -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_ */
|
|
|