• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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