1 diff -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); 204 diff -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" 217 diff -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) 249 diff -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. 301 diff -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); 400 diff -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