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 SECStatus
     32 SSL_PeerCertificateChain(PRFileDesc *fd, CERTCertificate **certs,
     33 			 unsigned int *numCerts, unsigned int maxNumCerts)
     34 {
     35     sslSocket *ss;
     36     ssl3CertNode* cur;
     37 
     38     ss = ssl_FindSocket(fd);
     39     if (!ss) {
     40 	SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain",
     41 		 SSL_GETPID(), fd));
     42 	return SECFailure;
     43     }
     44     if (!ss->opt.useSecurity)
     45 	return SECFailure;
     46 
     47     if (ss->sec.peerCert == NULL) {
     48       *numCerts = 0;
     49       return SECSuccess;
     50     }
     51 
     52     *numCerts = 1;  /* for the leaf certificate */
     53     if (maxNumCerts > 0)
     54 	certs[0] = CERT_DupCertificate(ss->sec.peerCert);
     55 
     56     for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
     57 	if (*numCerts < maxNumCerts)
     58 	    certs[*numCerts] = CERT_DupCertificate(cur->cert);
     59 	(*numCerts)++;
     60     }
     61 
     62     return SECSuccess;
     63 }
     64 
     65 /* NEED LOCKS IN HERE.  */
     66 CERTCertificate *
     67 SSL_LocalCertificate(PRFileDesc *fd)
     68 {
     69     sslSocket *ss;
     70 
     71     ss = ssl_FindSocket(fd);
     72     if (!ss) {
     73 	SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
     74 		 SSL_GETPID(), fd));
     75 	return NULL;
     76     }
     77     if (ss->opt.useSecurity) {
     78     	if (ss->sec.localCert) {
     79 	    return CERT_DupCertificate(ss->sec.localCert);
     80 	}
     81 	if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) {
     82 	    return CERT_DupCertificate(ss->sec.ci.sid->localCert);
     83 	}
     84     }
     85     return NULL;
     86 }
     87 
     88 
     89 
     90 /* NEED LOCKS IN HERE.  */
     91 SECStatus
     92 SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
     93 		   char **ip, char **sp)
     94 {
     95     sslSocket *ss;
     96     const char *cipherName;
     97     PRBool isDes = PR_FALSE;
     98     PRBool enoughFirstHsDone = PR_FALSE;
     99 
    100     ss = ssl_FindSocket(fd);
    101     if (!ss) {
    102 	SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
    103 		 SSL_GETPID(), fd));
    104 	return SECFailure;
    105     }
    106 
    107     if (cp) *cp = 0;
    108     if (kp0) *kp0 = 0;
    109     if (kp1) *kp1 = 0;
    110     if (ip) *ip = 0;
    111     if (sp) *sp = 0;
    112     if (op) {
    113 	*op = SSL_SECURITY_STATUS_OFF;
    114     }
    115 
    116     if (ss->firstHsDone) {
    117 	enoughFirstHsDone = PR_TRUE;
    118     } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
    119 	       ssl3_CanFalseStart(ss)) {
    120 	enoughFirstHsDone = PR_TRUE;
    121     }
    122 
    123     if (ss->opt.useSecurity && enoughFirstHsDone) {
    124 	if (ss->version < SSL_LIBRARY_VERSION_3_0) {
    125 	    cipherName = ssl_cipherName[ss->sec.cipherType];
    126 	} else {
    127 	    cipherName = ssl3_cipherName[ss->sec.cipherType];
    128 	}
    129 	PORT_Assert(cipherName);
    130 	if (cipherName) {
    131             if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;
    132 
    133             if (cp) {
    134                 *cp = PORT_Strdup(cipherName);
    135             }
    136         }
    137 
    138 	if (kp0) {
    139 	    *kp0 = ss->sec.keyBits;
    140 	    if (isDes) *kp0 = (*kp0 * 7) / 8;
    141 	}
    142 	if (kp1) {
    143 	    *kp1 = ss->sec.secretKeyBits;
    144 	    if (isDes) *kp1 = (*kp1 * 7) / 8;
    145 	}
    146 	if (op) {
    147 	    if (ss->sec.keyBits == 0) {
    148 		*op = SSL_SECURITY_STATUS_OFF;
    149 	    } else if (ss->sec.secretKeyBits < 90) {
    150 		*op = SSL_SECURITY_STATUS_ON_LOW;
    151 
    152 	    } else {
    153 		*op = SSL_SECURITY_STATUS_ON_HIGH;
    154 	    }
    155 	}
    156 
    157 	if (ip || sp) {
    158 	    CERTCertificate *cert;
    159 
    160 	    cert = ss->sec.peerCert;
    161 	    if (cert) {
    162 		if (ip) {
    163 		    *ip = CERT_NameToAscii(&cert->issuer);
    164 		}
    165 		if (sp) {
    166 		    *sp = CERT_NameToAscii(&cert->subject);
    167 		}
    168 	    } else {
    169 		if (ip) {
    170 		    *ip = PORT_Strdup("no certificate");
    171 		}
    172 		if (sp) {
    173 		    *sp = PORT_Strdup("no certificate");
    174 		}
    175 	    }
    176 	}
    177     }
    178 
    179     return SECSuccess;
    180 }
    181 
    182 /************************************************************************/
    183 
    184 /* NEED LOCKS IN HERE.  */
    185 SECStatus
    186 SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
    187 {
    188     sslSocket *ss;
    189 
    190     ss = ssl_FindSocket(s);
    191     if (!ss) {
    192 	SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook",
    193 		 SSL_GETPID(), s));
    194 	return SECFailure;
    195     }
    196 
    197     ss->authCertificate = func;
    198     ss->authCertificateArg = arg;
    199 
    200     return SECSuccess;
    201 }
    202 
    203 /* NEED LOCKS IN HERE.  */
    204 SECStatus
    205 SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
    206 			      void *arg)
    207 {
    208     sslSocket *ss;
    209 
    210     ss = ssl_FindSocket(s);
    211     if (!ss) {
    212 	SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
    213 		 SSL_GETPID(), s));
    214 	return SECFailure;
    215     }
    216 
    217     ss->getClientAuthData = func;
    218     ss->getClientAuthDataArg = arg;
    219     return SECSuccess;
    220 }
    221 
    222 SECStatus
    223 SSL_SetClientChannelIDCallback(PRFileDesc *fd,
    224 			       SSLClientChannelIDCallback callback,
    225 			       void *arg) {
    226     sslSocket *ss = ssl_FindSocket(fd);
    227 
    228     if (!ss) {
    229 	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback",
    230 		 SSL_GETPID(), fd));
    231 	return SECFailure;
    232     }
    233 
    234     ss->getChannelID = callback;
    235     ss->getChannelIDArg = arg;
    236 
    237     return SECSuccess;
    238 }
    239 
    240 #ifdef NSS_PLATFORM_CLIENT_AUTH
    241 /* NEED LOCKS IN HERE.  */
    242 SECStatus
    243 SSL_GetPlatformClientAuthDataHook(PRFileDesc *s,
    244                                   SSLGetPlatformClientAuthData func,
    245                                   void *arg)
    246 {
    247     sslSocket *ss;
    248 
    249     ss = ssl_FindSocket(s);
    250     if (!ss) {
    251 	SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook",
    252 		 SSL_GETPID(), s));
    253 	return SECFailure;
    254     }
    255 
    256     ss->getPlatformClientAuthData = func;
    257     ss->getPlatformClientAuthDataArg = arg;
    258     return SECSuccess;
    259 }
    260 #endif   /* NSS_PLATFORM_CLIENT_AUTH */
    261 
    262 /* NEED LOCKS IN HERE.  */
    263 SECStatus
    264 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
    265 {
    266     sslSocket *ss;
    267 
    268     ss = ssl_FindSocket(s);
    269     if (!ss) {
    270 	SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
    271 		 SSL_GETPID(), s));
    272 	return SECFailure;
    273     }
    274 
    275     ss->pkcs11PinArg = arg;
    276     return SECSuccess;
    277 }
    278 
    279 
    280 /* This is the "default" authCert callback function.  It is called when a
    281  * certificate message is received from the peer and the local application
    282  * has not registered an authCert callback function.
    283  */
    284 SECStatus
    285 SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
    286 {
    287     SECStatus          rv;
    288     CERTCertDBHandle * handle;
    289     sslSocket *        ss;
    290     SECCertUsage       certUsage;
    291     const char *       hostname    = NULL;
    292     PRTime             now = PR_Now();
    293     SECItemArray *     certStatusArray;
    294 
    295     ss = ssl_FindSocket(fd);
    296     PORT_Assert(ss != NULL);
    297     if (!ss) {
    298 	return SECFailure;
    299     }
    300 
    301     handle = (CERTCertDBHandle *)arg;
    302     certStatusArray = &ss->sec.ci.sid->peerCertStatus;
    303 
    304     if (certStatusArray->len) {
    305         CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert,
    306 					now, &certStatusArray->items[0],
    307 					ss->pkcs11PinArg);
    308     }
    309 
    310     /* this may seem backwards, but isn't. */
    311     certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
    312 
    313     rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
    314 			 now, ss->pkcs11PinArg, NULL);
    315 
    316     if ( rv != SECSuccess || isServer )
    317 	return rv;
    318 
    319     /* cert is OK.  This is the client side of an SSL connection.
    320      * Now check the name field in the cert against the desired hostname.
    321      * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
    322      */
    323     hostname = ss->url;
    324     if (hostname && hostname[0])
    325 	rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
    326     else
    327 	rv = SECFailure;
    328     if (rv != SECSuccess)
    329 	PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
    330 
    331     return rv;
    332 }
    333