1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is the Netscape security libraries.
15 *
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36 /* $Id: sslauth.c,v 1.16 2006/04/20 00:20:45 alexei.volkov.bugs%sun.com Exp $ */
37 #include "cert.h"
38 #include "secitem.h"
39 #include "ssl.h"
40 #include "sslimpl.h"
41 #include "sslproto.h"
42 #include "pk11func.h"
43
44 /* NEED LOCKS IN HERE. */
45 CERTCertificate *
SSL_PeerCertificate(PRFileDesc * fd)46 SSL_PeerCertificate(PRFileDesc *fd)
47 {
48 sslSocket *ss;
49
50 ss = ssl_FindSocket(fd);
51 if (!ss) {
52 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
53 SSL_GETPID(), fd));
54 return 0;
55 }
56 if (ss->opt.useSecurity && ss->sec.peerCert) {
57 return CERT_DupCertificate(ss->sec.peerCert);
58 }
59 return 0;
60 }
61
62 /* NEED LOCKS IN HERE. */
63 CERTCertificate *
SSL_LocalCertificate(PRFileDesc * fd)64 SSL_LocalCertificate(PRFileDesc *fd)
65 {
66 sslSocket *ss;
67
68 ss = ssl_FindSocket(fd);
69 if (!ss) {
70 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
71 SSL_GETPID(), fd));
72 return NULL;
73 }
74 if (ss->opt.useSecurity) {
75 if (ss->sec.localCert) {
76 return CERT_DupCertificate(ss->sec.localCert);
77 }
78 if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) {
79 return CERT_DupCertificate(ss->sec.ci.sid->localCert);
80 }
81 }
82 return NULL;
83 }
84
85
86
87 /* NEED LOCKS IN HERE. */
88 SECStatus
SSL_SecurityStatus(PRFileDesc * fd,int * op,char ** cp,int * kp0,int * kp1,char ** ip,char ** sp)89 SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
90 char **ip, char **sp)
91 {
92 sslSocket *ss;
93 const char *cipherName;
94 PRBool isDes = PR_FALSE;
95
96 ss = ssl_FindSocket(fd);
97 if (!ss) {
98 SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
99 SSL_GETPID(), fd));
100 return SECFailure;
101 }
102
103 if (cp) *cp = 0;
104 if (kp0) *kp0 = 0;
105 if (kp1) *kp1 = 0;
106 if (ip) *ip = 0;
107 if (sp) *sp = 0;
108 if (op) {
109 *op = SSL_SECURITY_STATUS_OFF;
110 }
111
112 if (ss->opt.useSecurity && ss->firstHsDone) {
113
114 if (ss->version < SSL_LIBRARY_VERSION_3_0) {
115 cipherName = ssl_cipherName[ss->sec.cipherType];
116 } else {
117 cipherName = ssl3_cipherName[ss->sec.cipherType];
118 }
119 PORT_Assert(cipherName);
120 if (cipherName) {
121 if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;
122
123 if (cp) {
124 *cp = PORT_Strdup(cipherName);
125 }
126 }
127
128 if (kp0) {
129 *kp0 = ss->sec.keyBits;
130 if (isDes) *kp0 = (*kp0 * 7) / 8;
131 }
132 if (kp1) {
133 *kp1 = ss->sec.secretKeyBits;
134 if (isDes) *kp1 = (*kp1 * 7) / 8;
135 }
136 if (op) {
137 if (ss->sec.keyBits == 0) {
138 *op = SSL_SECURITY_STATUS_OFF;
139 } else if (ss->sec.secretKeyBits < 90) {
140 *op = SSL_SECURITY_STATUS_ON_LOW;
141
142 } else {
143 *op = SSL_SECURITY_STATUS_ON_HIGH;
144 }
145 }
146
147 if (ip || sp) {
148 CERTCertificate *cert;
149
150 cert = ss->sec.peerCert;
151 if (cert) {
152 if (ip) {
153 *ip = CERT_NameToAscii(&cert->issuer);
154 }
155 if (sp) {
156 *sp = CERT_NameToAscii(&cert->subject);
157 }
158 } else {
159 if (ip) {
160 *ip = PORT_Strdup("no certificate");
161 }
162 if (sp) {
163 *sp = PORT_Strdup("no certificate");
164 }
165 }
166 }
167 }
168
169 return SECSuccess;
170 }
171
172 /************************************************************************/
173
174 /* NEED LOCKS IN HERE. */
175 SECStatus
SSL_AuthCertificateHook(PRFileDesc * s,SSLAuthCertificate func,void * arg)176 SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
177 {
178 sslSocket *ss;
179
180 ss = ssl_FindSocket(s);
181 if (!ss) {
182 SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook",
183 SSL_GETPID(), s));
184 return SECFailure;
185 }
186
187 ss->authCertificate = func;
188 ss->authCertificateArg = arg;
189
190 return SECSuccess;
191 }
192
193 /* NEED LOCKS IN HERE. */
194 SECStatus
SSL_GetClientAuthDataHook(PRFileDesc * s,SSLGetClientAuthData func,void * arg)195 SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
196 void *arg)
197 {
198 sslSocket *ss;
199
200 ss = ssl_FindSocket(s);
201 if (!ss) {
202 SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
203 SSL_GETPID(), s));
204 return SECFailure;
205 }
206
207 ss->getClientAuthData = func;
208 ss->getClientAuthDataArg = arg;
209 return SECSuccess;
210 }
211
212 /* NEED LOCKS IN HERE. */
213 SECStatus
SSL_SetPKCS11PinArg(PRFileDesc * s,void * arg)214 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
215 {
216 sslSocket *ss;
217
218 ss = ssl_FindSocket(s);
219 if (!ss) {
220 SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
221 SSL_GETPID(), s));
222 return SECFailure;
223 }
224
225 ss->pkcs11PinArg = arg;
226 return SECSuccess;
227 }
228
229
230 /* This is the "default" authCert callback function. It is called when a
231 * certificate message is received from the peer and the local application
232 * has not registered an authCert callback function.
233 */
234 SECStatus
SSL_AuthCertificate(void * arg,PRFileDesc * fd,PRBool checkSig,PRBool isServer)235 SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
236 {
237 SECStatus rv;
238 CERTCertDBHandle * handle;
239 sslSocket * ss;
240 SECCertUsage certUsage;
241 const char * hostname = NULL;
242
243 ss = ssl_FindSocket(fd);
244 PORT_Assert(ss != NULL);
245 if (!ss) {
246 return SECFailure;
247 }
248
249 handle = (CERTCertDBHandle *)arg;
250
251 /* this may seem backwards, but isn't. */
252 certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
253
254 rv = CERT_VerifyCertNow(handle, ss->sec.peerCert, checkSig, certUsage,
255 ss->pkcs11PinArg);
256
257 if ( rv != SECSuccess || isServer )
258 return rv;
259
260 /* cert is OK. This is the client side of an SSL connection.
261 * Now check the name field in the cert against the desired hostname.
262 * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
263 */
264 hostname = ss->url;
265 if (hostname && hostname[0])
266 rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
267 else
268 rv = SECFailure;
269 if (rv != SECSuccess)
270 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
271
272 return rv;
273 }
274