1 diff -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); 226 diff -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" 239 diff -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) 271 diff -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. 323 diff -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); 414 diff -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