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 * 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 * 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 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 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 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 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 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