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