security/nss/lib/ssl/sslauth.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 #include "cert.h"
michael@0 5 #include "secitem.h"
michael@0 6 #include "ssl.h"
michael@0 7 #include "sslimpl.h"
michael@0 8 #include "sslproto.h"
michael@0 9 #include "pk11func.h"
michael@0 10 #include "ocsp.h"
michael@0 11
michael@0 12 /* NEED LOCKS IN HERE. */
michael@0 13 CERTCertificate *
michael@0 14 SSL_PeerCertificate(PRFileDesc *fd)
michael@0 15 {
michael@0 16 sslSocket *ss;
michael@0 17
michael@0 18 ss = ssl_FindSocket(fd);
michael@0 19 if (!ss) {
michael@0 20 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
michael@0 21 SSL_GETPID(), fd));
michael@0 22 return 0;
michael@0 23 }
michael@0 24 if (ss->opt.useSecurity && ss->sec.peerCert) {
michael@0 25 return CERT_DupCertificate(ss->sec.peerCert);
michael@0 26 }
michael@0 27 return 0;
michael@0 28 }
michael@0 29
michael@0 30 /* NEED LOCKS IN HERE. */
michael@0 31 CERTCertList *
michael@0 32 SSL_PeerCertificateChain(PRFileDesc *fd)
michael@0 33 {
michael@0 34 sslSocket *ss;
michael@0 35 CERTCertList *chain = NULL;
michael@0 36 CERTCertificate *cert;
michael@0 37 ssl3CertNode *cur;
michael@0 38
michael@0 39 ss = ssl_FindSocket(fd);
michael@0 40 if (!ss) {
michael@0 41 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain",
michael@0 42 SSL_GETPID(), fd));
michael@0 43 return NULL;
michael@0 44 }
michael@0 45 if (!ss->opt.useSecurity || !ss->sec.peerCert) {
michael@0 46 PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
michael@0 47 return NULL;
michael@0 48 }
michael@0 49 chain = CERT_NewCertList();
michael@0 50 if (!chain) {
michael@0 51 return NULL;
michael@0 52 }
michael@0 53 cert = CERT_DupCertificate(ss->sec.peerCert);
michael@0 54 if (CERT_AddCertToListTail(chain, cert) != SECSuccess) {
michael@0 55 goto loser;
michael@0 56 }
michael@0 57 for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
michael@0 58 cert = CERT_DupCertificate(cur->cert);
michael@0 59 if (CERT_AddCertToListTail(chain, cert) != SECSuccess) {
michael@0 60 goto loser;
michael@0 61 }
michael@0 62 }
michael@0 63 return chain;
michael@0 64
michael@0 65 loser:
michael@0 66 CERT_DestroyCertList(chain);
michael@0 67 return NULL;
michael@0 68 }
michael@0 69
michael@0 70 /* NEED LOCKS IN HERE. */
michael@0 71 CERTCertificate *
michael@0 72 SSL_LocalCertificate(PRFileDesc *fd)
michael@0 73 {
michael@0 74 sslSocket *ss;
michael@0 75
michael@0 76 ss = ssl_FindSocket(fd);
michael@0 77 if (!ss) {
michael@0 78 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
michael@0 79 SSL_GETPID(), fd));
michael@0 80 return NULL;
michael@0 81 }
michael@0 82 if (ss->opt.useSecurity) {
michael@0 83 if (ss->sec.localCert) {
michael@0 84 return CERT_DupCertificate(ss->sec.localCert);
michael@0 85 }
michael@0 86 if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) {
michael@0 87 return CERT_DupCertificate(ss->sec.ci.sid->localCert);
michael@0 88 }
michael@0 89 }
michael@0 90 return NULL;
michael@0 91 }
michael@0 92
michael@0 93
michael@0 94
michael@0 95 /* NEED LOCKS IN HERE. */
michael@0 96 SECStatus
michael@0 97 SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
michael@0 98 char **ip, char **sp)
michael@0 99 {
michael@0 100 sslSocket *ss;
michael@0 101 const char *cipherName;
michael@0 102 PRBool isDes = PR_FALSE;
michael@0 103
michael@0 104 ss = ssl_FindSocket(fd);
michael@0 105 if (!ss) {
michael@0 106 SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
michael@0 107 SSL_GETPID(), fd));
michael@0 108 return SECFailure;
michael@0 109 }
michael@0 110
michael@0 111 if (cp) *cp = 0;
michael@0 112 if (kp0) *kp0 = 0;
michael@0 113 if (kp1) *kp1 = 0;
michael@0 114 if (ip) *ip = 0;
michael@0 115 if (sp) *sp = 0;
michael@0 116 if (op) {
michael@0 117 *op = SSL_SECURITY_STATUS_OFF;
michael@0 118 }
michael@0 119
michael@0 120 if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
michael@0 121 if (ss->version < SSL_LIBRARY_VERSION_3_0) {
michael@0 122 cipherName = ssl_cipherName[ss->sec.cipherType];
michael@0 123 } else {
michael@0 124 cipherName = ssl3_cipherName[ss->sec.cipherType];
michael@0 125 }
michael@0 126 PORT_Assert(cipherName);
michael@0 127 if (cipherName) {
michael@0 128 if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;
michael@0 129
michael@0 130 if (cp) {
michael@0 131 *cp = PORT_Strdup(cipherName);
michael@0 132 }
michael@0 133 }
michael@0 134
michael@0 135 if (kp0) {
michael@0 136 *kp0 = ss->sec.keyBits;
michael@0 137 if (isDes) *kp0 = (*kp0 * 7) / 8;
michael@0 138 }
michael@0 139 if (kp1) {
michael@0 140 *kp1 = ss->sec.secretKeyBits;
michael@0 141 if (isDes) *kp1 = (*kp1 * 7) / 8;
michael@0 142 }
michael@0 143 if (op) {
michael@0 144 if (ss->sec.keyBits == 0) {
michael@0 145 *op = SSL_SECURITY_STATUS_OFF;
michael@0 146 } else if (ss->sec.secretKeyBits < 90) {
michael@0 147 *op = SSL_SECURITY_STATUS_ON_LOW;
michael@0 148
michael@0 149 } else {
michael@0 150 *op = SSL_SECURITY_STATUS_ON_HIGH;
michael@0 151 }
michael@0 152 }
michael@0 153
michael@0 154 if (ip || sp) {
michael@0 155 CERTCertificate *cert;
michael@0 156
michael@0 157 cert = ss->sec.peerCert;
michael@0 158 if (cert) {
michael@0 159 if (ip) {
michael@0 160 *ip = CERT_NameToAscii(&cert->issuer);
michael@0 161 }
michael@0 162 if (sp) {
michael@0 163 *sp = CERT_NameToAscii(&cert->subject);
michael@0 164 }
michael@0 165 } else {
michael@0 166 if (ip) {
michael@0 167 *ip = PORT_Strdup("no certificate");
michael@0 168 }
michael@0 169 if (sp) {
michael@0 170 *sp = PORT_Strdup("no certificate");
michael@0 171 }
michael@0 172 }
michael@0 173 }
michael@0 174 }
michael@0 175
michael@0 176 return SECSuccess;
michael@0 177 }
michael@0 178
michael@0 179 /************************************************************************/
michael@0 180
michael@0 181 /* NEED LOCKS IN HERE. */
michael@0 182 SECStatus
michael@0 183 SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
michael@0 184 {
michael@0 185 sslSocket *ss;
michael@0 186
michael@0 187 ss = ssl_FindSocket(s);
michael@0 188 if (!ss) {
michael@0 189 SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook",
michael@0 190 SSL_GETPID(), s));
michael@0 191 return SECFailure;
michael@0 192 }
michael@0 193
michael@0 194 ss->authCertificate = func;
michael@0 195 ss->authCertificateArg = arg;
michael@0 196
michael@0 197 return SECSuccess;
michael@0 198 }
michael@0 199
michael@0 200 /* NEED LOCKS IN HERE. */
michael@0 201 SECStatus
michael@0 202 SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
michael@0 203 void *arg)
michael@0 204 {
michael@0 205 sslSocket *ss;
michael@0 206
michael@0 207 ss = ssl_FindSocket(s);
michael@0 208 if (!ss) {
michael@0 209 SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
michael@0 210 SSL_GETPID(), s));
michael@0 211 return SECFailure;
michael@0 212 }
michael@0 213
michael@0 214 ss->getClientAuthData = func;
michael@0 215 ss->getClientAuthDataArg = arg;
michael@0 216 return SECSuccess;
michael@0 217 }
michael@0 218
michael@0 219 /* NEED LOCKS IN HERE. */
michael@0 220 SECStatus
michael@0 221 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
michael@0 222 {
michael@0 223 sslSocket *ss;
michael@0 224
michael@0 225 ss = ssl_FindSocket(s);
michael@0 226 if (!ss) {
michael@0 227 SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
michael@0 228 SSL_GETPID(), s));
michael@0 229 return SECFailure;
michael@0 230 }
michael@0 231
michael@0 232 ss->pkcs11PinArg = arg;
michael@0 233 return SECSuccess;
michael@0 234 }
michael@0 235
michael@0 236
michael@0 237 /* This is the "default" authCert callback function. It is called when a
michael@0 238 * certificate message is received from the peer and the local application
michael@0 239 * has not registered an authCert callback function.
michael@0 240 */
michael@0 241 SECStatus
michael@0 242 SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
michael@0 243 {
michael@0 244 SECStatus rv;
michael@0 245 CERTCertDBHandle * handle;
michael@0 246 sslSocket * ss;
michael@0 247 SECCertUsage certUsage;
michael@0 248 const char * hostname = NULL;
michael@0 249 PRTime now = PR_Now();
michael@0 250 SECItemArray * certStatusArray;
michael@0 251
michael@0 252 ss = ssl_FindSocket(fd);
michael@0 253 PORT_Assert(ss != NULL);
michael@0 254 if (!ss) {
michael@0 255 return SECFailure;
michael@0 256 }
michael@0 257
michael@0 258 handle = (CERTCertDBHandle *)arg;
michael@0 259 certStatusArray = &ss->sec.ci.sid->peerCertStatus;
michael@0 260
michael@0 261 if (certStatusArray->len) {
michael@0 262 PORT_SetError(0);
michael@0 263 if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now,
michael@0 264 &certStatusArray->items[0],
michael@0 265 ss->pkcs11PinArg)
michael@0 266 != SECSuccess) {
michael@0 267 PRErrorCode error = PR_GetError();
michael@0 268 PORT_Assert(error != 0);
michael@0 269 }
michael@0 270 }
michael@0 271
michael@0 272 /* this may seem backwards, but isn't. */
michael@0 273 certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
michael@0 274
michael@0 275 rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
michael@0 276 now, ss->pkcs11PinArg, NULL);
michael@0 277
michael@0 278 if ( rv != SECSuccess || isServer )
michael@0 279 return rv;
michael@0 280
michael@0 281 /* cert is OK. This is the client side of an SSL connection.
michael@0 282 * Now check the name field in the cert against the desired hostname.
michael@0 283 * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
michael@0 284 */
michael@0 285 hostname = ss->url;
michael@0 286 if (hostname && hostname[0])
michael@0 287 rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
michael@0 288 else
michael@0 289 rv = SECFailure;
michael@0 290 if (rv != SECSuccess)
michael@0 291 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
michael@0 292
michael@0 293 return rv;
michael@0 294 }

mercurial