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;
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 @@ -5768,25 +5771,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 @@ -5870,6 +5884,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 @@ -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 */
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);
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;
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,
110 + &platform_cert_list,
111 + (void**)&ss->ssl3.platformClientKey,
112 + &ss->ssl3.clientCertificate,
113 + &ss->ssl3.clientPrivateKey);
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
121 rv = SECFailure; /* force it to send a no_certificate alert */
125 case SECWouldBlock: /* getClientAuthData has put up a dialog box. */
126 ssl3_SetAlwaysBlock(ss);
127 break; /* not an error */
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;
137 + if (ss->ssl3.platformClientKey) {
138 + ssl_FreePlatformKey(ss->ssl3.platformClientKey);
139 + ss->ssl3.platformClientKey = (PlatformKey)NULL;
141 + /* Fall through to NSS client auth check */
143 + certNode = CERT_LIST_HEAD(platform_cert_list);
144 + ss->ssl3.clientCertificate = CERT_DupCertificate(certNode->cert);
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
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;
160 + if (ss->ssl3.platformClientKey) {
161 + ssl_FreePlatformKey(ss->ssl3.platformClientKey);
162 + ss->ssl3.platformClientKey = (PlatformKey)NULL;
164 + goto send_no_certificate;
166 + break; /* not an error */
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:
175 PORT_FreeArena(arena, PR_FALSE);
176 +#ifdef NSS_PLATFORM_CLIENT_AUTH
177 + if (platform_cert_list)
178 + CERT_DestroyCertList(platform_cert_list);
183 @@ -6749,7 +6830,8 @@ ssl3_SendClientSecondRound(sslSocket *ss
185 sendClientCert = !ss->ssl3.sendEmptyCert &&
186 ss->ssl3.clientCertChain != NULL &&
187 - ss->ssl3.clientPrivateKey != NULL;
188 + (ss->ssl3.platformClientKey ||
189 + ss->ssl3.clientPrivateKey != NULL);
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)
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 */
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
208 #include "nssrenam.h"
211 -#include "sslproto.h"
213 +#include "sslproto.h"
215 #ifdef NO_PKCS11_BYPASS
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,
224 +#ifdef NSS_PLATFORM_CLIENT_AUTH
225 +/* NEED LOCKS IN HERE. */
227 +SSL_GetPlatformClientAuthDataHook(PRFileDesc *s,
228 + SSLGetPlatformClientAuthData func,
233 + ss = ssl_FindSocket(s);
235 + SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook",
240 + ss->getPlatformClientAuthData = func;
241 + ss->getPlatformClientAuthDataArg = arg;
244 +#endif /* NSS_PLATFORM_CLIENT_AUTH */
246 /* NEED LOCKS IN HERE. */
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);
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
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
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.
277 +typedef SECStatus (PR_CALLBACK *SSLGetPlatformClientAuthData)(void *arg,
279 + CERTDistNames *caNames,
280 + CERTCertList **pRetCerts,/*return */
281 + void **pRetKey,/* return */
282 + CERTCertificate **pRetNSSCert,/*return */
283 + SECKEYPrivateKey **pRetNSSKey);/* return */
286 + * Set the client side callback for SSL to retrieve user's private key
288 + * Note: If a platform client auth callback is set, the callback configured by
289 + * SSL_GetClientAuthDataHook, if any, will not be called.
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
295 +SSL_IMPORT SECStatus
296 +SSL_GetPlatformClientAuthDataHook(PRFileDesc *fd,
297 + SSLGetPlatformClientAuthData f, void *a);
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
306 #include "ssl3prot.h"
309 #include "nssilock.h"
311 #if defined(XP_UNIX) || defined(XP_BEOS)
314 #include "sslt.h" /* for some formerly private types, now public */
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>
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
330 typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
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;
337 +typedef void *PlatformKey;
343 @@ -896,6 +914,10 @@ struct ssl3StateStr {
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 */
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
367 extern int ssl3_config_match_init(sslSocket *);
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
375 extern SECStatus ssl_FreeSessionCacheLocks(void);
377 +/***************** platform client auth ****************/
379 +#ifdef NSS_PLATFORM_CLIENT_AUTH
380 +// Releases the platform key.
381 +extern void ssl_FreePlatformKey(PlatformKey key);
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);
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 */
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;
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;
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;