security/nss/lib/ssl/sslauth.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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"
    12 /* NEED LOCKS IN HERE.  */
    13 CERTCertificate *
    14 SSL_PeerCertificate(PRFileDesc *fd)
    15 {
    16     sslSocket *ss;
    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 }
    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;
    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;
    65 loser:
    66     CERT_DestroyCertList(chain);
    67     return NULL;
    68 }
    70 /* NEED LOCKS IN HERE.  */
    71 CERTCertificate *
    72 SSL_LocalCertificate(PRFileDesc *fd)
    73 {
    74     sslSocket *ss;
    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 }
    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;
   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     }
   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     }
   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;
   130             if (cp) {
   131                 *cp = PORT_Strdup(cipherName);
   132             }
   133         }
   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;
   149 	    } else {
   150 		*op = SSL_SECURITY_STATUS_ON_HIGH;
   151 	    }
   152 	}
   154 	if (ip || sp) {
   155 	    CERTCertificate *cert;
   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     }
   176     return SECSuccess;
   177 }
   179 /************************************************************************/
   181 /* NEED LOCKS IN HERE.  */
   182 SECStatus
   183 SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
   184 {
   185     sslSocket *ss;
   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     }
   194     ss->authCertificate = func;
   195     ss->authCertificateArg = arg;
   197     return SECSuccess;
   198 }
   200 /* NEED LOCKS IN HERE.  */
   201 SECStatus 
   202 SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
   203 			      void *arg)
   204 {
   205     sslSocket *ss;
   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     }
   214     ss->getClientAuthData = func;
   215     ss->getClientAuthDataArg = arg;
   216     return SECSuccess;
   217 }
   219 /* NEED LOCKS IN HERE.  */
   220 SECStatus 
   221 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
   222 {
   223     sslSocket *ss;
   225     ss = ssl_FindSocket(s);
   226     if (!ss) {
   227 	SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
   228 		 SSL_GETPID(), s));
   229 	return SECFailure;
   230     }
   232     ss->pkcs11PinArg = arg;
   233     return SECSuccess;
   234 }
   237 /* This is the "default" authCert callback function.  It is called when a 
   238  * certificate message is received from the peer and the local application
   239  * has not registered an authCert callback function.
   240  */
   241 SECStatus
   242 SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
   243 {
   244     SECStatus          rv;
   245     CERTCertDBHandle * handle;
   246     sslSocket *        ss;
   247     SECCertUsage       certUsage;
   248     const char *       hostname    = NULL;
   249     PRTime             now = PR_Now();
   250     SECItemArray *     certStatusArray;
   252     ss = ssl_FindSocket(fd);
   253     PORT_Assert(ss != NULL);
   254     if (!ss) {
   255 	return SECFailure;
   256     }
   258     handle = (CERTCertDBHandle *)arg;
   259     certStatusArray = &ss->sec.ci.sid->peerCertStatus;
   261     if (certStatusArray->len) {
   262 	PORT_SetError(0);
   263 	if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now,
   264 						  &certStatusArray->items[0],
   265 						  ss->pkcs11PinArg)
   266 		!= SECSuccess) {
   267 	    PRErrorCode error = PR_GetError();
   268 	    PORT_Assert(error != 0);
   269 	}
   270     }
   272     /* this may seem backwards, but isn't. */
   273     certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
   275     rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
   276 			 now, ss->pkcs11PinArg, NULL);
   278     if ( rv != SECSuccess || isServer )
   279 	return rv;
   281     /* cert is OK.  This is the client side of an SSL connection.
   282      * Now check the name field in the cert against the desired hostname.
   283      * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
   284      */
   285     hostname = ss->url;
   286     if (hostname && hostname[0])
   287 	rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
   288     else 
   289 	rv = SECFailure;
   290     if (rv != SECSuccess)
   291 	PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
   293     return rv;
   294 }

mercurial