1diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c 2--- a/nss/lib/ssl/ssl3con.c 2014-01-17 17:52:00.295082288 -0800 3+++ b/nss/lib/ssl/ssl3con.c 2014-01-17 17:52:19.745405758 -0800 4@@ -2471,6 +2471,9 @@ ssl3_ClientAuthTokenPresent(sslSessionID 5 PRBool isPresent = PR_TRUE; 6 7 /* we only care if we are doing client auth */ 8+ /* If NSS_PLATFORM_CLIENT_AUTH is defined and a platformClientKey is being 9+ * used, u.ssl3.clAuthValid will be false and this function will always 10+ * return PR_TRUE. */ 11 if (!sid || !sid->u.ssl3.clAuthValid) { 12 return PR_TRUE; 13 } 14@@ -6103,25 +6106,36 @@ ssl3_SendCertificateVerify(sslSocket *ss 15 16 isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); 17 isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); 18- keyType = ss->ssl3.clientPrivateKey->keyType; 19- rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); 20- if (rv == SECSuccess) { 21- PK11SlotInfo * slot; 22- sslSessionID * sid = ss->sec.ci.sid; 23+ if (ss->ssl3.platformClientKey) { 24+#ifdef NSS_PLATFORM_CLIENT_AUTH 25+ keyType = CERT_GetCertKeyType( 26+ &ss->ssl3.clientCertificate->subjectPublicKeyInfo); 27+ rv = ssl3_PlatformSignHashes( 28+ &hashes, ss->ssl3.platformClientKey, &buf, isTLS, keyType); 29+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 30+ ss->ssl3.platformClientKey = (PlatformKey)NULL; 31+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 32+ } else { 33+ keyType = ss->ssl3.clientPrivateKey->keyType; 34+ rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); 35+ if (rv == SECSuccess) { 36+ PK11SlotInfo * slot; 37+ sslSessionID * sid = ss->sec.ci.sid; 38 39- /* Remember the info about the slot that did the signing. 40- ** Later, when doing an SSL restart handshake, verify this. 41- ** These calls are mere accessors, and can't fail. 42- */ 43- slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey); 44- sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot); 45- sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot); 46- sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot); 47- sid->u.ssl3.clAuthValid = PR_TRUE; 48- PK11_FreeSlot(slot); 49+ /* Remember the info about the slot that did the signing. 50+ ** Later, when doing an SSL restart handshake, verify this. 51+ ** These calls are mere accessors, and can't fail. 52+ */ 53+ slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey); 54+ sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot); 55+ sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot); 56+ sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot); 57+ sid->u.ssl3.clAuthValid = PR_TRUE; 58+ PK11_FreeSlot(slot); 59+ } 60+ SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); 61+ ss->ssl3.clientPrivateKey = NULL; 62 } 63- SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); 64- ss->ssl3.clientPrivateKey = NULL; 65 if (rv != SECSuccess) { 66 goto done; /* err code was set by ssl3_SignHashes */ 67 } 68@@ -6200,6 +6214,12 @@ ssl3_HandleServerHello(sslSocket *ss, SS 69 SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); 70 ss->ssl3.clientPrivateKey = NULL; 71 } 72+#ifdef NSS_PLATFORM_CLIENT_AUTH 73+ if (ss->ssl3.platformClientKey) { 74+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 75+ ss->ssl3.platformClientKey = (PlatformKey)NULL; 76+ } 77+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 78 79 temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); 80 if (temp < 0) { 81@@ -6827,6 +6847,18 @@ ssl3_ExtractClientKeyInfo(sslSocket *ss, 82 goto done; 83 } 84 85+#if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(_WIN32) 86+ /* If the key is in CAPI, assume conservatively that the CAPI service 87+ * provider may be unable to sign SHA-256 hashes. 88+ */ 89+ if (ss->ssl3.platformClientKey->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { 90+ /* CAPI only supports RSA and DSA signatures, so we don't need to 91+ * check the key type. */ 92+ *preferSha1 = PR_TRUE; 93+ goto done; 94+ } 95+#endif /* NSS_PLATFORM_CLIENT_AUTH && _WIN32 */ 96+ 97 /* If the key is a 1024-bit RSA or DSA key, assume conservatively that 98 * it may be unable to sign SHA-256 hashes. This is the case for older 99 * Estonian ID cards that have 1024-bit RSA keys. In FIPS 186-2 and 100@@ -6925,6 +6957,10 @@ ssl3_HandleCertificateRequest(sslSocket 101 SECItem cert_types = {siBuffer, NULL, 0}; 102 SECItem algorithms = {siBuffer, NULL, 0}; 103 CERTDistNames ca_list; 104+#ifdef NSS_PLATFORM_CLIENT_AUTH 105+ CERTCertList * platform_cert_list = NULL; 106+ CERTCertListNode * certNode = NULL; 107+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 108 109 SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake", 110 SSL_GETPID(), ss->fd)); 111@@ -6941,6 +6977,7 @@ ssl3_HandleCertificateRequest(sslSocket 112 PORT_Assert(ss->ssl3.clientCertChain == NULL); 113 PORT_Assert(ss->ssl3.clientCertificate == NULL); 114 PORT_Assert(ss->ssl3.clientPrivateKey == NULL); 115+ PORT_Assert(ss->ssl3.platformClientKey == (PlatformKey)NULL); 116 117 isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); 118 isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); 119@@ -7020,6 +7057,18 @@ ssl3_HandleCertificateRequest(sslSocket 120 desc = no_certificate; 121 ss->ssl3.hs.ws = wait_hello_done; 122 123+#ifdef NSS_PLATFORM_CLIENT_AUTH 124+ if (ss->getPlatformClientAuthData != NULL) { 125+ /* XXX Should pass cert_types and algorithms in this call!! */ 126+ rv = (SECStatus)(*ss->getPlatformClientAuthData)( 127+ ss->getPlatformClientAuthDataArg, 128+ ss->fd, &ca_list, 129+ &platform_cert_list, 130+ (void**)&ss->ssl3.platformClientKey, 131+ &ss->ssl3.clientCertificate, 132+ &ss->ssl3.clientPrivateKey); 133+ } else 134+#endif 135 if (ss->getClientAuthData != NULL) { 136 /* XXX Should pass cert_types and algorithms in this call!! */ 137 rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg, 138@@ -7029,12 +7078,55 @@ ssl3_HandleCertificateRequest(sslSocket 139 } else { 140 rv = SECFailure; /* force it to send a no_certificate alert */ 141 } 142+ 143 switch (rv) { 144 case SECWouldBlock: /* getClientAuthData has put up a dialog box. */ 145 ssl3_SetAlwaysBlock(ss); 146 break; /* not an error */ 147 148 case SECSuccess: 149+#ifdef NSS_PLATFORM_CLIENT_AUTH 150+ if (!platform_cert_list || CERT_LIST_EMPTY(platform_cert_list) || 151+ !ss->ssl3.platformClientKey) { 152+ if (platform_cert_list) { 153+ CERT_DestroyCertList(platform_cert_list); 154+ platform_cert_list = NULL; 155+ } 156+ if (ss->ssl3.platformClientKey) { 157+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 158+ ss->ssl3.platformClientKey = (PlatformKey)NULL; 159+ } 160+ /* Fall through to NSS client auth check */ 161+ } else { 162+ certNode = CERT_LIST_HEAD(platform_cert_list); 163+ ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert); 164+ 165+ /* Setting ssl3.clientCertChain non-NULL will cause 166+ * ssl3_HandleServerHelloDone to call SendCertificate. 167+ * Note: clientCertChain should include the EE cert as 168+ * clientCertificate is ignored during the actual sending 169+ */ 170+ ss->ssl3.clientCertChain = 171+ hack_NewCertificateListFromCertList(platform_cert_list); 172+ CERT_DestroyCertList(platform_cert_list); 173+ platform_cert_list = NULL; 174+ if (ss->ssl3.clientCertChain == NULL) { 175+ if (ss->ssl3.clientCertificate != NULL) { 176+ CERT_DestroyCertificate(ss->ssl3.clientCertificate); 177+ ss->ssl3.clientCertificate = NULL; 178+ } 179+ if (ss->ssl3.platformClientKey) { 180+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 181+ ss->ssl3.platformClientKey = (PlatformKey)NULL; 182+ } 183+ goto send_no_certificate; 184+ } 185+ if (ss->ssl3.hs.hashType == handshake_hash_single) { 186+ ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, &algorithms); 187+ } 188+ break; /* not an error */ 189+ } 190+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 191 /* check what the callback function returned */ 192 if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) { 193 /* we are missing either the key or cert */ 194@@ -7096,6 +7188,10 @@ loser: 195 done: 196 if (arena != NULL) 197 PORT_FreeArena(arena, PR_FALSE); 198+#ifdef NSS_PLATFORM_CLIENT_AUTH 199+ if (platform_cert_list) 200+ CERT_DestroyCertList(platform_cert_list); 201+#endif 202 return rv; 203 } 204 205@@ -7213,7 +7309,8 @@ ssl3_SendClientSecondRound(sslSocket *ss 206 207 sendClientCert = !ss->ssl3.sendEmptyCert && 208 ss->ssl3.clientCertChain != NULL && 209- ss->ssl3.clientPrivateKey != NULL; 210+ (ss->ssl3.platformClientKey || 211+ ss->ssl3.clientPrivateKey != NULL); 212 213 if (!sendClientCert && 214 ss->ssl3.hs.hashType == handshake_hash_single && 215@@ -12052,6 +12149,10 @@ ssl3_DestroySSL3Info(sslSocket *ss) 216 217 if (ss->ssl3.clientPrivateKey != NULL) 218 SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); 219+#ifdef NSS_PLATFORM_CLIENT_AUTH 220+ if (ss->ssl3.platformClientKey) 221+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 222+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 223 224 if (ss->ssl3.peerCertArena != NULL) 225 ssl3_CleanupPeerCerts(ss); 226diff -pu a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c 227--- a/nss/lib/ssl/ssl3ext.c 2014-01-17 17:49:26.072517368 -0800 228+++ b/nss/lib/ssl/ssl3ext.c 2014-01-17 17:52:19.745405758 -0800 229@@ -10,8 +10,8 @@ 230 #include "nssrenam.h" 231 #include "nss.h" 232 #include "ssl.h" 233-#include "sslproto.h" 234 #include "sslimpl.h" 235+#include "sslproto.h" 236 #include "pk11pub.h" 237 #ifdef NO_PKCS11_BYPASS 238 #include "blapit.h" 239diff -pu a/nss/lib/ssl/sslauth.c b/nss/lib/ssl/sslauth.c 240--- a/nss/lib/ssl/sslauth.c 2014-01-17 17:49:26.072517368 -0800 241+++ b/nss/lib/ssl/sslauth.c 2014-01-17 17:52:19.755405924 -0800 242@@ -216,6 +216,28 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, 243 return SECSuccess; 244 } 245 246+#ifdef NSS_PLATFORM_CLIENT_AUTH 247+/* NEED LOCKS IN HERE. */ 248+SECStatus 249+SSL_GetPlatformClientAuthDataHook(PRFileDesc *s, 250+ SSLGetPlatformClientAuthData func, 251+ void *arg) 252+{ 253+ sslSocket *ss; 254+ 255+ ss = ssl_FindSocket(s); 256+ if (!ss) { 257+ SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook", 258+ SSL_GETPID(), s)); 259+ return SECFailure; 260+ } 261+ 262+ ss->getPlatformClientAuthData = func; 263+ ss->getPlatformClientAuthDataArg = arg; 264+ return SECSuccess; 265+} 266+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 267+ 268 /* NEED LOCKS IN HERE. */ 269 SECStatus 270 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) 271diff -pu a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h 272--- a/nss/lib/ssl/ssl.h 2014-01-17 17:49:26.062517203 -0800 273+++ b/nss/lib/ssl/ssl.h 2014-01-17 17:52:19.755405924 -0800 274@@ -533,6 +533,48 @@ typedef SECStatus (PR_CALLBACK *SSLGetCl 275 SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd, 276 SSLGetClientAuthData f, void *a); 277 278+/* 279+ * Prototype for SSL callback to get client auth data from the application, 280+ * optionally using the underlying platform's cryptographic primitives. 281+ * To use the platform cryptographic primitives, caNames and pRetCerts 282+ * should be set. To use NSS, pRetNSSCert and pRetNSSKey should be set. 283+ * Returning SECFailure will cause the socket to send no client certificate. 284+ * arg - application passed argument 285+ * caNames - pointer to distinguished names of CAs that the server likes 286+ * pRetCerts - pointer to pointer to list of certs, with the first being 287+ * the client cert, and any following being used for chain 288+ * building 289+ * pRetKey - pointer to native key pointer, for return of key 290+ * - Windows: A pointer to a PCERT_KEY_CONTEXT that was allocated 291+ * via PORT_Alloc(). Ownership of the PCERT_KEY_CONTEXT 292+ * is transferred to NSS, which will free via 293+ * PORT_Free(). 294+ * - Mac OS X: A pointer to a SecKeyRef. Ownership is 295+ * transferred to NSS, which will free via CFRelease(). 296+ * pRetNSSCert - pointer to pointer to NSS cert, for return of cert. 297+ * pRetNSSKey - pointer to NSS key pointer, for return of key. 298+ */ 299+typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg, 300+ PRFileDesc *fd, 301+ CERTDistNames *caNames, 302+ CERTCertList **pRetCerts,/*return */ 303+ void **pRetKey,/* return */ 304+ CERTCertificate **pRetNSSCert,/*return */ 305+ SECKEYPrivateKey **pRetNSSKey);/* return */ 306+ 307+/* 308+ * Set the client side callback for SSL to retrieve user's private key 309+ * and certificate. 310+ * Note: If a platform client auth callback is set, the callback configured by 311+ * SSL_GetClientAuthDataHook, if any, will not be called. 312+ * 313+ * fd - the file descriptor for the connection in question 314+ * f - the application's callback that delivers the key and cert 315+ * a - application specific data 316+ */ 317+SSL_IMPORT SECStatus 318+SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd, 319+ SSLGetPlatformClientAuthData f, void *a); 320 321 /* 322 ** SNI extension processing callback function. 323diff -pu a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h 324--- a/nss/lib/ssl/sslimpl.h 2014-01-17 17:52:00.295082288 -0800 325+++ b/nss/lib/ssl/sslimpl.h 2014-01-17 17:52:19.755405924 -0800 326@@ -20,6 +20,7 @@ 327 #include "sslerr.h" 328 #include "ssl3prot.h" 329 #include "hasht.h" 330+#include "keythi.h" 331 #include "nssilock.h" 332 #include "pkcs11t.h" 333 #if defined(XP_UNIX) || defined(XP_BEOS) 334@@ -31,6 +32,15 @@ 335 336 #include "sslt.h" /* for some formerly private types, now public */ 337 338+#ifdef NSS_PLATFORM_CLIENT_AUTH 339+#if defined(XP_WIN32) 340+#include <windows.h> 341+#include <wincrypt.h> 342+#elif defined(XP_MACOSX) 343+#include <Security/Security.h> 344+#endif 345+#endif 346+ 347 /* to make some of these old enums public without namespace pollution, 348 ** it was necessary to prepend ssl_ to the names. 349 ** These #defines preserve compatibility with the old code here in libssl. 350@@ -441,6 +451,14 @@ struct sslGatherStr { 351 #define GS_DATA 3 352 #define GS_PAD 4 353 354+#if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_WIN32) 355+typedef PCERT_KEY_CONTEXT PlatformKey; 356+#elif defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_MACOSX) 357+typedef SecKeyRef PlatformKey; 358+#else 359+typedef void *PlatformKey; 360+#endif 361+ 362 363 364 /* 365@@ -953,6 +971,10 @@ struct ssl3StateStr { 366 367 CERTCertificate * clientCertificate; /* used by client */ 368 SECKEYPrivateKey * clientPrivateKey; /* used by client */ 369+ /* platformClientKey is present even when NSS_PLATFORM_CLIENT_AUTH is not 370+ * defined in order to allow cleaner conditional code. 371+ * At most one of clientPrivateKey and platformClientKey may be set. */ 372+ PlatformKey platformClientKey; /* used by client */ 373 CERTCertificateList *clientCertChain; /* used by client */ 374 PRBool sendEmptyCert; /* used by client */ 375 376@@ -1214,6 +1236,10 @@ const unsigned char * preferredCipher; 377 void *authCertificateArg; 378 SSLGetClientAuthData getClientAuthData; 379 void *getClientAuthDataArg; 380+#ifdef NSS_PLATFORM_CLIENT_AUTH 381+ SSLGetPlatformClientAuthData getPlatformClientAuthData; 382+ void *getPlatformClientAuthDataArg; 383+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 384 SSLSNISocketConfig sniSocketConfig; 385 void *sniSocketConfigArg; 386 SSLBadCertHandler handleBadCert; 387@@ -1852,6 +1878,26 @@ extern SECStatus ssl_InitSessionCacheLoc 388 389 extern SECStatus ssl_FreeSessionCacheLocks(void); 390 391+/***************** platform client auth ****************/ 392+ 393+#ifdef NSS_PLATFORM_CLIENT_AUTH 394+// Releases the platform key. 395+extern void ssl_FreePlatformKey(PlatformKey key); 396+ 397+// Implement the client CertificateVerify message for SSL3/TLS1.0 398+extern SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash, 399+ PlatformKey key, SECItem *buf, 400+ PRBool isTLS, KeyType keyType); 401+ 402+// Converts a CERTCertList* (A collection of CERTCertificates) into a 403+// CERTCertificateList* (A collection of SECItems), or returns NULL if 404+// it cannot be converted. 405+// This is to allow the platform-supplied chain to be created with purely 406+// public API functions, using the preferred CERTCertList mutators, rather 407+// pushing this hack to clients. 408+extern CERTCertificateList* hack_NewCertificateListFromCertList( 409+ CERTCertList* list); 410+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 411 412 /**************** DTLS-specific functions **************/ 413 extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg); 414diff -pu a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c 415--- a/nss/lib/ssl/sslsock.c 2014-01-17 17:49:40.942764689 -0800 416+++ b/nss/lib/ssl/sslsock.c 2014-01-17 17:52:19.755405924 -0800 417@@ -263,6 +263,10 @@ ssl_DupSocket(sslSocket *os) 418 ss->authCertificateArg = os->authCertificateArg; 419 ss->getClientAuthData = os->getClientAuthData; 420 ss->getClientAuthDataArg = os->getClientAuthDataArg; 421+#ifdef NSS_PLATFORM_CLIENT_AUTH 422+ ss->getPlatformClientAuthData = os->getPlatformClientAuthData; 423+ ss->getPlatformClientAuthDataArg = os->getPlatformClientAuthDataArg; 424+#endif 425 ss->sniSocketConfig = os->sniSocketConfig; 426 ss->sniSocketConfigArg = os->sniSocketConfigArg; 427 ss->handleBadCert = os->handleBadCert; 428@@ -1667,6 +1671,12 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile 429 ss->getClientAuthData = sm->getClientAuthData; 430 if (sm->getClientAuthDataArg) 431 ss->getClientAuthDataArg = sm->getClientAuthDataArg; 432+#ifdef NSS_PLATFORM_CLIENT_AUTH 433+ if (sm->getPlatformClientAuthData) 434+ ss->getPlatformClientAuthData = sm->getPlatformClientAuthData; 435+ if (sm->getPlatformClientAuthDataArg) 436+ ss->getPlatformClientAuthDataArg = sm->getPlatformClientAuthDataArg; 437+#endif 438 if (sm->sniSocketConfig) 439 ss->sniSocketConfig = sm->sniSocketConfig; 440 if (sm->sniSocketConfigArg) 441@@ -2921,6 +2931,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProto 442 ss->sniSocketConfig = NULL; 443 ss->sniSocketConfigArg = NULL; 444 ss->getClientAuthData = NULL; 445+#ifdef NSS_PLATFORM_CLIENT_AUTH 446+ ss->getPlatformClientAuthData = NULL; 447+ ss->getPlatformClientAuthDataArg = NULL; 448+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 449 ss->handleBadCert = NULL; 450 ss->badCertArg = NULL; 451 ss->pkcs11PinArg = NULL; 452