diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c
--- a/nss/lib/ssl/ssl3con.c	2014-01-17 17:52:00.295082288 -0800
+++ b/nss/lib/ssl/ssl3con.c	2014-01-17 17:52:19.745405758 -0800
@@ -2471,6 +2471,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;
     }
@@ -6103,25 +6106,36 @@ ssl3_SendCertificateVerify(sslSocket *ss
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
-    keyType = ss->ssl3.clientPrivateKey->keyType;
-    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
+	keyType = CERT_GetCertKeyType(
+	    &ss->ssl3.clientCertificate->subjectPublicKeyInfo);
+	rv = ssl3_PlatformSignHashes(
+	    &hashes, ss->ssl3.platformClientKey, &buf, isTLS, keyType);
+	ssl_FreePlatformKey(ss->ssl3.platformClientKey);
+	ss->ssl3.platformClientKey = (PlatformKey)NULL;
+#endif /* NSS_PLATFORM_CLIENT_AUTH */
+    } else {
+	keyType = ss->ssl3.clientPrivateKey->keyType;
+	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 */
     }
@@ -6200,6 +6214,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) {
@@ -6827,6 +6847,18 @@ ssl3_ExtractClientKeyInfo(sslSocket *ss,
 	goto done;
     }
 
+#if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(_WIN32)
+    /* If the key is in CAPI, assume conservatively that the CAPI service
+     * provider may be unable to sign SHA-256 hashes.
+     */
+    if (ss->ssl3.platformClientKey->dwKeySpec != CERT_NCRYPT_KEY_SPEC) {
+	/* CAPI only supports RSA and DSA signatures, so we don't need to
+	 * check the key type. */
+	*preferSha1 = PR_TRUE;
+	goto done;
+    }
+#endif  /* NSS_PLATFORM_CLIENT_AUTH && _WIN32 */
+
     /* If the key is a 1024-bit RSA or DSA key, assume conservatively that
      * it may be unable to sign SHA-256 hashes. This is the case for older
      * Estonian ID cards that have 1024-bit RSA keys. In FIPS 186-2 and
@@ -6925,6 +6957,10 @@ ssl3_HandleCertificateRequest(sslSocket
     SECItem              cert_types  = {siBuffer, NULL, 0};
     SECItem              algorithms  = {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));
@@ -6941,6 +6977,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);
     isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
@@ -7020,6 +7057,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 and algorithms 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) {
 	/* XXX Should pass cert_types and algorithms in this call!! */
 	rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg,
@@ -7029,12 +7078,55 @@ ssl3_HandleCertificateRequest(sslSocket
     } else {
 	rv = SECFailure; /* force it to send a no_certificate alert */
     }
+
     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;
+	    }
+	    if (ss->ssl3.hs.hashType == handshake_hash_single) {
+		ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, &algorithms);
+	    }
+	    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 */
@@ -7096,6 +7188,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;
 }
 
@@ -7213,7 +7309,8 @@ ssl3_SendClientSecondRound(sslSocket *ss
 
     sendClientCert = !ss->ssl3.sendEmptyCert &&
 		     ss->ssl3.clientCertChain  != NULL &&
-		     ss->ssl3.clientPrivateKey != NULL;
+		     (ss->ssl3.platformClientKey ||
+		     ss->ssl3.clientPrivateKey != NULL);
 
     if (!sendClientCert &&
 	ss->ssl3.hs.hashType == handshake_hash_single &&
@@ -12052,6 +12149,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 -pu a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c
--- a/nss/lib/ssl/ssl3ext.c	2014-01-17 17:49:26.072517368 -0800
+++ b/nss/lib/ssl/ssl3ext.c	2014-01-17 17:52:19.745405758 -0800
@@ -10,8 +10,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 -pu a/nss/lib/ssl/sslauth.c b/nss/lib/ssl/sslauth.c
--- a/nss/lib/ssl/sslauth.c	2014-01-17 17:49:26.072517368 -0800
+++ b/nss/lib/ssl/sslauth.c	2014-01-17 17:52:19.755405924 -0800
@@ -216,6 +216,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 -pu a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h
--- a/nss/lib/ssl/ssl.h	2014-01-17 17:49:26.062517203 -0800
+++ b/nss/lib/ssl/ssl.h	2014-01-17 17:52:19.755405924 -0800
@@ -533,6 +533,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 -pu a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h
--- a/nss/lib/ssl/sslimpl.h	2014-01-17 17:52:00.295082288 -0800
+++ b/nss/lib/ssl/sslimpl.h	2014-01-17 17:52:19.755405924 -0800
@@ -20,6 +20,7 @@
 #include "sslerr.h"
 #include "ssl3prot.h"
 #include "hasht.h"
+#include "keythi.h"
 #include "nssilock.h"
 #include "pkcs11t.h"
 #if defined(XP_UNIX) || defined(XP_BEOS)
@@ -31,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.
@@ -441,6 +451,14 @@ struct sslGatherStr {
 #define GS_DATA		3
 #define GS_PAD		4
 
+#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
+
 
 
 /*
@@ -953,6 +971,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 */
 
@@ -1214,6 +1236,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;
@@ -1852,6 +1878,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, KeyType keyType);
+
+// 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 -pu a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c
--- a/nss/lib/ssl/sslsock.c	2014-01-17 17:49:40.942764689 -0800
+++ b/nss/lib/ssl/sslsock.c	2014-01-17 17:52:19.755405924 -0800
@@ -263,6 +263,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;
@@ -1667,6 +1671,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)
@@ -2921,6 +2931,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;