- add sources.
[platform/framework/web/crosswalk.git] / src / net / third_party / nss / ssl / sslauth.c
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.  */
13 CERTCertificate *
14 SSL_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.  */
31 CERTCertList *
32 SSL_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
65 loser:
66     CERT_DestroyCertList(chain);
67     return NULL;
68 }
69
70 /* NEED LOCKS IN HERE.  */
71 CERTCertificate *
72 SSL_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.  */
96 SECStatus
97 SSL_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.  */
182 SECStatus
183 SSL_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.  */
201 SECStatus 
202 SSL_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
219 SECStatus
220 SSL_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.  */
239 SECStatus 
240 SSL_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.  */
260 SECStatus 
261 SSL_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  */
281 SECStatus
282 SSL_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         CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert,
303                                         now, &certStatusArray->items[0],
304                                         ss->pkcs11PinArg);
305     }
306
307     /* this may seem backwards, but isn't. */
308     certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
309
310     rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
311                          now, ss->pkcs11PinArg, NULL);
312
313     if ( rv != SECSuccess || isServer )
314         return rv;
315   
316     /* cert is OK.  This is the client side of an SSL connection.
317      * Now check the name field in the cert against the desired hostname.
318      * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
319      */
320     hostname = ss->url;
321     if (hostname && hostname[0])
322         rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
323     else 
324         rv = SECFailure;
325     if (rv != SECSuccess)
326         PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
327
328     return rv;
329 }