1diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c 2--- a/nss/lib/ssl/ssl3con.c 2013-07-31 12:31:45.326118409 -0700 3+++ b/nss/lib/ssl/ssl3con.c 2013-07-31 12:35:27.189373289 -0700 4@@ -2284,6 +2284,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@@ -5768,25 +5771,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@@ -5870,6 +5884,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@@ -6496,6 +6516,10 @@ ssl3_HandleCertificateRequest(sslSocket 82 SECItem cert_types = {siBuffer, NULL, 0}; 83 SECItem algorithms = {siBuffer, NULL, 0}; 84 CERTDistNames ca_list; 85+#ifdef NSS_PLATFORM_CLIENT_AUTH 86+ CERTCertList * platform_cert_list = NULL; 87+ CERTCertListNode * certNode = NULL; 88+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 89 90 SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake", 91 SSL_GETPID(), ss->fd)); 92@@ -6512,6 +6536,7 @@ ssl3_HandleCertificateRequest(sslSocket 93 PORT_Assert(ss->ssl3.clientCertChain == NULL); 94 PORT_Assert(ss->ssl3.clientCertificate == NULL); 95 PORT_Assert(ss->ssl3.clientPrivateKey == NULL); 96+ PORT_Assert(ss->ssl3.platformClientKey == (PlatformKey)NULL); 97 98 isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); 99 isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); 100@@ -6591,6 +6616,18 @@ ssl3_HandleCertificateRequest(sslSocket 101 desc = no_certificate; 102 ss->ssl3.hs.ws = wait_hello_done; 103 104+#ifdef NSS_PLATFORM_CLIENT_AUTH 105+ if (ss->getPlatformClientAuthData != NULL) { 106+ /* XXX Should pass cert_types and algorithms in this call!! */ 107+ rv = (SECStatus)(*ss->getPlatformClientAuthData)( 108+ ss->getPlatformClientAuthDataArg, 109+ ss->fd, &ca_list, 110+ &platform_cert_list, 111+ (void**)&ss->ssl3.platformClientKey, 112+ &ss->ssl3.clientCertificate, 113+ &ss->ssl3.clientPrivateKey); 114+ } else 115+#endif 116 if (ss->getClientAuthData != NULL) { 117 /* XXX Should pass cert_types and algorithms in this call!! */ 118 rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg, 119@@ -6600,12 +6637,52 @@ ssl3_HandleCertificateRequest(sslSocket 120 } else { 121 rv = SECFailure; /* force it to send a no_certificate alert */ 122 } 123+ 124 switch (rv) { 125 case SECWouldBlock: /* getClientAuthData has put up a dialog box. */ 126 ssl3_SetAlwaysBlock(ss); 127 break; /* not an error */ 128 129 case SECSuccess: 130+#ifdef NSS_PLATFORM_CLIENT_AUTH 131+ if (!platform_cert_list || CERT_LIST_EMPTY(platform_cert_list) || 132+ !ss->ssl3.platformClientKey) { 133+ if (platform_cert_list) { 134+ CERT_DestroyCertList(platform_cert_list); 135+ platform_cert_list = NULL; 136+ } 137+ if (ss->ssl3.platformClientKey) { 138+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 139+ ss->ssl3.platformClientKey = (PlatformKey)NULL; 140+ } 141+ /* Fall through to NSS client auth check */ 142+ } else { 143+ certNode = CERT_LIST_HEAD(platform_cert_list); 144+ ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert); 145+ 146+ /* Setting ssl3.clientCertChain non-NULL will cause 147+ * ssl3_HandleServerHelloDone to call SendCertificate. 148+ * Note: clientCertChain should include the EE cert as 149+ * clientCertificate is ignored during the actual sending 150+ */ 151+ ss->ssl3.clientCertChain = 152+ hack_NewCertificateListFromCertList(platform_cert_list); 153+ CERT_DestroyCertList(platform_cert_list); 154+ platform_cert_list = NULL; 155+ if (ss->ssl3.clientCertChain == NULL) { 156+ if (ss->ssl3.clientCertificate != NULL) { 157+ CERT_DestroyCertificate(ss->ssl3.clientCertificate); 158+ ss->ssl3.clientCertificate = NULL; 159+ } 160+ if (ss->ssl3.platformClientKey) { 161+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 162+ ss->ssl3.platformClientKey = (PlatformKey)NULL; 163+ } 164+ goto send_no_certificate; 165+ } 166+ break; /* not an error */ 167+ } 168+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 169 /* check what the callback function returned */ 170 if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) { 171 /* we are missing either the key or cert */ 172@@ -6668,6 +6745,10 @@ loser: 173 done: 174 if (arena != NULL) 175 PORT_FreeArena(arena, PR_FALSE); 176+#ifdef NSS_PLATFORM_CLIENT_AUTH 177+ if (platform_cert_list) 178+ CERT_DestroyCertList(platform_cert_list); 179+#endif 180 return rv; 181 } 182 183@@ -6749,7 +6830,8 @@ ssl3_SendClientSecondRound(sslSocket *ss 184 185 sendClientCert = !ss->ssl3.sendEmptyCert && 186 ss->ssl3.clientCertChain != NULL && 187- ss->ssl3.clientPrivateKey != NULL; 188+ (ss->ssl3.platformClientKey || 189+ ss->ssl3.clientPrivateKey != NULL); 190 191 /* We must wait for the server's certificate to be authenticated before 192 * sending the client certificate in order to disclosing the client 193@@ -11465,6 +11547,10 @@ ssl3_DestroySSL3Info(sslSocket *ss) 194 195 if (ss->ssl3.clientPrivateKey != NULL) 196 SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); 197+#ifdef NSS_PLATFORM_CLIENT_AUTH 198+ if (ss->ssl3.platformClientKey) 199+ ssl_FreePlatformKey(ss->ssl3.platformClientKey); 200+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 201 202 if (ss->ssl3.peerCertArena != NULL) 203 ssl3_CleanupPeerCerts(ss); 204diff -pu a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c 205--- a/nss/lib/ssl/ssl3ext.c 2013-07-31 12:07:10.964699464 -0700 206+++ b/nss/lib/ssl/ssl3ext.c 2013-07-31 12:35:27.189373289 -0700 207@@ -10,8 +10,8 @@ 208 #include "nssrenam.h" 209 #include "nss.h" 210 #include "ssl.h" 211-#include "sslproto.h" 212 #include "sslimpl.h" 213+#include "sslproto.h" 214 #include "pk11pub.h" 215 #ifdef NO_PKCS11_BYPASS 216 #include "blapit.h" 217diff -pu a/nss/lib/ssl/sslauth.c b/nss/lib/ssl/sslauth.c 218--- a/nss/lib/ssl/sslauth.c 2013-07-31 12:32:29.076760372 -0700 219+++ b/nss/lib/ssl/sslauth.c 2013-07-31 12:35:27.189373289 -0700 220@@ -219,6 +219,28 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, 221 return SECSuccess; 222 } 223 224+#ifdef NSS_PLATFORM_CLIENT_AUTH 225+/* NEED LOCKS IN HERE. */ 226+SECStatus 227+SSL_GetPlatformClientAuthDataHook(PRFileDesc *s, 228+ SSLGetPlatformClientAuthData func, 229+ void *arg) 230+{ 231+ sslSocket *ss; 232+ 233+ ss = ssl_FindSocket(s); 234+ if (!ss) { 235+ SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook", 236+ SSL_GETPID(), s)); 237+ return SECFailure; 238+ } 239+ 240+ ss->getPlatformClientAuthData = func; 241+ ss->getPlatformClientAuthDataArg = arg; 242+ return SECSuccess; 243+} 244+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 245+ 246 /* NEED LOCKS IN HERE. */ 247 SECStatus 248 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) 249diff -pu a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h 250--- a/nss/lib/ssl/ssl.h 2013-07-31 12:32:29.076760372 -0700 251+++ b/nss/lib/ssl/ssl.h 2013-07-31 12:35:27.199373436 -0700 252@@ -503,6 +503,48 @@ typedef SECStatus (PR_CALLBACK *SSLGetCl 253 SSL_IMPORT SECStatus SSL_GetClientAuthDataHook(PRFileDesc *fd, 254 SSLGetClientAuthData f, void *a); 255 256+/* 257+ * Prototype for SSL callback to get client auth data from the application, 258+ * optionally using the underlying platform's cryptographic primitives. 259+ * To use the platform cryptographic primitives, caNames and pRetCerts 260+ * should be set. To use NSS, pRetNSSCert and pRetNSSKey should be set. 261+ * Returning SECFailure will cause the socket to send no client certificate. 262+ * arg - application passed argument 263+ * caNames - pointer to distinguished names of CAs that the server likes 264+ * pRetCerts - pointer to pointer to list of certs, with the first being 265+ * the client cert, and any following being used for chain 266+ * building 267+ * pRetKey - pointer to native key pointer, for return of key 268+ * - Windows: A pointer to a PCERT_KEY_CONTEXT that was allocated 269+ * via PORT_Alloc(). Ownership of the PCERT_KEY_CONTEXT 270+ * is transferred to NSS, which will free via 271+ * PORT_Free(). 272+ * - Mac OS X: A pointer to a SecKeyRef. Ownership is 273+ * transferred to NSS, which will free via CFRelease(). 274+ * pRetNSSCert - pointer to pointer to NSS cert, for return of cert. 275+ * pRetNSSKey - pointer to NSS key pointer, for return of key. 276+ */ 277+typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg, 278+ PRFileDesc *fd, 279+ CERTDistNames *caNames, 280+ CERTCertList **pRetCerts,/*return */ 281+ void **pRetKey,/* return */ 282+ CERTCertificate **pRetNSSCert,/*return */ 283+ SECKEYPrivateKey **pRetNSSKey);/* return */ 284+ 285+/* 286+ * Set the client side callback for SSL to retrieve user's private key 287+ * and certificate. 288+ * Note: If a platform client auth callback is set, the callback configured by 289+ * SSL_GetClientAuthDataHook, if any, will not be called. 290+ * 291+ * fd - the file descriptor for the connection in question 292+ * f - the application's callback that delivers the key and cert 293+ * a - application specific data 294+ */ 295+SSL_IMPORT SECStatus 296+SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd, 297+ SSLGetPlatformClientAuthData f, void *a); 298 299 /* 300 ** SNI extension processing callback function. 301diff -pu a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h 302--- a/nss/lib/ssl/sslimpl.h 2013-07-31 12:31:45.326118409 -0700 303+++ b/nss/lib/ssl/sslimpl.h 2013-07-31 12:35:27.199373436 -0700 304@@ -20,6 +20,7 @@ 305 #include "sslerr.h" 306 #include "ssl3prot.h" 307 #include "hasht.h" 308+#include "keythi.h" 309 #include "nssilock.h" 310 #include "pkcs11t.h" 311 #if defined(XP_UNIX) || defined(XP_BEOS) 312@@ -31,6 +32,15 @@ 313 314 #include "sslt.h" /* for some formerly private types, now public */ 315 316+#ifdef NSS_PLATFORM_CLIENT_AUTH 317+#if defined(XP_WIN32) 318+#include <windows.h> 319+#include <wincrypt.h> 320+#elif defined(XP_MACOSX) 321+#include <Security/Security.h> 322+#endif 323+#endif 324+ 325 /* to make some of these old enums public without namespace pollution, 326 ** it was necessary to prepend ssl_ to the names. 327 ** These #defines preserve compatibility with the old code here in libssl. 328@@ -444,6 +454,14 @@ typedef SECStatus (*SSLCompressor)(void 329 int inlen); 330 typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit); 331 332+#if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_WIN32) 333+typedef PCERT_KEY_CONTEXT PlatformKey; 334+#elif defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_MACOSX) 335+typedef SecKeyRef PlatformKey; 336+#else 337+typedef void *PlatformKey; 338+#endif 339+ 340 341 342 /* 343@@ -896,6 +914,10 @@ struct ssl3StateStr { 344 345 CERTCertificate * clientCertificate; /* used by client */ 346 SECKEYPrivateKey * clientPrivateKey; /* used by client */ 347+ /* platformClientKey is present even when NSS_PLATFORM_CLIENT_AUTH is not 348+ * defined in order to allow cleaner conditional code. 349+ * At most one of clientPrivateKey and platformClientKey may be set. */ 350+ PlatformKey platformClientKey; /* used by client */ 351 CERTCertificateList *clientCertChain; /* used by client */ 352 PRBool sendEmptyCert; /* used by client */ 353 354@@ -1153,6 +1175,10 @@ const unsigned char * preferredCipher; 355 void *authCertificateArg; 356 SSLGetClientAuthData getClientAuthData; 357 void *getClientAuthDataArg; 358+#ifdef NSS_PLATFORM_CLIENT_AUTH 359+ SSLGetPlatformClientAuthData getPlatformClientAuthData; 360+ void *getPlatformClientAuthDataArg; 361+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 362 SSLSNISocketConfig sniSocketConfig; 363 void *sniSocketConfigArg; 364 SSLBadCertHandler handleBadCert; 365@@ -1737,7 +1763,6 @@ extern void ssl_FreePRSocket(PRFileDesc 366 * various ciphers */ 367 extern int ssl3_config_match_init(sslSocket *); 368 369- 370 /* Create a new ref counted key pair object from two keys. */ 371 extern ssl3KeyPair * ssl3_NewKeyPair( SECKEYPrivateKey * privKey, 372 SECKEYPublicKey * pubKey); 373@@ -1777,6 +1802,26 @@ extern SECStatus ssl_InitSessionCacheLoc 374 375 extern SECStatus ssl_FreeSessionCacheLocks(void); 376 377+/***************** platform client auth ****************/ 378+ 379+#ifdef NSS_PLATFORM_CLIENT_AUTH 380+// Releases the platform key. 381+extern void ssl_FreePlatformKey(PlatformKey key); 382+ 383+// Implement the client CertificateVerify message for SSL3/TLS1.0 384+extern SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash, 385+ PlatformKey key, SECItem *buf, 386+ PRBool isTLS, KeyType keyType); 387+ 388+// Converts a CERTCertList* (A collection of CERTCertificates) into a 389+// CERTCertificateList* (A collection of SECItems), or returns NULL if 390+// it cannot be converted. 391+// This is to allow the platform-supplied chain to be created with purely 392+// public API functions, using the preferred CERTCertList mutators, rather 393+// pushing this hack to clients. 394+extern CERTCertificateList* hack_NewCertificateListFromCertList( 395+ CERTCertList* list); 396+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 397 398 /**************** DTLS-specific functions **************/ 399 extern void dtls_FreeQueuedMessage(DTLSQueuedMessage *msg); 400diff -pu a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c 401--- a/nss/lib/ssl/sslsock.c 2013-07-31 12:28:39.283413269 -0700 402+++ b/nss/lib/ssl/sslsock.c 2013-07-31 12:35:27.199373436 -0700 403@@ -343,6 +343,10 @@ ssl_DupSocket(sslSocket *os) 404 ss->authCertificateArg = os->authCertificateArg; 405 ss->getClientAuthData = os->getClientAuthData; 406 ss->getClientAuthDataArg = os->getClientAuthDataArg; 407+#ifdef NSS_PLATFORM_CLIENT_AUTH 408+ ss->getPlatformClientAuthData = os->getPlatformClientAuthData; 409+ ss->getPlatformClientAuthDataArg = os->getPlatformClientAuthDataArg; 410+#endif 411 ss->sniSocketConfig = os->sniSocketConfig; 412 ss->sniSocketConfigArg = os->sniSocketConfigArg; 413 ss->handleBadCert = os->handleBadCert; 414@@ -1730,6 +1734,12 @@ SSL_ReconfigFD(PRFileDesc *model, PRFile 415 ss->getClientAuthData = sm->getClientAuthData; 416 if (sm->getClientAuthDataArg) 417 ss->getClientAuthDataArg = sm->getClientAuthDataArg; 418+#ifdef NSS_PLATFORM_CLIENT_AUTH 419+ if (sm->getPlatformClientAuthData) 420+ ss->getPlatformClientAuthData = sm->getPlatformClientAuthData; 421+ if (sm->getPlatformClientAuthDataArg) 422+ ss->getPlatformClientAuthDataArg = sm->getPlatformClientAuthDataArg; 423+#endif 424 if (sm->sniSocketConfig) 425 ss->sniSocketConfig = sm->sniSocketConfig; 426 if (sm->sniSocketConfigArg) 427@@ -2980,6 +2990,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProto 428 ss->sniSocketConfig = NULL; 429 ss->sniSocketConfigArg = NULL; 430 ss->getClientAuthData = NULL; 431+#ifdef NSS_PLATFORM_CLIENT_AUTH 432+ ss->getPlatformClientAuthData = NULL; 433+ ss->getPlatformClientAuthDataArg = NULL; 434+#endif /* NSS_PLATFORM_CLIENT_AUTH */ 435 ss->handleBadCert = NULL; 436 ss->badCertArg = NULL; 437 ss->pkcs11PinArg = NULL; 438