|
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 /* NEED LOCKS IN HERE. */ |
|
220 SECStatus |
|
221 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) |
|
222 { |
|
223 sslSocket *ss; |
|
224 |
|
225 ss = ssl_FindSocket(s); |
|
226 if (!ss) { |
|
227 SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook", |
|
228 SSL_GETPID(), s)); |
|
229 return SECFailure; |
|
230 } |
|
231 |
|
232 ss->pkcs11PinArg = arg; |
|
233 return SECSuccess; |
|
234 } |
|
235 |
|
236 |
|
237 /* This is the "default" authCert callback function. It is called when a |
|
238 * certificate message is received from the peer and the local application |
|
239 * has not registered an authCert callback function. |
|
240 */ |
|
241 SECStatus |
|
242 SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) |
|
243 { |
|
244 SECStatus rv; |
|
245 CERTCertDBHandle * handle; |
|
246 sslSocket * ss; |
|
247 SECCertUsage certUsage; |
|
248 const char * hostname = NULL; |
|
249 PRTime now = PR_Now(); |
|
250 SECItemArray * certStatusArray; |
|
251 |
|
252 ss = ssl_FindSocket(fd); |
|
253 PORT_Assert(ss != NULL); |
|
254 if (!ss) { |
|
255 return SECFailure; |
|
256 } |
|
257 |
|
258 handle = (CERTCertDBHandle *)arg; |
|
259 certStatusArray = &ss->sec.ci.sid->peerCertStatus; |
|
260 |
|
261 if (certStatusArray->len) { |
|
262 PORT_SetError(0); |
|
263 if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now, |
|
264 &certStatusArray->items[0], |
|
265 ss->pkcs11PinArg) |
|
266 != SECSuccess) { |
|
267 PRErrorCode error = PR_GetError(); |
|
268 PORT_Assert(error != 0); |
|
269 } |
|
270 } |
|
271 |
|
272 /* this may seem backwards, but isn't. */ |
|
273 certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; |
|
274 |
|
275 rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage, |
|
276 now, ss->pkcs11PinArg, NULL); |
|
277 |
|
278 if ( rv != SECSuccess || isServer ) |
|
279 return rv; |
|
280 |
|
281 /* cert is OK. This is the client side of an SSL connection. |
|
282 * Now check the name field in the cert against the desired hostname. |
|
283 * NB: This is our only defense against Man-In-The-Middle (MITM) attacks! |
|
284 */ |
|
285 hostname = ss->url; |
|
286 if (hostname && hostname[0]) |
|
287 rv = CERT_VerifyCertName(ss->sec.peerCert, hostname); |
|
288 else |
|
289 rv = SECFailure; |
|
290 if (rv != SECSuccess) |
|
291 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); |
|
292 |
|
293 return rv; |
|
294 } |