From f95f89147dbc66f2b3c54f6e8179c9400607338c Mon Sep 17 00:00:00 2001 From: "agl@chromium.org" Date: Fri, 22 Jul 2011 15:41:45 +0000 Subject: net: add NSS support for RFC 5705 (Keying Material Exporters for TLS). This is a reworked version of the patch from https://bugzilla.mozilla.org/show_bug.cgi?id=507359. BUG=none TEST=none yet Review URL: http://codereview.chromium.org/7464031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93635 0039d316-1c4b-4281-b951-d872f2087c98 --- net/third_party/nss/ssl/ssl.h | 11 +++++++ net/third_party/nss/ssl/ssl3con.c | 60 +++++++++++++++++++++++-------------- net/third_party/nss/ssl/sslimpl.h | 6 ++++ net/third_party/nss/ssl/sslinfo.c | 63 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 22 deletions(-) (limited to 'net/third_party/nss/ssl') diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h index 53ca301..1537aae 100644 --- a/net/third_party/nss/ssl/ssl.h +++ b/net/third_party/nss/ssl/ssl.h @@ -686,6 +686,17 @@ SSL_IMPORT SECStatus SSL_GetCipherSuiteInfo(PRUint16 cipherSuite, /* Returnes negotiated through SNI host info. */ SSL_IMPORT SECItem *SSL_GetNegotiatedHostInfo(PRFileDesc *fd); +/* Export keying material according to RFC 5705. +** fd must correspond to a TLS 1.0 or higher socket and out must +** already be allocated. +*/ +SSL_IMPORT SECStatus SSL_ExportKeyingMaterial(PRFileDesc *fd, + const char *label, + const unsigned char *context, + unsigned int contextlen, + unsigned char *out, + unsigned int outlen); + /* ** Return a new reference to the certificate that was most recently sent ** to the peer on this SSL/TLS connection, or NULL if none has been sent. diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index c39b8f8..dee5555 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -8442,18 +8442,17 @@ ssl3_RestartHandshakeAfterServerCert(sslSocket *ss) return rv; } -static SECStatus -ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, - PRBool isServer, - const SSL3Finished * hashes, - TLSFinished * tlsFinished) +/* The calling function must acquire and release the appropriate lock (i.e., + * ssl_GetSpecReadLock / ssl_ReleaseSpecReadLock for ss->ssl3.crSpec). Any + * label must already be concatenated onto the beginning of val. + */ +SECStatus +ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label, + unsigned int labelLen, const unsigned char *val, unsigned int valLen, + unsigned char *out, unsigned int outLen) { - const char * label; - unsigned int len; - SECStatus rv; - - label = isServer ? "server finished" : "client finished"; - len = 15; + SECStatus rv = SECSuccess; + unsigned int retLen; if (spec->master_secret && !spec->bypassCiphers) { SECItem param = {siBuffer, NULL, 0}; @@ -8464,11 +8463,11 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, return SECFailure; rv = PK11_DigestBegin(prf_context); - rv |= PK11_DigestOp(prf_context, (const unsigned char *) label, len); - rv |= PK11_DigestOp(prf_context, hashes->md5, sizeof *hashes); - rv |= PK11_DigestFinal(prf_context, tlsFinished->verify_data, - &len, sizeof tlsFinished->verify_data); - PORT_Assert(rv != SECSuccess || len == sizeof *tlsFinished); + rv |= PK11_DigestOp(prf_context, (unsigned char *) label, labelLen); + rv |= PK11_DigestOp(prf_context, val, valLen); + rv |= PK11_DigestFinal(prf_context, out, + &retLen, outLen); + PORT_Assert(rv != SECSuccess || retLen == outLen); PK11_DestroyContext(prf_context, PR_TRUE); } else { @@ -8477,17 +8476,34 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, SECItem outData = { siBuffer, }; PRBool isFIPS = PR_FALSE; - inData.data = (unsigned char *)hashes->md5; - inData.len = sizeof hashes[0]; - outData.data = tlsFinished->verify_data; - outData.len = sizeof tlsFinished->verify_data; + inData.data = (unsigned char *) val; + inData.len = valLen; + outData.data = out; + outData.len = outLen; rv = TLS_PRF(&spec->msItem, label, &inData, &outData, isFIPS); - PORT_Assert(rv != SECSuccess || \ - outData.len == sizeof tlsFinished->verify_data); + PORT_Assert(rv != SECSuccess || outData.len == outLen); } return rv; } +static SECStatus +ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, + PRBool isServer, + const SSL3Finished * hashes, + TLSFinished * tlsFinished) +{ + const char * label; + SECStatus rv; + + label = isServer ? "server finished" : "client finished"; + + rv = ssl3_TLSPRFWithMasterSecret(spec, label, 15, hashes->md5, + sizeof *hashes, tlsFinished->verify_data, + sizeof tlsFinished->verify_data); + + return rv; +} + /* called from ssl3_HandleServerHelloDone */ static SECStatus diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index df30029..073616f 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -1726,6 +1726,12 @@ SECStatus SSL_DisableDefaultExportCipherSuites(void); SECStatus SSL_DisableExportCipherSuites(PRFileDesc * fd); PRBool SSL_IsExportCipherSuite(PRUint16 cipherSuite); +SECStatus ssl3_TLSPRFWithMasterSecret( + ssl3CipherSpec *spec, const char *label, + unsigned int labelLen, const unsigned char *val, + unsigned int valLen, unsigned char *out, + unsigned int outLen); + /********************** FNV hash *********************/ void FNV1A64_Init(PRUint64 *digest); diff --git a/net/third_party/nss/ssl/sslinfo.c b/net/third_party/nss/ssl/sslinfo.c index 96377b0..9a58b4d 100644 --- a/net/third_party/nss/ssl/sslinfo.c +++ b/net/third_party/nss/ssl/sslinfo.c @@ -20,6 +20,7 @@ * * Contributor(s): * Dr Vipul Gupta , Sun Microsystems Laboratories + * Douglas Stebila * * 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 @@ -38,6 +39,7 @@ #include "ssl.h" #include "sslimpl.h" #include "sslproto.h" +#include "pk11func.h" static const char * ssl_GetCompressionMethodName(SSLCompressionMethod compression) @@ -316,6 +318,67 @@ SSL_IsExportCipherSuite(PRUint16 cipherSuite) return PR_FALSE; } +/* Export keying material according to draft-ietf-tls-extractor-06. +** fd must correspond to a TLS 1.0 or higher socket, out must +** be already allocated. +*/ +SECStatus +SSL_ExportKeyingMaterial(PRFileDesc *fd, const char *label, + const unsigned char *context, + unsigned int contextLen, + unsigned char *out, + unsigned int outLen) +{ + sslSocket *ss; + unsigned char *val = NULL; + unsigned int valLen, i; + SECStatus rv = SECFailure; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in ExportKeyingMaterial", + SSL_GETPID(), fd)); + return SECFailure; + } + + if (ss->version < SSL_LIBRARY_VERSION_3_1_TLS) { + PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION); + return SECFailure; + } + + if (ss->ssl3.hs.ws != idle_handshake) { + PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); + return SECFailure; + } + + valLen = SSL3_RANDOM_LENGTH * 2; + if (contextLen > 0) + valLen += 2 /* uint16 length */ + contextLen; + val = PORT_Alloc(valLen); + if (val == NULL) + return SECFailure; + i = 0; + PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); + i += SSL3_RANDOM_LENGTH; + PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH); + i += SSL3_RANDOM_LENGTH; + if (contextLen > 0) { + val[i++] = contextLen >> 8; + val[i++] = contextLen; + PORT_Memcpy(val + i, context, contextLen); + i += contextLen; + } + PORT_Assert(i == valLen); + + ssl_GetSpecReadLock(ss); + rv = ssl3_TLSPRFWithMasterSecret(ss->ssl3.crSpec, label, strlen(label), val, valLen, out, outLen); + ssl_ReleaseSpecReadLock(ss); + + if (val != NULL) + PORT_ZFree(val, valLen); + return rv; +} + SECItem* SSL_GetNegotiatedHostInfo(PRFileDesc *fd) { -- cgit v1.1