Home | History | Annotate | Download | only in ssl
      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