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;
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) {
14 @@ -6103,25 +6106,36 @@ ssl3_SendCertificateVerify(sslSocket *ss
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 */
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;
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.
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.
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);
60 + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
61 + ss->ssl3.clientPrivateKey = NULL;
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 */
68 @@ -6200,6 +6214,12 @@ ssl3_HandleServerHello(sslSocket *ss, SS
69 SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
70 ss->ssl3.clientPrivateKey = NULL;
72 +#ifdef NSS_PLATFORM_CLIENT_AUTH
73 + if (ss->ssl3.platformClientKey) {
74 + ssl_FreePlatformKey(ss->ssl3.platformClientKey);
75 + ss->ssl3.platformClientKey = (PlatformKey)NULL;
77 +#endif /* NSS_PLATFORM_CLIENT_AUTH */
79 temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
81 @@ -6827,6 +6847,18 @@ ssl3_ExtractClientKeyInfo(sslSocket *ss,
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.
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;
95 +#endif /* NSS_PLATFORM_CLIENT_AUTH && _WIN32 */
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 */
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);
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;
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,
129 + &platform_cert_list,
130 + (void**)&ss->ssl3.platformClientKey,
131 + &ss->ssl3.clientCertificate,
132 + &ss->ssl3.clientPrivateKey);
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
140 rv = SECFailure; /* force it to send a no_certificate alert */
144 case SECWouldBlock: /* getClientAuthData has put up a dialog box. */
145 ssl3_SetAlwaysBlock(ss);
146 break; /* not an error */
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;
156 + if (ss->ssl3.platformClientKey) {
157 + ssl_FreePlatformKey(ss->ssl3.platformClientKey);
158 + ss->ssl3.platformClientKey = (PlatformKey)NULL;
160 + /* Fall through to NSS client auth check */
162 + certNode = CERT_LIST_HEAD(platform_cert_list);
163 + ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert);
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
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;
179 + if (ss->ssl3.platformClientKey) {
180 + ssl_FreePlatformKey(ss->ssl3.platformClientKey);
181 + ss->ssl3.platformClientKey = (PlatformKey)NULL;
183 + goto send_no_certificate;
185 + if (ss->ssl3.hs.hashType == handshake_hash_single) {
186 + ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, &algorithms);
188 + break; /* not an error */
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:
197 PORT_FreeArena(arena, PR_FALSE);
198 +#ifdef NSS_PLATFORM_CLIENT_AUTH
199 + if (platform_cert_list)
200 + CERT_DestroyCertList(platform_cert_list);
205 @@ -7213,7 +7309,8 @@ ssl3_SendClientSecondRound(sslSocket *ss
207 sendClientCert = !ss->ssl3.sendEmptyCert &&
208 ss->ssl3.clientCertChain != NULL &&
209 - ss->ssl3.clientPrivateKey != NULL;
210 + (ss->ssl3.platformClientKey ||
211 + ss->ssl3.clientPrivateKey != NULL);
213 if (!sendClientCert &&
214 ss->ssl3.hs.hashType == handshake_hash_single &&
215 @@ -12052,6 +12149,10 @@ ssl3_DestroySSL3Info(sslSocket *ss)
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 */
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
230 #include "nssrenam.h"
233 -#include "sslproto.h"
235 +#include "sslproto.h"
237 #ifdef NO_PKCS11_BYPASS
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,
246 +#ifdef NSS_PLATFORM_CLIENT_AUTH
247 +/* NEED LOCKS IN HERE. */
249 +SSL_GetPlatformClientAuthDataHook(PRFileDesc *s,
250 + SSLGetPlatformClientAuthData func,
255 + ss = ssl_FindSocket(s);
257 + SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook",
262 + ss->getPlatformClientAuthData = func;
263 + ss->getPlatformClientAuthDataArg = arg;
266 +#endif /* NSS_PLATFORM_CLIENT_AUTH */
268 /* NEED LOCKS IN HERE. */
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);
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
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
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.
299 +typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg,
301 + CERTDistNames *caNames,
302 + CERTCertList **pRetCerts,/*return */
303 + void **pRetKey,/* return */
304 + CERTCertificate **pRetNSSCert,/*return */
305 + SECKEYPrivateKey **pRetNSSKey);/* return */
308 + * Set the client side callback for SSL to retrieve user's private key
310 + * Note: If a platform client auth callback is set, the callback configured by
311 + * SSL_GetClientAuthDataHook, if any, will not be called.
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
317 +SSL_IMPORT SECStatus
318 +SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd,
319 + SSLGetPlatformClientAuthData f, void *a);
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
328 #include "ssl3prot.h"
331 #include "nssilock.h"
333 #if defined(XP_UNIX) || defined(XP_BEOS)
336 #include "sslt.h" /* for some formerly private types, now public */
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>
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 {
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;
359 +typedef void *PlatformKey;
365 @@ -953,6 +971,10 @@ struct ssl3StateStr {
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 */
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
389 extern SECStatus ssl_FreeSessionCacheLocks(void);
391 +/***************** platform client auth ****************/
393 +#ifdef NSS_PLATFORM_CLIENT_AUTH
394 +// Releases the platform key.
395 +extern void ssl_FreePlatformKey(PlatformKey key);
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);
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 */
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;
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;
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;