1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4#include "cert.h"
5#include "secitem.h"
6#include "ssl.h"
7#include "sslimpl.h"
8#include "sslproto.h"
9#include "pk11func.h"
10#include "ocsp.h"
11
12/* NEED LOCKS IN HERE.  */
13CERTCertificate *
14SSL_PeerCertificate(PRFileDesc *fd)
15{
16    sslSocket *ss;
17
18    ss = ssl_FindSocket(fd);
19    if (!ss) {
20	SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
21		 SSL_GETPID(), fd));
22	return 0;
23    }
24    if (ss->opt.useSecurity && ss->sec.peerCert) {
25	return CERT_DupCertificate(ss->sec.peerCert);
26    }
27    return 0;
28}
29
30/* NEED LOCKS IN HERE.  */
31CERTCertList *
32SSL_PeerCertificateChain(PRFileDesc *fd)
33{
34    sslSocket *ss;
35    CERTCertList *chain = NULL;
36    CERTCertificate *cert;
37    ssl3CertNode *cur;
38
39    ss = ssl_FindSocket(fd);
40    if (!ss) {
41	SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain",
42		 SSL_GETPID(), fd));
43	return NULL;
44    }
45    if (!ss->opt.useSecurity || !ss->sec.peerCert) {
46	PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
47	return NULL;
48    }
49    chain = CERT_NewCertList();
50    if (!chain) {
51	return NULL;
52    }
53    cert = CERT_DupCertificate(ss->sec.peerCert);
54    if (CERT_AddCertToListTail(chain, cert) != SECSuccess) {
55	goto loser;
56    }
57    for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
58	cert = CERT_DupCertificate(cur->cert);
59	if (CERT_AddCertToListTail(chain, cert) != SECSuccess) {
60	    goto loser;
61	}
62    }
63    return chain;
64
65loser:
66    CERT_DestroyCertList(chain);
67    return NULL;
68}
69
70/* NEED LOCKS IN HERE.  */
71CERTCertificate *
72SSL_LocalCertificate(PRFileDesc *fd)
73{
74    sslSocket *ss;
75
76    ss = ssl_FindSocket(fd);
77    if (!ss) {
78	SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
79		 SSL_GETPID(), fd));
80	return NULL;
81    }
82    if (ss->opt.useSecurity) {
83    	if (ss->sec.localCert) {
84	    return CERT_DupCertificate(ss->sec.localCert);
85	}
86	if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) {
87	    return CERT_DupCertificate(ss->sec.ci.sid->localCert);
88	}
89    }
90    return NULL;
91}
92
93
94
95/* NEED LOCKS IN HERE.  */
96SECStatus
97SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
98		   char **ip, char **sp)
99{
100    sslSocket *ss;
101    const char *cipherName;
102    PRBool isDes = PR_FALSE;
103
104    ss = ssl_FindSocket(fd);
105    if (!ss) {
106	SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
107		 SSL_GETPID(), fd));
108	return SECFailure;
109    }
110
111    if (cp) *cp = 0;
112    if (kp0) *kp0 = 0;
113    if (kp1) *kp1 = 0;
114    if (ip) *ip = 0;
115    if (sp) *sp = 0;
116    if (op) {
117	*op = SSL_SECURITY_STATUS_OFF;
118    }
119
120    if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
121	if (ss->version < SSL_LIBRARY_VERSION_3_0) {
122	    cipherName = ssl_cipherName[ss->sec.cipherType];
123	} else {
124	    cipherName = ssl3_cipherName[ss->sec.cipherType];
125	}
126	PORT_Assert(cipherName);
127	if (cipherName) {
128            if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;
129
130            if (cp) {
131                *cp = PORT_Strdup(cipherName);
132            }
133        }
134
135	if (kp0) {
136	    *kp0 = ss->sec.keyBits;
137	    if (isDes) *kp0 = (*kp0 * 7) / 8;
138	}
139	if (kp1) {
140	    *kp1 = ss->sec.secretKeyBits;
141	    if (isDes) *kp1 = (*kp1 * 7) / 8;
142	}
143	if (op) {
144	    if (ss->sec.keyBits == 0) {
145		*op = SSL_SECURITY_STATUS_OFF;
146	    } else if (ss->sec.secretKeyBits < 90) {
147		*op = SSL_SECURITY_STATUS_ON_LOW;
148
149	    } else {
150		*op = SSL_SECURITY_STATUS_ON_HIGH;
151	    }
152	}
153
154	if (ip || sp) {
155	    CERTCertificate *cert;
156
157	    cert = ss->sec.peerCert;
158	    if (cert) {
159		if (ip) {
160		    *ip = CERT_NameToAscii(&cert->issuer);
161		}
162		if (sp) {
163		    *sp = CERT_NameToAscii(&cert->subject);
164		}
165	    } else {
166		if (ip) {
167		    *ip = PORT_Strdup("no certificate");
168		}
169		if (sp) {
170		    *sp = PORT_Strdup("no certificate");
171		}
172	    }
173	}
174    }
175
176    return SECSuccess;
177}
178
179/************************************************************************/
180
181/* NEED LOCKS IN HERE.  */
182SECStatus
183SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
184{
185    sslSocket *ss;
186
187    ss = ssl_FindSocket(s);
188    if (!ss) {
189	SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook",
190		 SSL_GETPID(), s));
191	return SECFailure;
192    }
193
194    ss->authCertificate = func;
195    ss->authCertificateArg = arg;
196
197    return SECSuccess;
198}
199
200/* NEED LOCKS IN HERE.  */
201SECStatus
202SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
203			      void *arg)
204{
205    sslSocket *ss;
206
207    ss = ssl_FindSocket(s);
208    if (!ss) {
209	SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
210		 SSL_GETPID(), s));
211	return SECFailure;
212    }
213
214    ss->getClientAuthData = func;
215    ss->getClientAuthDataArg = arg;
216    return SECSuccess;
217}
218
219SECStatus
220SSL_SetClientChannelIDCallback(PRFileDesc *fd,
221			       SSLClientChannelIDCallback callback,
222			       void *arg) {
223    sslSocket *ss = ssl_FindSocket(fd);
224
225    if (!ss) {
226	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback",
227		 SSL_GETPID(), fd));
228	return SECFailure;
229    }
230
231    ss->getChannelID = callback;
232    ss->getChannelIDArg = arg;
233
234    return SECSuccess;
235}
236
237#ifdef NSS_PLATFORM_CLIENT_AUTH
238/* NEED LOCKS IN HERE.  */
239SECStatus
240SSL_GetPlatformClientAuthDataHook(PRFileDesc *s,
241                                  SSLGetPlatformClientAuthData func,
242                                  void *arg)
243{
244    sslSocket *ss;
245
246    ss = ssl_FindSocket(s);
247    if (!ss) {
248	SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook",
249		 SSL_GETPID(), s));
250	return SECFailure;
251    }
252
253    ss->getPlatformClientAuthData = func;
254    ss->getPlatformClientAuthDataArg = arg;
255    return SECSuccess;
256}
257#endif   /* NSS_PLATFORM_CLIENT_AUTH */
258
259/* NEED LOCKS IN HERE.  */
260SECStatus
261SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
262{
263    sslSocket *ss;
264
265    ss = ssl_FindSocket(s);
266    if (!ss) {
267	SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
268		 SSL_GETPID(), s));
269	return SECFailure;
270    }
271
272    ss->pkcs11PinArg = arg;
273    return SECSuccess;
274}
275
276
277/* This is the "default" authCert callback function.  It is called when a
278 * certificate message is received from the peer and the local application
279 * has not registered an authCert callback function.
280 */
281SECStatus
282SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
283{
284    SECStatus          rv;
285    CERTCertDBHandle * handle;
286    sslSocket *        ss;
287    SECCertUsage       certUsage;
288    const char *       hostname    = NULL;
289    PRTime             now = PR_Now();
290    SECItemArray *     certStatusArray;
291
292    ss = ssl_FindSocket(fd);
293    PORT_Assert(ss != NULL);
294    if (!ss) {
295	return SECFailure;
296    }
297
298    handle = (CERTCertDBHandle *)arg;
299    certStatusArray = &ss->sec.ci.sid->peerCertStatus;
300
301    if (certStatusArray->len) {
302	PORT_SetError(0);
303	if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now,
304						  &certStatusArray->items[0],
305						  ss->pkcs11PinArg)
306		!= SECSuccess) {
307	    PRErrorCode error = PR_GetError();
308	    PORT_Assert(error != 0);
309	}
310    }
311
312    /* this may seem backwards, but isn't. */
313    certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
314
315    rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
316			 now, ss->pkcs11PinArg, NULL);
317
318    if ( rv != SECSuccess || isServer )
319	return rv;
320
321    /* cert is OK.  This is the client side of an SSL connection.
322     * Now check the name field in the cert against the desired hostname.
323     * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
324     */
325    hostname = ss->url;
326    if (hostname && hostname[0])
327	rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
328    else
329	rv = SECFailure;
330    if (rv != SECSuccess)
331	PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
332
333    return rv;
334}
335