blob: 33335f65100de060a1fb32519e2dd325cf27f08d [file] [log] [blame]
diff -puN -r a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
--- a/net/third_party/nss/ssl/ssl3con.c 2012-11-09 15:34:12.258133766 -0800
+++ b/net/third_party/nss/ssl/ssl3con.c 2012-11-09 15:35:08.488958561 -0800
@@ -2033,6 +2033,9 @@ ssl3_ClientAuthTokenPresent(sslSessionID
PRBool isPresent = PR_TRUE;
/* we only care if we are doing client auth */
+ /* If NSS_PLATFORM_CLIENT_AUTH is defined and a platformClientKey is being
+ * used, u.ssl3.clAuthValid will be false and this function will always
+ * return PR_TRUE. */
if (!sid || !sid->u.ssl3.clAuthValid) {
return PR_TRUE;
}
@@ -5226,24 +5229,33 @@ ssl3_SendCertificateVerify(sslSocket *ss
}
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
- rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS);
- if (rv == SECSuccess) {
- PK11SlotInfo * slot;
- sslSessionID * sid = ss->sec.ci.sid;
+ if (ss->ssl3.platformClientKey) {
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ rv = ssl3_PlatformSignHashes(&hashes, ss->ssl3.platformClientKey,
+ &buf, isTLS);
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+ } else {
+ rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS);
+ if (rv == SECSuccess) {
+ PK11SlotInfo * slot;
+ sslSessionID * sid = ss->sec.ci.sid;
- /* Remember the info about the slot that did the signing.
- ** Later, when doing an SSL restart handshake, verify this.
- ** These calls are mere accessors, and can't fail.
- */
- slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey);
- sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot);
- sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot);
- sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot);
- sid->u.ssl3.clAuthValid = PR_TRUE;
- PK11_FreeSlot(slot);
+ /* Remember the info about the slot that did the signing.
+ ** Later, when doing an SSL restart handshake, verify this.
+ ** These calls are mere accessors, and can't fail.
+ */
+ slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey);
+ sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot);
+ sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot);
+ sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot);
+ sid->u.ssl3.clAuthValid = PR_TRUE;
+ PK11_FreeSlot(slot);
+ }
+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+ ss->ssl3.clientPrivateKey = NULL;
}
- SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
- ss->ssl3.clientPrivateKey = NULL;
if (rv != SECSuccess) {
goto done; /* err code was set by ssl3_SignHashes */
}
@@ -5311,6 +5323,12 @@ ssl3_HandleServerHello(sslSocket *ss, SS
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
ss->ssl3.clientPrivateKey = NULL;
}
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (ss->ssl3.platformClientKey) {
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+ }
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
if (temp < 0) {
@@ -5901,6 +5919,10 @@ ssl3_HandleCertificateRequest(sslSocket
SSL3AlertDescription desc = illegal_parameter;
SECItem cert_types = {siBuffer, NULL, 0};
CERTDistNames ca_list;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ CERTCertList * platform_cert_list = NULL;
+ CERTCertListNode * certNode = NULL;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake",
SSL_GETPID(), ss->fd));
@@ -5917,6 +5939,7 @@ ssl3_HandleCertificateRequest(sslSocket
PORT_Assert(ss->ssl3.clientCertChain == NULL);
PORT_Assert(ss->ssl3.clientCertificate == NULL);
PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
+ PORT_Assert(ss->ssl3.platformClientKey == (PlatformKey)NULL);
isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length);
@@ -5983,6 +6006,18 @@ ssl3_HandleCertificateRequest(sslSocket
desc = no_certificate;
ss->ssl3.hs.ws = wait_hello_done;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (ss->getPlatformClientAuthData != NULL) {
+ /* XXX Should pass cert_types in this call!! */
+ rv = (SECStatus)(*ss->getPlatformClientAuthData)(
+ ss->getPlatformClientAuthDataArg,
+ ss->fd, &ca_list,
+ &platform_cert_list,
+ (void**)&ss->ssl3.platformClientKey,
+ &ss->ssl3.clientCertificate,
+ &ss->ssl3.clientPrivateKey);
+ } else
+#endif
if (ss->getClientAuthData == NULL) {
rv = SECFailure; /* force it to send a no_certificate alert */
} else {
@@ -5992,12 +6029,52 @@ ssl3_HandleCertificateRequest(sslSocket
&ss->ssl3.clientCertificate,
&ss->ssl3.clientPrivateKey);
}
+
switch (rv) {
case SECWouldBlock: /* getClientAuthData has put up a dialog box. */
ssl3_SetAlwaysBlock(ss);
break; /* not an error */
case SECSuccess:
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (!platform_cert_list || CERT_LIST_EMPTY(platform_cert_list) ||
+ !ss->ssl3.platformClientKey) {
+ if (platform_cert_list) {
+ CERT_DestroyCertList(platform_cert_list);
+ platform_cert_list = NULL;
+ }
+ if (ss->ssl3.platformClientKey) {
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+ }
+ /* Fall through to NSS client auth check */
+ } else {
+ certNode = CERT_LIST_HEAD(platform_cert_list);
+ ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert);
+
+ /* Setting ssl3.clientCertChain non-NULL will cause
+ * ssl3_HandleServerHelloDone to call SendCertificate.
+ * Note: clientCertChain should include the EE cert as
+ * clientCertificate is ignored during the actual sending
+ */
+ ss->ssl3.clientCertChain =
+ hack_NewCertificateListFromCertList(platform_cert_list);
+ CERT_DestroyCertList(platform_cert_list);
+ platform_cert_list = NULL;
+ if (ss->ssl3.clientCertChain == NULL) {
+ if (ss->ssl3.clientCertificate != NULL) {
+ CERT_DestroyCertificate(ss->ssl3.clientCertificate);
+ ss->ssl3.clientCertificate = NULL;
+ }
+ if (ss->ssl3.platformClientKey) {
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+ ss->ssl3.platformClientKey = (PlatformKey)NULL;
+ }
+ goto send_no_certificate;
+ }
+ break; /* not an error */
+ }
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
/* check what the callback function returned */
if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) {
/* we are missing either the key or cert */
@@ -6060,6 +6137,10 @@ loser:
done:
if (arena != NULL)
PORT_FreeArena(arena, PR_FALSE);
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (platform_cert_list)
+ CERT_DestroyCertList(platform_cert_list);
+#endif
return rv;
}
@@ -6134,7 +6215,8 @@ ssl3_SendClientSecondRound(sslSocket *ss
sendClientCert = !ss->ssl3.sendEmptyCert &&
ss->ssl3.clientCertChain != NULL &&
- ss->ssl3.clientPrivateKey != NULL;
+ (ss->ssl3.platformClientKey ||
+ ss->ssl3.clientPrivateKey != NULL);
/* We must wait for the server's certificate to be authenticated before
* sending the client certificate in order to disclosing the client
@@ -10446,6 +10528,10 @@ ssl3_DestroySSL3Info(sslSocket *ss)
if (ss->ssl3.clientPrivateKey != NULL)
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (ss->ssl3.platformClientKey)
+ ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
if (ss->ssl3.peerCertArena != NULL)
ssl3_CleanupPeerCerts(ss);
diff -puN -r a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c
--- a/net/third_party/nss/ssl/ssl3ext.c 2012-11-09 15:34:12.258133766 -0800
+++ b/net/third_party/nss/ssl/ssl3ext.c 2012-11-09 15:35:08.488958561 -0800
@@ -11,8 +11,8 @@
#include "nssrenam.h"
#include "nss.h"
#include "ssl.h"
-#include "sslproto.h"
#include "sslimpl.h"
+#include "sslproto.h"
#include "pk11pub.h"
#ifdef NO_PKCS11_BYPASS
#include "blapit.h"
diff -puN -r a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c
--- a/net/third_party/nss/ssl/sslauth.c 2012-11-09 15:27:15.952019947 -0800
+++ b/net/third_party/nss/ssl/sslauth.c 2012-11-09 15:35:08.488958561 -0800
@@ -219,6 +219,28 @@ SSL_GetClientAuthDataHook(PRFileDesc *s,
return SECSuccess;
}
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+/* NEED LOCKS IN HERE. */
+SECStatus
+SSL_GetPlatformClientAuthDataHook(PRFileDesc *s,
+ SSLGetPlatformClientAuthData func,
+ void *arg)
+{
+ sslSocket *ss;
+
+ ss = ssl_FindSocket(s);
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook",
+ SSL_GETPID(), s));
+ return SECFailure;
+ }
+
+ ss->getPlatformClientAuthData = func;
+ ss->getPlatformClientAuthDataArg = arg;
+ return SECSuccess;
+}
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+
/* NEED LOCKS IN HERE. */
SECStatus
SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
diff -puN -r a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
--- a/net/third_party/nss/ssl/ssl.h 2012-11-09 15:34:12.258133766 -0800
+++ b/net/third_party/nss/ssl/ssl.h 2012-11-09 15:35:08.488958561 -0800
@@ -483,6 +483,48 @@ typedef SECStatus (PR_CALLBACK *SSLGetCl
SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd,
SSLGetClientAuthData f, void *a);
+/*
+ * Prototype for SSL callback to get client auth data from the application,
+ * optionally using the underlying platform's cryptographic primitives.
+ * To use the platform cryptographic primitives, caNames and pRetCerts
+ * should be set. To use NSS, pRetNSSCert and pRetNSSKey should be set.
+ * Returning SECFailure will cause the socket to send no client certificate.
+ * arg - application passed argument
+ * caNames - pointer to distinguished names of CAs that the server likes
+ * pRetCerts - pointer to pointer to list of certs, with the first being
+ * the client cert, and any following being used for chain
+ * building
+ * pRetKey - pointer to native key pointer, for return of key
+ * - Windows: A pointer to a PCERT_KEY_CONTEXT that was allocated
+ * via PORT_Alloc(). Ownership of the PCERT_KEY_CONTEXT
+ * is transferred to NSS, which will free via
+ * PORT_Free().
+ * - Mac OS X: A pointer to a SecKeyRef. Ownership is
+ * transferred to NSS, which will free via CFRelease().
+ * pRetNSSCert - pointer to pointer to NSS cert, for return of cert.
+ * pRetNSSKey - pointer to NSS key pointer, for return of key.
+ */
+typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg,
+ PRFileDesc *fd,
+ CERTDistNames *caNames,
+ CERTCertList **pRetCerts,/*return */
+ void **pRetKey,/* return */
+ CERTCertificate **pRetNSSCert,/*return */
+ SECKEYPrivateKey **pRetNSSKey);/* return */
+
+/*
+ * Set the client side callback for SSL to retrieve user's private key
+ * and certificate.
+ * Note: If a platform client auth callback is set, the callback configured by
+ * SSL_GetClientAuthDataHook, if any, will not be called.
+ *
+ * fd - the file descriptor for the connection in question
+ * f - the application's callback that delivers the key and cert
+ * a - application specific data
+ */
+SSL_IMPORT SECStatus
+SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd,
+ SSLGetPlatformClientAuthData f, void *a);
/*
** SNI extension processing callback function.
diff -puN -r a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h
--- a/net/third_party/nss/ssl/sslimpl.h 2012-11-09 15:34:12.258133766 -0800
+++ b/net/third_party/nss/ssl/sslimpl.h 2012-11-09 15:36:42.600338478 -0800
@@ -32,6 +32,15 @@
#include "sslt.h" /* for some formerly private types, now public */
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+#if defined(XP_WIN32)
+#include <windows.h>
+#include <wincrypt.h>
+#elif defined(XP_MACOSX)
+#include <Security/Security.h>
+#endif
+#endif
+
/* to make some of these old enums public without namespace pollution,
** it was necessary to prepend ssl_ to the names.
** These #defines preserve compatibility with the old code here in libssl.
@@ -446,6 +455,14 @@ typedef SECStatus (*SSLCompressor)(void
int inlen);
typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
+#if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_WIN32)
+typedef PCERT_KEY_CONTEXT PlatformKey;
+#elif defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_MACOSX)
+typedef SecKeyRef PlatformKey;
+#else
+typedef void *PlatformKey;
+#endif
+
/*
@@ -870,6 +887,10 @@ struct ssl3StateStr {
CERTCertificate * clientCertificate; /* used by client */
SECKEYPrivateKey * clientPrivateKey; /* used by client */
+ /* platformClientKey is present even when NSS_PLATFORM_CLIENT_AUTH is not
+ * defined in order to allow cleaner conditional code.
+ * At most one of clientPrivateKey and platformClientKey may be set. */
+ PlatformKey platformClientKey; /* used by client */
CERTCertificateList *clientCertChain; /* used by client */
PRBool sendEmptyCert; /* used by client */
@@ -1127,6 +1148,10 @@ const unsigned char * preferredCipher;
void *authCertificateArg;
SSLGetClientAuthData getClientAuthData;
void *getClientAuthDataArg;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ SSLGetPlatformClientAuthData getPlatformClientAuthData;
+ void *getPlatformClientAuthDataArg;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
SSLSNISocketConfig sniSocketConfig;
void *sniSocketConfigArg;
SSLBadCertHandler handleBadCert;
@@ -1700,7 +1725,6 @@ extern void ssl_FreePRSocket(PRFileDesc
* various ciphers */
extern int ssl3_config_match_init(sslSocket *);
-
/* Create a new ref counted key pair object from two keys. */
extern ssl3KeyPair * ssl3_NewKeyPair( SECKEYPrivateKey * privKey,
SECKEYPublicKey * pubKey);
@@ -1740,6 +1764,26 @@ extern SECStatus ssl_InitSessionCacheLoc
extern SECStatus ssl_FreeSessionCacheLocks(void);
+/***************** platform client auth ****************/
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+// Releases the platform key.
+extern void ssl_FreePlatformKey(PlatformKey key);
+
+// Implement the client CertificateVerify message for SSL3/TLS1.0
+extern SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash,
+ PlatformKey key, SECItem *buf,
+ PRBool isTLS);
+
+// Converts a CERTCertList* (A collection of CERTCertificates) into a
+// CERTCertificateList* (A collection of SECItems), or returns NULL if
+// it cannot be converted.
+// This is to allow the platform-supplied chain to be created with purely
+// public API functions, using the preferred CERTCertList mutators, rather
+// pushing this hack to clients.
+extern CERTCertificateList* hack_NewCertificateListFromCertList(
+ CERTCertList* list);
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
/**************** DTLS-specific functions **************/
extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg);
diff -puN -r a/net/third_party/nss/ssl/sslplatf.c b/net/third_party/nss/ssl/sslplatf.c
--- a/net/third_party/nss/ssl/sslplatf.c 1969-12-31 16:00:00.000000000 -0800
+++ b/net/third_party/nss/ssl/sslplatf.c 2012-11-09 15:35:08.498958708 -0800
@@ -0,0 +1,399 @@
+/*
+ * Platform specific crypto wrappers
+ *
+ * ***** 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):
+ * Ryan Sleevi <ryan.sleevi@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* $Id$ */
+#include "ssl.h"
+#include "certt.h"
+#include "keythi.h"
+#include "sslimpl.h"
+#include "cryptohi.h"
+#include "secitem.h"
+
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+CERTCertificateList*
+hack_NewCertificateListFromCertList(CERTCertList* list)
+{
+ CERTCertificateList * chain = NULL;
+ PRArenaPool * arena = NULL;
+ CERTCertListNode * node;
+ int len;
+
+ if (CERT_LIST_EMPTY(list))
+ goto loser;
+
+ arena = PORT_NewArena(4096);
+ if (arena == NULL)
+ goto loser;
+
+ for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
+ len++, node = CERT_LIST_NEXT(node)) {
+ }
+
+ chain = PORT_ArenaNew(arena, CERTCertificateList);
+ if (chain == NULL)
+ goto loser;
+
+ chain->certs = PORT_ArenaNewArray(arena, SECItem, len);
+ if (!chain->certs)
+ goto loser;
+ chain->len = len;
+
+ for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
+ len++, node = CERT_LIST_NEXT(node)) {
+ // Check to see if the last cert to be sent is a self-signed cert,
+ // and if so, omit it from the list of certificates. However, if
+ // there is only one cert (len == 0), include the cert, as it means
+ // the EE cert is self-signed.
+ if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) {
+ chain->len = len;
+ break;
+ }
+ SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert);
+ }
+
+ chain->arena = arena;
+ return chain;
+
+loser:
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ return NULL;
+}
+
+#if defined(XP_WIN32)
+void
+ssl_FreePlatformKey(PlatformKey key)
+{
+ if (key) {
+ if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC)
+ CryptReleaseContext(key->hCryptProv, 0);
+ /* FIXME(rsleevi): Close CNG keys. */
+ PORT_Free(key);
+ }
+}
+
+SECStatus
+ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS)
+{
+ SECStatus rv = SECFailure;
+ PRBool doDerEncode = PR_FALSE;
+ SECItem hashItem;
+ HCRYPTKEY hKey = 0;
+ DWORD argLen = 0;
+ ALG_ID keyAlg = 0;
+ DWORD signatureLen = 0;
+ ALG_ID hashAlg = 0;
+ HCRYPTHASH hHash = 0;
+ DWORD hashLen = 0;
+ unsigned int i = 0;
+
+ buf->data = NULL;
+ if (!CryptGetUserKey(key->hCryptProv, key->dwKeySpec, &hKey)) {
+ if (GetLastError() == NTE_NO_KEY) {
+ PORT_SetError(SEC_ERROR_NO_KEY);
+ } else {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ }
+ goto done;
+ }
+
+ argLen = sizeof(keyAlg);
+ if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)&keyAlg, &argLen, 0)) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+
+ switch (keyAlg) {
+ case CALG_RSA_KEYX:
+ case CALG_RSA_SIGN:
+ hashAlg = CALG_SSL3_SHAMD5;
+ hashItem.data = hash->md5;
+ hashItem.len = sizeof(SSL3Hashes);
+ break;
+ case CALG_DSS_SIGN:
+ case CALG_ECDSA:
+ if (keyAlg == CALG_ECDSA) {
+ doDerEncode = PR_TRUE;
+ } else {
+ doDerEncode = isTLS;
+ }
+ hashAlg = CALG_SHA1;
+ hashItem.data = hash->sha;
+ hashItem.len = sizeof(hash->sha);
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+ PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
+
+ if (!CryptCreateHash(key->hCryptProv, hashAlg, 0, 0, &hHash)) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ argLen = sizeof(hashLen);
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ if (hashLen != hashItem.len) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
+ NULL, &signatureLen) || signatureLen == 0) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ buf->data = (unsigned char *)PORT_Alloc(signatureLen);
+ if (!buf->data)
+ goto done; /* error code was set. */
+
+ if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
+ (BYTE*)buf->data, &signatureLen)) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ buf->len = signatureLen;
+
+ /* CryptoAPI signs in little-endian, so reverse */
+ for (i = 0; i < buf->len / 2; ++i) {
+ unsigned char tmp = buf->data[i];
+ buf->data[i] = buf->data[buf->len - 1 - i];
+ buf->data[buf->len - 1 - i] = tmp;
+ }
+ if (doDerEncode) {
+ SECItem derSig = {siBuffer, NULL, 0};
+
+ /* This also works for an ECDSA signature */
+ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
+ if (rv == SECSuccess) {
+ PORT_Free(buf->data); /* discard unencoded signature. */
+ *buf = derSig; /* give caller encoded signature. */
+ } else if (derSig.data) {
+ PORT_Free(derSig.data);
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+ PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
+done:
+ if (hHash)
+ CryptDestroyHash(hHash);
+ if (hKey)
+ CryptDestroyKey(hKey);
+ if (rv != SECSuccess && buf->data) {
+ PORT_Free(buf->data);
+ buf->data = NULL;
+ }
+ return rv;
+}
+
+#elif defined(XP_MACOSX)
+#include <Security/cssm.h>
+
+void
+ssl_FreePlatformKey(PlatformKey key)
+{
+ CFRelease(key);
+}
+
+SECStatus
+ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS)
+{
+ SECStatus rv = SECFailure;
+ PRBool doDerEncode = PR_FALSE;
+ unsigned int signatureLen;
+ OSStatus status = noErr;
+ CSSM_CSP_HANDLE cspHandle = 0;
+ const CSSM_KEY *cssmKey = NULL;
+ CSSM_ALGORITHMS sigAlg;
+ const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL;
+ CSSM_RETURN cssmRv;
+ CSSM_DATA hashData;
+ CSSM_DATA signatureData;
+ CSSM_CC_HANDLE cssmSignature = 0;
+
+ buf->data = NULL;
+
+ status = SecKeyGetCSPHandle(key, &cspHandle);
+ if (status != noErr) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+
+ status = SecKeyGetCSSMKey(key, &cssmKey);
+ if (status != noErr || !cssmKey) {
+ PORT_SetError(SEC_ERROR_NO_KEY);
+ goto done;
+ }
+
+ /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the
+ * needed information is readily available on the key itself.
+ */
+ signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8;
+
+ if (signatureLen == 0) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+
+ buf->data = (unsigned char *)PORT_Alloc(signatureLen);
+ if (!buf->data)
+ goto done; /* error code was set. */
+
+ sigAlg = cssmKey->KeyHeader.AlgorithmId;
+ switch (sigAlg) {
+ case CSSM_ALGID_RSA:
+ hashData.Data = hash->md5;
+ hashData.Length = sizeof(SSL3Hashes);
+ break;
+ case CSSM_ALGID_ECDSA:
+ case CSSM_ALGID_DSA:
+ if (sigAlg == CSSM_ALGID_ECDSA) {
+ doDerEncode = PR_TRUE;
+ } else {
+ doDerEncode = isTLS;
+ }
+ hashData.Data = hash->sha;
+ hashData.Length = sizeof(hash->sha);
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+ PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length));
+
+ /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least,
+ * you can prevent the UI by setting the provider handle on the
+ * certificate to be opened with CRYPT_SILENT, but is there an equivalent?
+ */
+ status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN,
+ kSecCredentialTypeDefault, &cssmCreds);
+ if (status != noErr) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+
+ signatureData.Length = signatureLen;
+ signatureData.Data = (uint8*)buf->data;
+
+ cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds,
+ cssmKey, &cssmSignature);
+ if (cssmRv) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+
+ /* See "Apple Cryptographic Service Provider Functional Specification" */
+ if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
+ /* To set RSA blinding for RSA keys */
+ CSSM_CONTEXT_ATTRIBUTE blindingAttr;
+ blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
+ blindingAttr.AttributeLength = sizeof(uint32);
+ blindingAttr.Attribute.Uint32 = 1;
+ cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr);
+ if (cssmRv) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ }
+
+ cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, CSSM_ALGID_NONE,
+ &signatureData);
+ if (cssmRv) {
+ PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
+ goto done;
+ }
+ buf->len = signatureData.Length;
+
+ if (doDerEncode) {
+ SECItem derSig = {siBuffer, NULL, 0};
+
+ /* This also works for an ECDSA signature */
+ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
+ if (rv == SECSuccess) {
+ PORT_Free(buf->data); /* discard unencoded signature. */
+ *buf = derSig; /* give caller encoded signature. */
+ } else if (derSig.data) {
+ PORT_Free(derSig.data);
+ }
+ } else {
+ rv = SECSuccess;
+ }
+
+ PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
+done:
+ /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
+ * should not be freed. When the PlatformKey is freed, they will be
+ * released.
+ */
+ if (cssmSignature)
+ CSSM_DeleteContext(cssmSignature);
+
+ if (rv != SECSuccess && buf->data) {
+ PORT_Free(buf->data);
+ buf->data = NULL;
+ }
+ return rv;
+}
+#else
+void
+ssl_FreePlatformKey(PlatformKey key)
+{
+}
+
+SECStatus
+ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
+ PRBool isTLS)
+{
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+#endif
+
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
diff -puN -r a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c
--- a/net/third_party/nss/ssl/sslsock.c 2012-11-09 15:34:12.268133912 -0800
+++ b/net/third_party/nss/ssl/sslsock.c 2012-11-09 15:35:08.498958708 -0800
@@ -335,6 +335,10 @@ ssl_DupSocket(sslSocket *os)
ss->authCertificateArg = os->authCertificateArg;
ss->getClientAuthData = os->getClientAuthData;
ss->getClientAuthDataArg = os->getClientAuthDataArg;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ ss->getPlatformClientAuthData = os->getPlatformClientAuthData;
+ ss->getPlatformClientAuthDataArg = os->getPlatformClientAuthDataArg;
+#endif
ss->sniSocketConfig = os->sniSocketConfig;
ss->sniSocketConfigArg = os->sniSocketConfigArg;
ss->handleBadCert = os->handleBadCert;
@@ -1712,6 +1716,12 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile
ss->getClientAuthData = sm->getClientAuthData;
if (sm->getClientAuthDataArg)
ss->getClientAuthDataArg = sm->getClientAuthDataArg;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ if (sm->getPlatformClientAuthData)
+ ss->getPlatformClientAuthData = sm->getPlatformClientAuthData;
+ if (sm->getPlatformClientAuthDataArg)
+ ss->getPlatformClientAuthDataArg = sm->getPlatformClientAuthDataArg;
+#endif
if (sm->sniSocketConfig)
ss->sniSocketConfig = sm->sniSocketConfig;
if (sm->sniSocketConfigArg)
@@ -2942,6 +2952,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProto
ss->sniSocketConfig = NULL;
ss->sniSocketConfigArg = NULL;
ss->getClientAuthData = NULL;
+#ifdef NSS_PLATFORM_CLIENT_AUTH
+ ss->getPlatformClientAuthData = NULL;
+ ss->getPlatformClientAuthDataArg = NULL;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
ss->handleBadCert = NULL;
ss->badCertArg = NULL;
ss->pkcs11PinArg = NULL;