2008-06-06 05:40:11 -07:00
|
|
|
/*
|
|
|
|
* vtables (and methods that call through them) for the 4 types of
|
|
|
|
* SSLSockets supported. Only one type is still supported.
|
|
|
|
* Various other functions.
|
|
|
|
*
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Netscape security libraries.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1994-2000
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Dr Stephen Henson <stephen.henson@gemplus.com>
|
|
|
|
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2011-10-22 17:46:33 -07:00
|
|
|
/* $Id: sslsock.c,v 1.75 2011/10/22 16:45:40 emaldona%redhat.com Exp $ */
|
2008-06-06 05:40:11 -07:00
|
|
|
#include "seccomon.h"
|
|
|
|
#include "cert.h"
|
|
|
|
#include "keyhi.h"
|
|
|
|
#include "ssl.h"
|
|
|
|
#include "sslimpl.h"
|
|
|
|
#include "sslproto.h"
|
|
|
|
#include "nspr.h"
|
|
|
|
#include "private/pprio.h"
|
|
|
|
#include "blapi.h"
|
|
|
|
#include "nss.h"
|
|
|
|
|
|
|
|
#define SET_ERROR_CODE /* reminder */
|
|
|
|
|
|
|
|
struct cipherPolicyStr {
|
|
|
|
int cipher;
|
|
|
|
unsigned char export; /* policy value for export policy */
|
|
|
|
unsigned char france; /* policy value for france policy */
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct cipherPolicyStr cipherPolicy;
|
|
|
|
|
|
|
|
/* This table contains two preconfigured policies: Export and France.
|
|
|
|
** It is used only by the functions SSL_SetDomesticPolicy,
|
|
|
|
** SSL_SetExportPolicy, and SSL_SetFrancyPolicy.
|
|
|
|
** Order of entries is not important.
|
|
|
|
*/
|
|
|
|
static cipherPolicy ssl_ciphers[] = { /* Export France */
|
|
|
|
{ SSL_EN_RC4_128_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ SSL_EN_RC2_128_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ SSL_EN_DES_64_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_WITH_RC4_128_MD5, SSL_RESTRICTED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_WITH_RC4_128_SHA, SSL_RESTRICTED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RESTRICTED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_DSS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ SSL_RSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ SSL_RSA_WITH_NULL_MD5, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
2009-01-20 19:43:31 -08:00
|
|
|
{ TLS_RSA_WITH_SEED_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
2008-06-06 05:40:11 -07:00
|
|
|
{ TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
#ifdef NSS_ENABLE_ECC
|
|
|
|
{ TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ TLS_ECDH_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDH_RSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED },
|
|
|
|
{ TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
|
|
|
|
#endif /* NSS_ENABLE_ECC */
|
|
|
|
{ 0, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const sslSocketOps ssl_default_ops = { /* No SSL. */
|
|
|
|
ssl_DefConnect,
|
|
|
|
NULL,
|
|
|
|
ssl_DefBind,
|
|
|
|
ssl_DefListen,
|
|
|
|
ssl_DefShutdown,
|
|
|
|
ssl_DefClose,
|
|
|
|
ssl_DefRecv,
|
|
|
|
ssl_DefSend,
|
|
|
|
ssl_DefRead,
|
|
|
|
ssl_DefWrite,
|
|
|
|
ssl_DefGetpeername,
|
|
|
|
ssl_DefGetsockname
|
|
|
|
};
|
|
|
|
|
|
|
|
static const sslSocketOps ssl_secure_ops = { /* SSL. */
|
|
|
|
ssl_SecureConnect,
|
|
|
|
NULL,
|
|
|
|
ssl_DefBind,
|
|
|
|
ssl_DefListen,
|
|
|
|
ssl_SecureShutdown,
|
|
|
|
ssl_SecureClose,
|
|
|
|
ssl_SecureRecv,
|
|
|
|
ssl_SecureSend,
|
|
|
|
ssl_SecureRead,
|
|
|
|
ssl_SecureWrite,
|
|
|
|
ssl_DefGetpeername,
|
|
|
|
ssl_DefGetsockname
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
** default settings for socket enables
|
|
|
|
*/
|
|
|
|
static sslOptions ssl_defaults = {
|
|
|
|
PR_TRUE, /* useSecurity */
|
|
|
|
PR_FALSE, /* useSocks */
|
|
|
|
PR_FALSE, /* requestCertificate */
|
|
|
|
2, /* requireCertificate */
|
|
|
|
PR_FALSE, /* handshakeAsClient */
|
|
|
|
PR_FALSE, /* handshakeAsServer */
|
2011-10-07 13:37:26 -07:00
|
|
|
PR_FALSE, /* enableSSL2 */ /* now defaults to off in NSS 3.13 */
|
2008-06-06 05:40:11 -07:00
|
|
|
PR_TRUE, /* enableSSL3 */
|
|
|
|
PR_TRUE, /* enableTLS */ /* now defaults to on in NSS 3.0 */
|
|
|
|
PR_FALSE, /* noCache */
|
|
|
|
PR_FALSE, /* fdx */
|
2011-10-07 13:37:26 -07:00
|
|
|
PR_FALSE, /* v2CompatibleHello */ /* now defaults to off in NSS 3.13 */
|
2008-06-06 05:40:11 -07:00
|
|
|
PR_TRUE, /* detectRollBack */
|
|
|
|
PR_FALSE, /* noStepDown */
|
|
|
|
PR_FALSE, /* bypassPKCS11 */
|
|
|
|
PR_FALSE, /* noLocks */
|
|
|
|
PR_FALSE, /* enableSessionTickets */
|
2010-02-07 03:54:28 -08:00
|
|
|
PR_FALSE, /* enableDeflate */
|
|
|
|
2, /* enableRenegotiation (default: requires extension) */
|
|
|
|
PR_FALSE, /* requireSafeNegotiation */
|
2010-08-02 13:49:18 -07:00
|
|
|
PR_FALSE, /* enableFalseStart */
|
2011-10-07 13:37:26 -07:00
|
|
|
PR_TRUE /* cbcRandomIV */
|
2008-06-06 05:40:11 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
sslSessionIDLookupFunc ssl_sid_lookup;
|
|
|
|
sslSessionIDCacheFunc ssl_sid_cache;
|
|
|
|
sslSessionIDUncacheFunc ssl_sid_uncache;
|
|
|
|
|
|
|
|
static PRBool ssl_inited = PR_FALSE;
|
|
|
|
static PRDescIdentity ssl_layer_id;
|
|
|
|
|
|
|
|
PRBool locksEverDisabled; /* implicitly PR_FALSE */
|
|
|
|
PRBool ssl_force_locks; /* implicitly PR_FALSE */
|
|
|
|
int ssl_lock_readers = 1; /* default true. */
|
|
|
|
char ssl_debug;
|
|
|
|
char ssl_trace;
|
|
|
|
FILE * ssl_trace_iob;
|
2010-02-07 03:54:28 -08:00
|
|
|
FILE * ssl_keylog_iob;
|
2008-06-06 05:40:11 -07:00
|
|
|
char lockStatus[] = "Locks are ENABLED. ";
|
|
|
|
#define LOCKSTATUS_OFFSET 10 /* offset of ENABLED */
|
|
|
|
|
|
|
|
/* forward declarations. */
|
|
|
|
static sslSocket *ssl_NewSocket(PRBool makeLocks);
|
|
|
|
static SECStatus ssl_MakeLocks(sslSocket *ss);
|
Bug 673382: Update NSS to NSS_3_12_11_BETA1, which includes the fixes for
Bug 661609, Bug 650276 (code not used by Mozilla), Bug 602509, Bug 655411,
Bug 655850, Bug 671711, Bug 617565, Bug 668001, Bug 346583, Bug 661061.
2011-07-27 09:07:32 -07:00
|
|
|
static void ssl_SetDefaultsFromEnvironment(void);
|
2008-06-06 05:40:11 -07:00
|
|
|
static PRStatus ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack,
|
|
|
|
PRDescIdentity id);
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Lookup a socket structure from a file descriptor.
|
|
|
|
** Only functions called through the PRIOMethods table should use this.
|
|
|
|
** Other app-callable functions should use ssl_FindSocket.
|
|
|
|
*/
|
|
|
|
static sslSocket *
|
|
|
|
ssl_GetPrivate(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
|
|
|
|
PORT_Assert(fd != NULL);
|
|
|
|
PORT_Assert(fd->methods->file_type == PR_DESC_LAYERED);
|
|
|
|
PORT_Assert(fd->identity == ssl_layer_id);
|
|
|
|
|
|
|
|
if (fd->methods->file_type != PR_DESC_LAYERED ||
|
|
|
|
fd->identity != ssl_layer_id) {
|
|
|
|
PORT_SetError(PR_BAD_DESCRIPTOR_ERROR);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss = (sslSocket *)fd->secret;
|
|
|
|
ss->fd = fd;
|
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function tries to find the SSL layer in the stack.
|
|
|
|
* It searches for the first SSL layer at or below the argument fd,
|
|
|
|
* and failing that, it searches for the nearest SSL layer above the
|
|
|
|
* argument fd. It returns the private sslSocket from the found layer.
|
|
|
|
*/
|
|
|
|
sslSocket *
|
|
|
|
ssl_FindSocket(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
PRFileDesc *layer;
|
|
|
|
sslSocket *ss;
|
|
|
|
|
|
|
|
PORT_Assert(fd != NULL);
|
|
|
|
PORT_Assert(ssl_layer_id != 0);
|
|
|
|
|
|
|
|
layer = PR_GetIdentitiesLayer(fd, ssl_layer_id);
|
|
|
|
if (layer == NULL) {
|
|
|
|
PORT_SetError(PR_BAD_DESCRIPTOR_ERROR);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss = (sslSocket *)layer->secret;
|
|
|
|
ss->fd = layer;
|
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
|
|
|
|
sslSocket *
|
|
|
|
ssl_DupSocket(sslSocket *os)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
SECStatus rv;
|
|
|
|
|
|
|
|
ss = ssl_NewSocket((PRBool)(!os->opt.noLocks));
|
|
|
|
if (ss) {
|
|
|
|
ss->opt = os->opt;
|
|
|
|
ss->opt.useSocks = PR_FALSE;
|
|
|
|
|
|
|
|
ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
|
|
|
|
ss->url = !os->url ? NULL : PORT_Strdup(os->url);
|
|
|
|
|
|
|
|
ss->ops = os->ops;
|
|
|
|
ss->rTimeout = os->rTimeout;
|
|
|
|
ss->wTimeout = os->wTimeout;
|
|
|
|
ss->cTimeout = os->cTimeout;
|
|
|
|
ss->dbHandle = os->dbHandle;
|
|
|
|
|
|
|
|
/* copy ssl2&3 policy & prefs, even if it's not selected (yet) */
|
|
|
|
ss->allowedByPolicy = os->allowedByPolicy;
|
|
|
|
ss->maybeAllowedByPolicy= os->maybeAllowedByPolicy;
|
|
|
|
ss->chosenPreference = os->chosenPreference;
|
|
|
|
PORT_Memcpy(ss->cipherSuites, os->cipherSuites, sizeof os->cipherSuites);
|
|
|
|
|
|
|
|
if (os->cipherSpecs) {
|
|
|
|
ss->cipherSpecs = (unsigned char*)PORT_Alloc(os->sizeCipherSpecs);
|
|
|
|
if (ss->cipherSpecs)
|
|
|
|
PORT_Memcpy(ss->cipherSpecs, os->cipherSpecs,
|
|
|
|
os->sizeCipherSpecs);
|
|
|
|
ss->sizeCipherSpecs = os->sizeCipherSpecs;
|
|
|
|
ss->preferredCipher = os->preferredCipher;
|
|
|
|
} else {
|
|
|
|
ss->cipherSpecs = NULL; /* produced lazily */
|
|
|
|
ss->sizeCipherSpecs = 0;
|
|
|
|
ss->preferredCipher = NULL;
|
|
|
|
}
|
|
|
|
if (ss->opt.useSecurity) {
|
|
|
|
/* This int should be SSLKEAType, but CC on Irix complains,
|
|
|
|
* during the for loop.
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
sslServerCerts * oc = os->serverCerts;
|
|
|
|
sslServerCerts * sc = ss->serverCerts;
|
2010-02-07 03:54:28 -08:00
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
for (i=kt_null; i < kt_kea_size; i++, oc++, sc++) {
|
|
|
|
if (oc->serverCert && oc->serverCertChain) {
|
|
|
|
sc->serverCert = CERT_DupCertificate(oc->serverCert);
|
|
|
|
sc->serverCertChain = CERT_DupCertList(oc->serverCertChain);
|
|
|
|
if (!sc->serverCertChain)
|
|
|
|
goto loser;
|
|
|
|
} else {
|
|
|
|
sc->serverCert = NULL;
|
|
|
|
sc->serverCertChain = NULL;
|
|
|
|
}
|
|
|
|
sc->serverKeyPair = oc->serverKeyPair ?
|
|
|
|
ssl3_GetKeyPairRef(oc->serverKeyPair) : NULL;
|
|
|
|
if (oc->serverKeyPair && !sc->serverKeyPair)
|
|
|
|
goto loser;
|
|
|
|
sc->serverKeyBits = oc->serverKeyBits;
|
|
|
|
}
|
|
|
|
ss->stepDownKeyPair = !os->stepDownKeyPair ? NULL :
|
|
|
|
ssl3_GetKeyPairRef(os->stepDownKeyPair);
|
|
|
|
ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL :
|
|
|
|
ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair);
|
|
|
|
/*
|
2010-07-18 22:45:52 -07:00
|
|
|
* XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL.
|
2008-06-06 05:40:11 -07:00
|
|
|
* XXX We should detect this, and not just march on with NULL pointers.
|
|
|
|
*/
|
|
|
|
ss->authCertificate = os->authCertificate;
|
|
|
|
ss->authCertificateArg = os->authCertificateArg;
|
|
|
|
ss->getClientAuthData = os->getClientAuthData;
|
|
|
|
ss->getClientAuthDataArg = os->getClientAuthDataArg;
|
2010-02-07 03:54:28 -08:00
|
|
|
ss->sniSocketConfig = os->sniSocketConfig;
|
|
|
|
ss->sniSocketConfigArg = os->sniSocketConfigArg;
|
2008-06-06 05:40:11 -07:00
|
|
|
ss->handleBadCert = os->handleBadCert;
|
|
|
|
ss->badCertArg = os->badCertArg;
|
|
|
|
ss->handshakeCallback = os->handshakeCallback;
|
|
|
|
ss->handshakeCallbackData = os->handshakeCallbackData;
|
|
|
|
ss->pkcs11PinArg = os->pkcs11PinArg;
|
|
|
|
|
|
|
|
/* Create security data */
|
|
|
|
rv = ssl_CopySecurityInfo(ss, os);
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
goto loser;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ss;
|
|
|
|
|
|
|
|
loser:
|
|
|
|
ssl_FreeSocket(ss);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ssl_DestroyLocks(sslSocket *ss)
|
|
|
|
{
|
|
|
|
/* Destroy locks. */
|
|
|
|
if (ss->firstHandshakeLock) {
|
|
|
|
PZ_DestroyMonitor(ss->firstHandshakeLock);
|
|
|
|
ss->firstHandshakeLock = NULL;
|
|
|
|
}
|
|
|
|
if (ss->ssl3HandshakeLock) {
|
|
|
|
PZ_DestroyMonitor(ss->ssl3HandshakeLock);
|
|
|
|
ss->ssl3HandshakeLock = NULL;
|
|
|
|
}
|
|
|
|
if (ss->specLock) {
|
|
|
|
NSSRWLock_Destroy(ss->specLock);
|
|
|
|
ss->specLock = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ss->recvLock) {
|
|
|
|
PZ_DestroyLock(ss->recvLock);
|
|
|
|
ss->recvLock = NULL;
|
|
|
|
}
|
|
|
|
if (ss->sendLock) {
|
|
|
|
PZ_DestroyLock(ss->sendLock);
|
|
|
|
ss->sendLock = NULL;
|
|
|
|
}
|
|
|
|
if (ss->xmitBufLock) {
|
|
|
|
PZ_DestroyMonitor(ss->xmitBufLock);
|
|
|
|
ss->xmitBufLock = NULL;
|
|
|
|
}
|
|
|
|
if (ss->recvBufLock) {
|
|
|
|
PZ_DestroyMonitor(ss->recvBufLock);
|
|
|
|
ss->recvBufLock = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Caller holds any relevant locks */
|
|
|
|
static void
|
|
|
|
ssl_DestroySocketContents(sslSocket *ss)
|
|
|
|
{
|
|
|
|
/* "i" should be of type SSLKEAType, but CC on IRIX complains during
|
|
|
|
* the for loop.
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Free up socket */
|
|
|
|
ssl_DestroySecurityInfo(&ss->sec);
|
|
|
|
|
|
|
|
ssl3_DestroySSL3Info(ss);
|
|
|
|
|
|
|
|
PORT_Free(ss->saveBuf.buf);
|
|
|
|
PORT_Free(ss->pendingBuf.buf);
|
|
|
|
ssl_DestroyGather(&ss->gs);
|
|
|
|
|
|
|
|
if (ss->peerID != NULL)
|
|
|
|
PORT_Free(ss->peerID);
|
|
|
|
if (ss->url != NULL)
|
|
|
|
PORT_Free((void *)ss->url); /* CONST */
|
|
|
|
if (ss->cipherSpecs) {
|
|
|
|
PORT_Free(ss->cipherSpecs);
|
|
|
|
ss->cipherSpecs = NULL;
|
|
|
|
ss->sizeCipherSpecs = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean up server configuration */
|
|
|
|
for (i=kt_null; i < kt_kea_size; i++) {
|
|
|
|
sslServerCerts * sc = ss->serverCerts + i;
|
|
|
|
if (sc->serverCert != NULL)
|
|
|
|
CERT_DestroyCertificate(sc->serverCert);
|
|
|
|
if (sc->serverCertChain != NULL)
|
|
|
|
CERT_DestroyCertificateList(sc->serverCertChain);
|
|
|
|
if (sc->serverKeyPair != NULL)
|
|
|
|
ssl3_FreeKeyPair(sc->serverKeyPair);
|
|
|
|
}
|
|
|
|
if (ss->stepDownKeyPair) {
|
|
|
|
ssl3_FreeKeyPair(ss->stepDownKeyPair);
|
|
|
|
ss->stepDownKeyPair = NULL;
|
|
|
|
}
|
|
|
|
if (ss->ephemeralECDHKeyPair) {
|
|
|
|
ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
|
|
|
|
ss->ephemeralECDHKeyPair = NULL;
|
|
|
|
}
|
2010-02-07 03:54:28 -08:00
|
|
|
PORT_Assert(!ss->xtnData.sniNameArr);
|
|
|
|
if (ss->xtnData.sniNameArr) {
|
|
|
|
PORT_Free(ss->xtnData.sniNameArr);
|
|
|
|
ss->xtnData.sniNameArr = NULL;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* free an sslSocket struct, and all the stuff that hangs off of it
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ssl_FreeSocket(sslSocket *ss)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
sslSocket *fs;
|
|
|
|
sslSocket lSock;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Get every lock you can imagine!
|
|
|
|
** Caller already holds these:
|
|
|
|
** SSL_LOCK_READER(ss);
|
|
|
|
** SSL_LOCK_WRITER(ss);
|
|
|
|
*/
|
|
|
|
ssl_Get1stHandshakeLock(ss);
|
|
|
|
ssl_GetRecvBufLock(ss);
|
|
|
|
ssl_GetSSL3HandshakeLock(ss);
|
|
|
|
ssl_GetXmitBufLock(ss);
|
|
|
|
ssl_GetSpecWriteLock(ss);
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
fs = &lSock;
|
|
|
|
*fs = *ss; /* Copy the old socket structure, */
|
|
|
|
PORT_Memset(ss, 0x1f, sizeof *ss); /* then blast the old struct ASAP. */
|
|
|
|
#else
|
|
|
|
#define fs ss
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ssl_DestroySocketContents(fs);
|
|
|
|
|
|
|
|
/* Release all the locks acquired above. */
|
|
|
|
SSL_UNLOCK_READER(fs);
|
|
|
|
SSL_UNLOCK_WRITER(fs);
|
|
|
|
ssl_Release1stHandshakeLock(fs);
|
|
|
|
ssl_ReleaseRecvBufLock(fs);
|
|
|
|
ssl_ReleaseSSL3HandshakeLock(fs);
|
|
|
|
ssl_ReleaseXmitBufLock(fs);
|
|
|
|
ssl_ReleaseSpecWriteLock(fs);
|
|
|
|
|
|
|
|
ssl_DestroyLocks(fs);
|
|
|
|
|
|
|
|
PORT_Free(ss); /* free the caller's copy, not ours. */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#undef fs
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
SECStatus
|
|
|
|
ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled)
|
|
|
|
{
|
|
|
|
PRFileDesc * osfd = ss->fd->lower;
|
|
|
|
SECStatus rv = SECFailure;
|
|
|
|
PRSocketOptionData opt;
|
|
|
|
|
|
|
|
opt.option = PR_SockOpt_NoDelay;
|
|
|
|
opt.value.no_delay = (PRBool)!enabled;
|
|
|
|
|
|
|
|
if (osfd->methods->setsocketoption) {
|
|
|
|
rv = (SECStatus) osfd->methods->setsocketoption(osfd, &opt);
|
|
|
|
} else {
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ssl_ChooseOps(sslSocket *ss)
|
|
|
|
{
|
|
|
|
ss->ops = ss->opt.useSecurity ? &ssl_secure_ops : &ssl_default_ops;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from SSL_Enable (immediately below) */
|
|
|
|
static SECStatus
|
|
|
|
PrepareSocket(sslSocket *ss)
|
|
|
|
{
|
|
|
|
SECStatus rv = SECSuccess;
|
|
|
|
|
|
|
|
ssl_ChooseOps(ss);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_Enable(PRFileDesc *fd, int which, PRBool on)
|
|
|
|
{
|
|
|
|
return SSL_OptionSet(fd, which, on);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const PRCallOnceType pristineCallOnce;
|
|
|
|
static PRCallOnceType setupBypassOnce;
|
|
|
|
|
|
|
|
static SECStatus SSL_BypassShutdown(void* appData, void* nssData)
|
|
|
|
{
|
|
|
|
/* unload freeBL shared library from memory */
|
|
|
|
BL_Unload();
|
|
|
|
setupBypassOnce = pristineCallOnce;
|
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus SSL_BypassRegisterShutdown(void)
|
|
|
|
{
|
|
|
|
SECStatus rv = NSS_RegisterShutdown(SSL_BypassShutdown, NULL);
|
|
|
|
PORT_Assert(SECSuccess == rv);
|
|
|
|
return SECSuccess == rv ? PR_SUCCESS : PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus SSL_BypassSetup(void)
|
|
|
|
{
|
|
|
|
return PR_CallOnce(&setupBypassOnce, &SSL_BypassRegisterShutdown);
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
|
|
|
|
{
|
|
|
|
sslSocket *ss = ssl_FindSocket(fd);
|
|
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PRBool holdingLocks;
|
|
|
|
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd));
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
holdingLocks = (!ss->opt.noLocks);
|
|
|
|
ssl_Get1stHandshakeLock(ss);
|
|
|
|
ssl_GetSSL3HandshakeLock(ss);
|
|
|
|
|
|
|
|
switch (which) {
|
|
|
|
case SSL_SOCKS:
|
|
|
|
ss->opt.useSocks = PR_FALSE;
|
|
|
|
rv = PrepareSocket(ss);
|
|
|
|
if (on) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_SECURITY:
|
|
|
|
ss->opt.useSecurity = on;
|
|
|
|
rv = PrepareSocket(ss);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_REQUEST_CERTIFICATE:
|
|
|
|
ss->opt.requestCertificate = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_REQUIRE_CERTIFICATE:
|
|
|
|
ss->opt.requireCertificate = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_HANDSHAKE_AS_CLIENT:
|
|
|
|
if ( ss->opt.handshakeAsServer && on ) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ss->opt.handshakeAsClient = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_HANDSHAKE_AS_SERVER:
|
|
|
|
if ( ss->opt.handshakeAsClient && on ) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ss->opt.handshakeAsServer = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_TLS:
|
|
|
|
ss->opt.enableTLS = on;
|
|
|
|
ss->preferredCipher = NULL;
|
|
|
|
if (ss->cipherSpecs) {
|
|
|
|
PORT_Free(ss->cipherSpecs);
|
|
|
|
ss->cipherSpecs = NULL;
|
|
|
|
ss->sizeCipherSpecs = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_SSL3:
|
|
|
|
ss->opt.enableSSL3 = on;
|
|
|
|
ss->preferredCipher = NULL;
|
|
|
|
if (ss->cipherSpecs) {
|
|
|
|
PORT_Free(ss->cipherSpecs);
|
|
|
|
ss->cipherSpecs = NULL;
|
|
|
|
ss->sizeCipherSpecs = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_SSL2:
|
|
|
|
ss->opt.enableSSL2 = on;
|
|
|
|
if (on) {
|
|
|
|
ss->opt.v2CompatibleHello = on;
|
|
|
|
}
|
|
|
|
ss->preferredCipher = NULL;
|
|
|
|
if (ss->cipherSpecs) {
|
|
|
|
PORT_Free(ss->cipherSpecs);
|
|
|
|
ss->cipherSpecs = NULL;
|
|
|
|
ss->sizeCipherSpecs = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_NO_CACHE:
|
|
|
|
ss->opt.noCache = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_FDX:
|
|
|
|
if (on && ss->opt.noLocks) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
}
|
|
|
|
ss->opt.fdx = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_V2_COMPATIBLE_HELLO:
|
|
|
|
ss->opt.v2CompatibleHello = on;
|
|
|
|
if (!on) {
|
|
|
|
ss->opt.enableSSL2 = on;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ROLLBACK_DETECTION:
|
|
|
|
ss->opt.detectRollBack = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_NO_STEP_DOWN:
|
|
|
|
ss->opt.noStepDown = on;
|
|
|
|
if (on)
|
|
|
|
SSL_DisableExportCipherSuites(fd);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_BYPASS_PKCS11:
|
|
|
|
if (ss->handshakeBegun) {
|
|
|
|
PORT_SetError(PR_INVALID_STATE_ERROR);
|
|
|
|
rv = SECFailure;
|
|
|
|
} else {
|
|
|
|
if (PR_FALSE != on) {
|
|
|
|
if (PR_SUCCESS == SSL_BypassSetup() ) {
|
|
|
|
ss->opt.bypassPKCS11 = on;
|
|
|
|
} else {
|
|
|
|
rv = SECFailure;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ss->opt.bypassPKCS11 = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_NO_LOCKS:
|
|
|
|
if (on && ss->opt.fdx) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
}
|
|
|
|
if (on && ssl_force_locks)
|
|
|
|
on = PR_FALSE; /* silent override */
|
|
|
|
ss->opt.noLocks = on;
|
|
|
|
if (on) {
|
|
|
|
locksEverDisabled = PR_TRUE;
|
|
|
|
strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED.");
|
|
|
|
} else if (!holdingLocks) {
|
|
|
|
rv = ssl_MakeLocks(ss);
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
ss->opt.noLocks = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_SESSION_TICKETS:
|
|
|
|
ss->opt.enableSessionTickets = on;
|
|
|
|
break;
|
|
|
|
|
2010-02-07 03:54:28 -08:00
|
|
|
case SSL_ENABLE_DEFLATE:
|
|
|
|
ss->opt.enableDeflate = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_RENEGOTIATION:
|
|
|
|
ss->opt.enableRenegotiation = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_REQUIRE_SAFE_NEGOTIATION:
|
|
|
|
ss->opt.requireSafeNegotiation = on;
|
|
|
|
break;
|
|
|
|
|
2010-08-02 13:49:18 -07:00
|
|
|
case SSL_ENABLE_FALSE_START:
|
|
|
|
ss->opt.enableFalseStart = on;
|
|
|
|
break;
|
|
|
|
|
2011-10-07 13:37:26 -07:00
|
|
|
case SSL_CBC_RANDOM_IV:
|
|
|
|
ss->opt.cbcRandomIV = on;
|
|
|
|
break;
|
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
default:
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We can't use the macros for releasing the locks here,
|
|
|
|
* because ss->opt.noLocks might have changed just above.
|
|
|
|
* We must release these locks (monitors) here, if we aquired them above,
|
|
|
|
* regardless of the current value of ss->opt.noLocks.
|
|
|
|
*/
|
|
|
|
if (holdingLocks) {
|
|
|
|
PZ_ExitMonitor((ss)->ssl3HandshakeLock);
|
|
|
|
PZ_ExitMonitor((ss)->firstHandshakeLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
|
|
|
|
{
|
|
|
|
sslSocket *ss = ssl_FindSocket(fd);
|
|
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PRBool on = PR_FALSE;
|
|
|
|
|
|
|
|
if (!pOn) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd));
|
|
|
|
*pOn = PR_FALSE;
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssl_Get1stHandshakeLock(ss);
|
|
|
|
ssl_GetSSL3HandshakeLock(ss);
|
|
|
|
|
|
|
|
switch (which) {
|
|
|
|
case SSL_SOCKS: on = PR_FALSE; break;
|
|
|
|
case SSL_SECURITY: on = ss->opt.useSecurity; break;
|
|
|
|
case SSL_REQUEST_CERTIFICATE: on = ss->opt.requestCertificate; break;
|
|
|
|
case SSL_REQUIRE_CERTIFICATE: on = ss->opt.requireCertificate; break;
|
|
|
|
case SSL_HANDSHAKE_AS_CLIENT: on = ss->opt.handshakeAsClient; break;
|
|
|
|
case SSL_HANDSHAKE_AS_SERVER: on = ss->opt.handshakeAsServer; break;
|
|
|
|
case SSL_ENABLE_TLS: on = ss->opt.enableTLS; break;
|
|
|
|
case SSL_ENABLE_SSL3: on = ss->opt.enableSSL3; break;
|
|
|
|
case SSL_ENABLE_SSL2: on = ss->opt.enableSSL2; break;
|
|
|
|
case SSL_NO_CACHE: on = ss->opt.noCache; break;
|
|
|
|
case SSL_ENABLE_FDX: on = ss->opt.fdx; break;
|
|
|
|
case SSL_V2_COMPATIBLE_HELLO: on = ss->opt.v2CompatibleHello; break;
|
|
|
|
case SSL_ROLLBACK_DETECTION: on = ss->opt.detectRollBack; break;
|
|
|
|
case SSL_NO_STEP_DOWN: on = ss->opt.noStepDown; break;
|
|
|
|
case SSL_BYPASS_PKCS11: on = ss->opt.bypassPKCS11; break;
|
|
|
|
case SSL_NO_LOCKS: on = ss->opt.noLocks; break;
|
|
|
|
case SSL_ENABLE_SESSION_TICKETS:
|
|
|
|
on = ss->opt.enableSessionTickets;
|
|
|
|
break;
|
2010-02-07 03:54:28 -08:00
|
|
|
case SSL_ENABLE_DEFLATE: on = ss->opt.enableDeflate; break;
|
|
|
|
case SSL_ENABLE_RENEGOTIATION:
|
|
|
|
on = ss->opt.enableRenegotiation; break;
|
|
|
|
case SSL_REQUIRE_SAFE_NEGOTIATION:
|
|
|
|
on = ss->opt.requireSafeNegotiation; break;
|
2010-08-02 13:49:18 -07:00
|
|
|
case SSL_ENABLE_FALSE_START: on = ss->opt.enableFalseStart; break;
|
2011-10-07 13:37:26 -07:00
|
|
|
case SSL_CBC_RANDOM_IV: on = ss->opt.cbcRandomIV; break;
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
default:
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssl_ReleaseSSL3HandshakeLock(ss);
|
|
|
|
ssl_Release1stHandshakeLock(ss);
|
|
|
|
|
|
|
|
*pOn = on;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
|
|
|
|
{
|
|
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PRBool on = PR_FALSE;
|
|
|
|
|
|
|
|
if (!pOn) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
Bug 673382: Update NSS to NSS_3_12_11_BETA1, which includes the fixes for
Bug 661609, Bug 650276 (code not used by Mozilla), Bug 602509, Bug 655411,
Bug 655850, Bug 671711, Bug 617565, Bug 668001, Bug 346583, Bug 661061.
2011-07-27 09:07:32 -07:00
|
|
|
ssl_SetDefaultsFromEnvironment();
|
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
switch (which) {
|
|
|
|
case SSL_SOCKS: on = PR_FALSE; break;
|
|
|
|
case SSL_SECURITY: on = ssl_defaults.useSecurity; break;
|
|
|
|
case SSL_REQUEST_CERTIFICATE: on = ssl_defaults.requestCertificate; break;
|
|
|
|
case SSL_REQUIRE_CERTIFICATE: on = ssl_defaults.requireCertificate; break;
|
|
|
|
case SSL_HANDSHAKE_AS_CLIENT: on = ssl_defaults.handshakeAsClient; break;
|
|
|
|
case SSL_HANDSHAKE_AS_SERVER: on = ssl_defaults.handshakeAsServer; break;
|
|
|
|
case SSL_ENABLE_TLS: on = ssl_defaults.enableTLS; break;
|
|
|
|
case SSL_ENABLE_SSL3: on = ssl_defaults.enableSSL3; break;
|
|
|
|
case SSL_ENABLE_SSL2: on = ssl_defaults.enableSSL2; break;
|
|
|
|
case SSL_NO_CACHE: on = ssl_defaults.noCache; break;
|
|
|
|
case SSL_ENABLE_FDX: on = ssl_defaults.fdx; break;
|
|
|
|
case SSL_V2_COMPATIBLE_HELLO: on = ssl_defaults.v2CompatibleHello; break;
|
|
|
|
case SSL_ROLLBACK_DETECTION: on = ssl_defaults.detectRollBack; break;
|
|
|
|
case SSL_NO_STEP_DOWN: on = ssl_defaults.noStepDown; break;
|
|
|
|
case SSL_BYPASS_PKCS11: on = ssl_defaults.bypassPKCS11; break;
|
|
|
|
case SSL_NO_LOCKS: on = ssl_defaults.noLocks; break;
|
|
|
|
case SSL_ENABLE_SESSION_TICKETS:
|
|
|
|
on = ssl_defaults.enableSessionTickets;
|
|
|
|
break;
|
2010-02-07 03:54:28 -08:00
|
|
|
case SSL_ENABLE_DEFLATE: on = ssl_defaults.enableDeflate; break;
|
|
|
|
case SSL_ENABLE_RENEGOTIATION:
|
|
|
|
on = ssl_defaults.enableRenegotiation; break;
|
|
|
|
case SSL_REQUIRE_SAFE_NEGOTIATION:
|
|
|
|
on = ssl_defaults.requireSafeNegotiation;
|
|
|
|
break;
|
2010-08-02 13:49:18 -07:00
|
|
|
case SSL_ENABLE_FALSE_START: on = ssl_defaults.enableFalseStart; break;
|
2011-10-07 13:37:26 -07:00
|
|
|
case SSL_CBC_RANDOM_IV: on = ssl_defaults.cbcRandomIV; break;
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
default:
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
rv = SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pOn = on;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX Use Global Lock to protect this stuff. */
|
|
|
|
SECStatus
|
|
|
|
SSL_EnableDefault(int which, PRBool on)
|
|
|
|
{
|
|
|
|
return SSL_OptionSetDefault(which, on);
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_OptionSetDefault(PRInt32 which, PRBool on)
|
|
|
|
{
|
2011-08-19 08:27:10 -07:00
|
|
|
SECStatus status = ssl_Init();
|
|
|
|
|
|
|
|
if (status != SECSuccess) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
Bug 673382: Update NSS to NSS_3_12_11_BETA1, which includes the fixes for
Bug 661609, Bug 650276 (code not used by Mozilla), Bug 602509, Bug 655411,
Bug 655850, Bug 671711, Bug 617565, Bug 668001, Bug 346583, Bug 661061.
2011-07-27 09:07:32 -07:00
|
|
|
ssl_SetDefaultsFromEnvironment();
|
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
switch (which) {
|
|
|
|
case SSL_SOCKS:
|
|
|
|
ssl_defaults.useSocks = PR_FALSE;
|
|
|
|
if (on) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_SECURITY:
|
|
|
|
ssl_defaults.useSecurity = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_REQUEST_CERTIFICATE:
|
|
|
|
ssl_defaults.requestCertificate = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_REQUIRE_CERTIFICATE:
|
|
|
|
ssl_defaults.requireCertificate = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_HANDSHAKE_AS_CLIENT:
|
|
|
|
if ( ssl_defaults.handshakeAsServer && on ) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
ssl_defaults.handshakeAsClient = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_HANDSHAKE_AS_SERVER:
|
|
|
|
if ( ssl_defaults.handshakeAsClient && on ) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
ssl_defaults.handshakeAsServer = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_TLS:
|
|
|
|
ssl_defaults.enableTLS = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_SSL3:
|
|
|
|
ssl_defaults.enableSSL3 = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_SSL2:
|
|
|
|
ssl_defaults.enableSSL2 = on;
|
|
|
|
if (on) {
|
|
|
|
ssl_defaults.v2CompatibleHello = on;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_NO_CACHE:
|
|
|
|
ssl_defaults.noCache = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_FDX:
|
|
|
|
if (on && ssl_defaults.noLocks) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
ssl_defaults.fdx = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_V2_COMPATIBLE_HELLO:
|
|
|
|
ssl_defaults.v2CompatibleHello = on;
|
|
|
|
if (!on) {
|
|
|
|
ssl_defaults.enableSSL2 = on;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ROLLBACK_DETECTION:
|
|
|
|
ssl_defaults.detectRollBack = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_NO_STEP_DOWN:
|
|
|
|
ssl_defaults.noStepDown = on;
|
|
|
|
if (on)
|
|
|
|
SSL_DisableDefaultExportCipherSuites();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_BYPASS_PKCS11:
|
|
|
|
if (PR_FALSE != on) {
|
|
|
|
if (PR_SUCCESS == SSL_BypassSetup()) {
|
|
|
|
ssl_defaults.bypassPKCS11 = on;
|
|
|
|
} else {
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ssl_defaults.bypassPKCS11 = PR_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_NO_LOCKS:
|
|
|
|
if (on && ssl_defaults.fdx) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (on && ssl_force_locks)
|
|
|
|
on = PR_FALSE; /* silent override */
|
|
|
|
ssl_defaults.noLocks = on;
|
|
|
|
if (on) {
|
|
|
|
locksEverDisabled = PR_TRUE;
|
|
|
|
strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED.");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_SESSION_TICKETS:
|
|
|
|
ssl_defaults.enableSessionTickets = on;
|
|
|
|
break;
|
|
|
|
|
2010-02-07 03:54:28 -08:00
|
|
|
case SSL_ENABLE_DEFLATE:
|
|
|
|
ssl_defaults.enableDeflate = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_ENABLE_RENEGOTIATION:
|
|
|
|
ssl_defaults.enableRenegotiation = on;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SSL_REQUIRE_SAFE_NEGOTIATION:
|
|
|
|
ssl_defaults.requireSafeNegotiation = on;
|
|
|
|
break;
|
|
|
|
|
2010-08-02 13:49:18 -07:00
|
|
|
case SSL_ENABLE_FALSE_START:
|
|
|
|
ssl_defaults.enableFalseStart = on;
|
|
|
|
break;
|
|
|
|
|
2011-10-07 13:37:26 -07:00
|
|
|
case SSL_CBC_RANDOM_IV:
|
|
|
|
ssl_defaults.cbcRandomIV = on;
|
|
|
|
break;
|
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
default:
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* function tells us if the cipher suite is one that we no longer support. */
|
|
|
|
static PRBool
|
|
|
|
ssl_IsRemovedCipherSuite(PRInt32 suite)
|
|
|
|
{
|
|
|
|
switch (suite) {
|
|
|
|
case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
|
|
|
|
case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:
|
|
|
|
case SSL_FORTEZZA_DMS_WITH_RC4_128_SHA:
|
|
|
|
return PR_TRUE;
|
|
|
|
default:
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Part of the public NSS API.
|
|
|
|
* Since this is a global (not per-socket) setting, we cannot use the
|
|
|
|
* HandshakeLock to protect this. Probably want a global lock.
|
|
|
|
*/
|
|
|
|
SECStatus
|
|
|
|
SSL_SetPolicy(long which, int policy)
|
|
|
|
{
|
|
|
|
if ((which & 0xfffe) == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) {
|
|
|
|
/* one of the two old FIPS ciphers */
|
|
|
|
if (which == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA)
|
|
|
|
which = SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA;
|
|
|
|
else if (which == SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA)
|
|
|
|
which = SSL_RSA_FIPS_WITH_DES_CBC_SHA;
|
|
|
|
}
|
|
|
|
if (ssl_IsRemovedCipherSuite(which))
|
|
|
|
return SECSuccess;
|
|
|
|
return SSL_CipherPolicySet(which, policy);
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_CipherPolicySet(PRInt32 which, PRInt32 policy)
|
|
|
|
{
|
2011-08-19 08:27:10 -07:00
|
|
|
SECStatus rv = ssl_Init();
|
|
|
|
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
return rv;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
if (ssl_IsRemovedCipherSuite(which)) {
|
|
|
|
rv = SECSuccess;
|
|
|
|
} else if (SSL_IS_SSL2_CIPHER(which)) {
|
|
|
|
rv = ssl2_SetPolicy(which, policy);
|
|
|
|
} else {
|
|
|
|
rv = ssl3_SetPolicy((ssl3CipherSuite)which, policy);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_CipherPolicyGet(PRInt32 which, PRInt32 *oPolicy)
|
|
|
|
{
|
|
|
|
SECStatus rv;
|
|
|
|
|
|
|
|
if (!oPolicy) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (ssl_IsRemovedCipherSuite(which)) {
|
|
|
|
*oPolicy = SSL_NOT_ALLOWED;
|
|
|
|
rv = SECSuccess;
|
|
|
|
} else if (SSL_IS_SSL2_CIPHER(which)) {
|
|
|
|
rv = ssl2_GetPolicy(which, oPolicy);
|
|
|
|
} else {
|
|
|
|
rv = ssl3_GetPolicy((ssl3CipherSuite)which, oPolicy);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Part of the public NSS API.
|
|
|
|
* Since this is a global (not per-socket) setting, we cannot use the
|
|
|
|
* HandshakeLock to protect this. Probably want a global lock.
|
|
|
|
* These changes have no effect on any sslSockets already created.
|
|
|
|
*/
|
|
|
|
SECStatus
|
|
|
|
SSL_EnableCipher(long which, PRBool enabled)
|
|
|
|
{
|
|
|
|
if ((which & 0xfffe) == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA) {
|
|
|
|
/* one of the two old FIPS ciphers */
|
|
|
|
if (which == SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA)
|
|
|
|
which = SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA;
|
|
|
|
else if (which == SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA)
|
|
|
|
which = SSL_RSA_FIPS_WITH_DES_CBC_SHA;
|
|
|
|
}
|
|
|
|
if (ssl_IsRemovedCipherSuite(which))
|
|
|
|
return SECSuccess;
|
|
|
|
return SSL_CipherPrefSetDefault(which, enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
|
|
|
|
{
|
2011-08-19 08:27:10 -07:00
|
|
|
SECStatus rv = ssl_Init();
|
|
|
|
|
|
|
|
if (rv != SECSuccess) {
|
|
|
|
return rv;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
if (ssl_IsRemovedCipherSuite(which))
|
|
|
|
return SECSuccess;
|
|
|
|
if (enabled && ssl_defaults.noStepDown && SSL_IsExportCipherSuite(which)) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (SSL_IS_SSL2_CIPHER(which)) {
|
|
|
|
rv = ssl2_CipherPrefSetDefault(which, enabled);
|
|
|
|
} else {
|
|
|
|
rv = ssl3_CipherPrefSetDefault((ssl3CipherSuite)which, enabled);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_CipherPrefGetDefault(PRInt32 which, PRBool *enabled)
|
|
|
|
{
|
|
|
|
SECStatus rv;
|
|
|
|
|
|
|
|
if (!enabled) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (ssl_IsRemovedCipherSuite(which)) {
|
|
|
|
*enabled = PR_FALSE;
|
|
|
|
rv = SECSuccess;
|
|
|
|
} else if (SSL_IS_SSL2_CIPHER(which)) {
|
|
|
|
rv = ssl2_CipherPrefGetDefault(which, enabled);
|
|
|
|
} else {
|
|
|
|
rv = ssl3_CipherPrefGetDefault((ssl3CipherSuite)which, enabled);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled)
|
|
|
|
{
|
|
|
|
SECStatus rv;
|
|
|
|
sslSocket *ss = ssl_FindSocket(fd);
|
|
|
|
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefSet", SSL_GETPID(), fd));
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (ssl_IsRemovedCipherSuite(which))
|
|
|
|
return SECSuccess;
|
|
|
|
if (enabled && ss->opt.noStepDown && SSL_IsExportCipherSuite(which)) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (SSL_IS_SSL2_CIPHER(which)) {
|
|
|
|
rv = ssl2_CipherPrefSet(ss, which, enabled);
|
|
|
|
} else {
|
|
|
|
rv = ssl3_CipherPrefSet(ss, (ssl3CipherSuite)which, enabled);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
SSL_CipherPrefGet(PRFileDesc *fd, PRInt32 which, PRBool *enabled)
|
|
|
|
{
|
|
|
|
SECStatus rv;
|
|
|
|
sslSocket *ss = ssl_FindSocket(fd);
|
|
|
|
|
|
|
|
if (!enabled) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefGet", SSL_GETPID(), fd));
|
|
|
|
*enabled = PR_FALSE;
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
if (ssl_IsRemovedCipherSuite(which)) {
|
|
|
|
*enabled = PR_FALSE;
|
|
|
|
rv = SECSuccess;
|
|
|
|
} else if (SSL_IS_SSL2_CIPHER(which)) {
|
|
|
|
rv = ssl2_CipherPrefGet(ss, which, enabled);
|
|
|
|
} else {
|
|
|
|
rv = ssl3_CipherPrefGet(ss, (ssl3CipherSuite)which, enabled);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
NSS_SetDomesticPolicy(void)
|
|
|
|
{
|
|
|
|
#ifndef EXPORT_VERSION
|
|
|
|
SECStatus status = SECSuccess;
|
|
|
|
cipherPolicy * policy;
|
|
|
|
|
|
|
|
for (policy = ssl_ciphers; policy->cipher != 0; ++policy) {
|
|
|
|
status = SSL_SetPolicy(policy->cipher, SSL_ALLOWED);
|
|
|
|
if (status != SECSuccess)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
#else
|
|
|
|
return NSS_SetExportPolicy();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
NSS_SetExportPolicy(void)
|
|
|
|
{
|
|
|
|
SECStatus status = SECSuccess;
|
|
|
|
cipherPolicy * policy;
|
|
|
|
|
|
|
|
for (policy = ssl_ciphers; policy->cipher != 0; ++policy) {
|
|
|
|
status = SSL_SetPolicy(policy->cipher, policy->export);
|
|
|
|
if (status != SECSuccess)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECStatus
|
|
|
|
NSS_SetFrancePolicy(void)
|
|
|
|
{
|
|
|
|
SECStatus status = SECSuccess;
|
|
|
|
cipherPolicy * policy;
|
|
|
|
|
|
|
|
for (policy = ssl_ciphers; policy->cipher != 0; ++policy) {
|
|
|
|
status = SSL_SetPolicy(policy->cipher, policy->france);
|
|
|
|
if (status != SECSuccess)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* LOCKS ??? XXX */
|
|
|
|
PRFileDesc *
|
|
|
|
SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
sslSocket * ns = NULL;
|
|
|
|
PRStatus rv;
|
|
|
|
PRNetAddr addr;
|
2011-08-19 08:27:10 -07:00
|
|
|
SECStatus status = ssl_Init();
|
|
|
|
|
|
|
|
if (status != SECSuccess) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
|
|
|
|
if (model == NULL) {
|
|
|
|
/* Just create a default socket if we're given NULL for the model */
|
|
|
|
ns = ssl_NewSocket((PRBool)(!ssl_defaults.noLocks));
|
|
|
|
} else {
|
|
|
|
sslSocket * ss = ssl_FindSocket(model);
|
|
|
|
if (ss == NULL) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ImportFD",
|
|
|
|
SSL_GETPID(), model));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ns = ssl_DupSocket(ss);
|
|
|
|
}
|
|
|
|
if (ns == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
rv = ssl_PushIOLayer(ns, fd, PR_TOP_IO_LAYER);
|
|
|
|
if (rv != PR_SUCCESS) {
|
|
|
|
ssl_FreeSocket(ns);
|
|
|
|
SET_ERROR_CODE
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
|
|
PR_Sleep(PR_INTERVAL_NO_WAIT); /* workaround NT winsock connect bug. */
|
|
|
|
#endif
|
|
|
|
ns = ssl_FindSocket(fd);
|
|
|
|
PORT_Assert(ns);
|
|
|
|
if (ns)
|
|
|
|
ns->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ns, &addr));
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2010-02-07 03:54:28 -08:00
|
|
|
PRFileDesc *
|
|
|
|
SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
sslSocket * sm = NULL, *ss = NULL;
|
|
|
|
int i;
|
2011-05-05 07:35:11 -07:00
|
|
|
sslServerCerts * mc = NULL;
|
|
|
|
sslServerCerts * sc = NULL;
|
2010-02-07 03:54:28 -08:00
|
|
|
|
|
|
|
if (model == NULL) {
|
|
|
|
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
sm = ssl_FindSocket(model);
|
|
|
|
if (sm == NULL) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad model socket in ssl_ReconfigFD",
|
|
|
|
SSL_GETPID(), model));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ss = ssl_FindSocket(fd);
|
|
|
|
PORT_Assert(ss);
|
|
|
|
if (ss == NULL) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ss->opt = sm->opt;
|
|
|
|
PORT_Memcpy(ss->cipherSuites, sm->cipherSuites, sizeof sm->cipherSuites);
|
|
|
|
|
|
|
|
if (!ss->opt.useSecurity) {
|
|
|
|
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* This int should be SSLKEAType, but CC on Irix complains,
|
|
|
|
* during the for loop.
|
|
|
|
*/
|
2011-05-05 07:35:11 -07:00
|
|
|
for (i=kt_null; i < kt_kea_size; i++) {
|
|
|
|
mc = &(sm->serverCerts[i]);
|
|
|
|
sc = &(ss->serverCerts[i]);
|
2010-02-07 03:54:28 -08:00
|
|
|
if (mc->serverCert && mc->serverCertChain) {
|
|
|
|
if (sc->serverCert) {
|
|
|
|
CERT_DestroyCertificate(sc->serverCert);
|
|
|
|
}
|
|
|
|
sc->serverCert = CERT_DupCertificate(mc->serverCert);
|
|
|
|
if (sc->serverCertChain) {
|
|
|
|
CERT_DestroyCertificateList(sc->serverCertChain);
|
|
|
|
}
|
|
|
|
sc->serverCertChain = CERT_DupCertList(mc->serverCertChain);
|
|
|
|
if (!sc->serverCertChain)
|
|
|
|
goto loser;
|
|
|
|
}
|
|
|
|
if (mc->serverKeyPair) {
|
|
|
|
if (sc->serverKeyPair) {
|
|
|
|
ssl3_FreeKeyPair(sc->serverKeyPair);
|
|
|
|
}
|
|
|
|
sc->serverKeyPair = ssl3_GetKeyPairRef(mc->serverKeyPair);
|
|
|
|
sc->serverKeyBits = mc->serverKeyBits;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sm->stepDownKeyPair) {
|
|
|
|
if (ss->stepDownKeyPair) {
|
|
|
|
ssl3_FreeKeyPair(ss->stepDownKeyPair);
|
|
|
|
}
|
|
|
|
ss->stepDownKeyPair = ssl3_GetKeyPairRef(sm->stepDownKeyPair);
|
|
|
|
}
|
|
|
|
if (sm->ephemeralECDHKeyPair) {
|
|
|
|
if (ss->ephemeralECDHKeyPair) {
|
|
|
|
ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
|
|
|
|
}
|
|
|
|
ss->ephemeralECDHKeyPair =
|
|
|
|
ssl3_GetKeyPairRef(sm->ephemeralECDHKeyPair);
|
|
|
|
}
|
|
|
|
/* copy trust anchor names */
|
|
|
|
if (sm->ssl3.ca_list) {
|
|
|
|
if (ss->ssl3.ca_list) {
|
|
|
|
CERT_FreeDistNames(ss->ssl3.ca_list);
|
|
|
|
}
|
|
|
|
ss->ssl3.ca_list = CERT_DupDistNames(sm->ssl3.ca_list);
|
|
|
|
if (!ss->ssl3.ca_list) {
|
|
|
|
goto loser;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sm->authCertificate)
|
|
|
|
ss->authCertificate = sm->authCertificate;
|
|
|
|
if (sm->authCertificateArg)
|
|
|
|
ss->authCertificateArg = sm->authCertificateArg;
|
|
|
|
if (sm->getClientAuthData)
|
|
|
|
ss->getClientAuthData = sm->getClientAuthData;
|
|
|
|
if (sm->getClientAuthDataArg)
|
|
|
|
ss->getClientAuthDataArg = sm->getClientAuthDataArg;
|
|
|
|
if (sm->sniSocketConfig)
|
|
|
|
ss->sniSocketConfig = sm->sniSocketConfig;
|
|
|
|
if (sm->sniSocketConfigArg)
|
|
|
|
ss->sniSocketConfigArg = sm->sniSocketConfigArg;
|
|
|
|
if (sm->handleBadCert)
|
|
|
|
ss->handleBadCert = sm->handleBadCert;
|
|
|
|
if (sm->badCertArg)
|
|
|
|
ss->badCertArg = sm->badCertArg;
|
|
|
|
if (sm->handshakeCallback)
|
|
|
|
ss->handshakeCallback = sm->handshakeCallback;
|
|
|
|
if (sm->handshakeCallbackData)
|
|
|
|
ss->handshakeCallbackData = sm->handshakeCallbackData;
|
|
|
|
if (sm->pkcs11PinArg)
|
|
|
|
ss->pkcs11PinArg = sm->pkcs11PinArg;
|
|
|
|
return fd;
|
|
|
|
loser:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
/************************************************************************/
|
|
|
|
/* The following functions are the TOP LEVEL SSL functions.
|
|
|
|
** They all get called through the NSPRIOMethods table below.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static PRFileDesc * PR_CALLBACK
|
|
|
|
ssl_Accept(PRFileDesc *fd, PRNetAddr *sockaddr, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
sslSocket *ns = NULL;
|
|
|
|
PRFileDesc *newfd = NULL;
|
|
|
|
PRFileDesc *osfd;
|
|
|
|
PRStatus status;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in accept", SSL_GETPID(), fd));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* IF this is a listen socket, there shouldn't be any I/O going on */
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
ssl_Get1stHandshakeLock(ss);
|
|
|
|
ssl_GetSSL3HandshakeLock(ss);
|
|
|
|
|
|
|
|
ss->cTimeout = timeout;
|
|
|
|
|
|
|
|
osfd = ss->fd->lower;
|
|
|
|
|
|
|
|
/* First accept connection */
|
|
|
|
newfd = osfd->methods->accept(osfd, sockaddr, timeout);
|
|
|
|
if (newfd == NULL) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: accept failed, errno=%d",
|
|
|
|
SSL_GETPID(), ss->fd, PORT_GetError()));
|
|
|
|
} else {
|
|
|
|
/* Create ssl module */
|
|
|
|
ns = ssl_DupSocket(ss);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssl_ReleaseSSL3HandshakeLock(ss);
|
|
|
|
ssl_Release1stHandshakeLock(ss);
|
|
|
|
SSL_UNLOCK_WRITER(ss);
|
|
|
|
SSL_UNLOCK_READER(ss); /* ss isn't used below here. */
|
|
|
|
|
|
|
|
if (ns == NULL)
|
|
|
|
goto loser;
|
|
|
|
|
|
|
|
/* push ssl module onto the new socket */
|
|
|
|
status = ssl_PushIOLayer(ns, newfd, PR_TOP_IO_LAYER);
|
|
|
|
if (status != PR_SUCCESS)
|
|
|
|
goto loser;
|
|
|
|
|
|
|
|
/* Now start server connection handshake with client.
|
|
|
|
** Don't need locks here because nobody else has a reference to ns yet.
|
|
|
|
*/
|
|
|
|
if ( ns->opt.useSecurity ) {
|
|
|
|
if ( ns->opt.handshakeAsClient ) {
|
|
|
|
ns->handshake = ssl2_BeginClientHandshake;
|
|
|
|
ss->handshaking = sslHandshakingAsClient;
|
|
|
|
} else {
|
|
|
|
ns->handshake = ssl2_BeginServerHandshake;
|
|
|
|
ss->handshaking = sslHandshakingAsServer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ns->TCPconnected = 1;
|
|
|
|
return newfd;
|
|
|
|
|
|
|
|
loser:
|
|
|
|
if (ns != NULL)
|
|
|
|
ssl_FreeSocket(ns);
|
|
|
|
if (newfd != NULL)
|
|
|
|
PR_Close(newfd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_Connect(PRFileDesc *fd, const PRNetAddr *sockaddr, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
PRStatus rv;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in connect", SSL_GETPID(), fd));
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* IF this is a listen socket, there shouldn't be any I/O going on */
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
|
|
|
|
ss->cTimeout = timeout;
|
|
|
|
rv = (PRStatus)(*ss->ops->connect)(ss, sockaddr);
|
|
|
|
#ifdef _WIN32
|
|
|
|
PR_Sleep(PR_INTERVAL_NO_WAIT); /* workaround NT winsock connect bug. */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SSL_UNLOCK_WRITER(ss);
|
|
|
|
SSL_UNLOCK_READER(ss);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_Bind(PRFileDesc *fd, const PRNetAddr *addr)
|
|
|
|
{
|
|
|
|
sslSocket * ss = ssl_GetPrivate(fd);
|
|
|
|
PRStatus rv;
|
|
|
|
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in bind", SSL_GETPID(), fd));
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
|
|
|
|
rv = (PRStatus)(*ss->ops->bind)(ss, addr);
|
|
|
|
|
|
|
|
SSL_UNLOCK_WRITER(ss);
|
|
|
|
SSL_UNLOCK_READER(ss);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_Listen(PRFileDesc *fd, PRIntn backlog)
|
|
|
|
{
|
|
|
|
sslSocket * ss = ssl_GetPrivate(fd);
|
|
|
|
PRStatus rv;
|
|
|
|
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in listen", SSL_GETPID(), fd));
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
|
|
|
|
rv = (PRStatus)(*ss->ops->listen)(ss, backlog);
|
|
|
|
|
|
|
|
SSL_UNLOCK_WRITER(ss);
|
|
|
|
SSL_UNLOCK_READER(ss);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_Shutdown(PRFileDesc *fd, PRIntn how)
|
|
|
|
{
|
|
|
|
sslSocket * ss = ssl_GetPrivate(fd);
|
|
|
|
PRStatus rv;
|
|
|
|
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in shutdown", SSL_GETPID(), fd));
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
if (how == PR_SHUTDOWN_RCV || how == PR_SHUTDOWN_BOTH) {
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
}
|
|
|
|
if (how == PR_SHUTDOWN_SEND || how == PR_SHUTDOWN_BOTH) {
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = (PRStatus)(*ss->ops->shutdown)(ss, how);
|
|
|
|
|
|
|
|
if (how == PR_SHUTDOWN_SEND || how == PR_SHUTDOWN_BOTH) {
|
|
|
|
SSL_UNLOCK_WRITER(ss);
|
|
|
|
}
|
|
|
|
if (how == PR_SHUTDOWN_RCV || how == PR_SHUTDOWN_BOTH) {
|
|
|
|
SSL_UNLOCK_READER(ss);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_Close(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
PRStatus rv;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in close", SSL_GETPID(), fd));
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* There must not be any I/O going on */
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
|
|
|
|
/* By the time this function returns,
|
|
|
|
** ss is an invalid pointer, and the locks to which it points have
|
|
|
|
** been unlocked and freed. So, this is the ONE PLACE in all of SSL
|
|
|
|
** where the LOCK calls and the corresponding UNLOCK calls are not in
|
|
|
|
** the same function scope. The unlock calls are in ssl_FreeSocket().
|
|
|
|
*/
|
|
|
|
rv = (PRStatus)(*ss->ops->close)(ss);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int PR_CALLBACK
|
|
|
|
ssl_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags,
|
|
|
|
PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in recv", SSL_GETPID(), fd));
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
ss->rTimeout = timeout;
|
|
|
|
if (!ss->opt.fdx)
|
|
|
|
ss->wTimeout = timeout;
|
|
|
|
rv = (*ss->ops->recv)(ss, (unsigned char*)buf, len, flags);
|
|
|
|
SSL_UNLOCK_READER(ss);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int PR_CALLBACK
|
|
|
|
ssl_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags,
|
|
|
|
PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in send", SSL_GETPID(), fd));
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
ss->wTimeout = timeout;
|
|
|
|
if (!ss->opt.fdx)
|
|
|
|
ss->rTimeout = timeout;
|
|
|
|
rv = (*ss->ops->send)(ss, (const unsigned char*)buf, len, flags);
|
|
|
|
SSL_UNLOCK_WRITER(ss);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int PR_CALLBACK
|
|
|
|
ssl_Read(PRFileDesc *fd, void *buf, PRInt32 len)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in read", SSL_GETPID(), fd));
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
SSL_LOCK_READER(ss);
|
|
|
|
ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
|
|
|
|
if (!ss->opt.fdx)
|
|
|
|
ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
|
|
|
|
rv = (*ss->ops->read)(ss, (unsigned char*)buf, len);
|
|
|
|
SSL_UNLOCK_READER(ss);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int PR_CALLBACK
|
|
|
|
ssl_Write(PRFileDesc *fd, const void *buf, PRInt32 len)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in write", SSL_GETPID(), fd));
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
SSL_LOCK_WRITER(ss);
|
|
|
|
ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
|
|
|
|
if (!ss->opt.fdx)
|
|
|
|
ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
|
|
|
|
rv = (*ss->ops->write)(ss, (const unsigned char*)buf, len);
|
|
|
|
SSL_UNLOCK_WRITER(ss);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in getpeername", SSL_GETPID(), fd));
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
return (PRStatus)(*ss->ops->getpeername)(ss, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
SECStatus
|
|
|
|
ssl_GetPeerInfo(sslSocket *ss)
|
|
|
|
{
|
|
|
|
PRFileDesc * osfd;
|
|
|
|
int rv;
|
|
|
|
PRNetAddr sin;
|
|
|
|
|
|
|
|
osfd = ss->fd->lower;
|
|
|
|
|
|
|
|
PORT_Memset(&sin, 0, sizeof(sin));
|
|
|
|
rv = osfd->methods->getpeername(osfd, &sin);
|
|
|
|
if (rv < 0) {
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
ss->TCPconnected = 1;
|
|
|
|
if (sin.inet.family == PR_AF_INET) {
|
|
|
|
PR_ConvertIPv4AddrToIPv6(sin.inet.ip, &ss->sec.ci.peer);
|
|
|
|
ss->sec.ci.port = sin.inet.port;
|
|
|
|
} else if (sin.ipv6.family == PR_AF_INET6) {
|
|
|
|
ss->sec.ci.peer = sin.ipv6.ip;
|
|
|
|
ss->sec.ci.port = sin.ipv6.port;
|
|
|
|
} else {
|
|
|
|
PORT_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
return SECSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_GetSockName(PRFileDesc *fd, PRNetAddr *name)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in getsockname", SSL_GETPID(), fd));
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
return (PRStatus)(*ss->ops->getsockname)(ss, name);
|
|
|
|
}
|
|
|
|
|
2010-02-07 03:54:28 -08:00
|
|
|
SECStatus
|
|
|
|
SSL_SetSockPeerID(PRFileDesc *fd, const char *peerID)
|
2008-06-06 05:40:11 -07:00
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
|
|
|
|
ss = ssl_FindSocket(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCacheIndex",
|
|
|
|
SSL_GETPID(), fd));
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
2009-04-09 17:00:56 -07:00
|
|
|
if (ss->peerID) {
|
|
|
|
PORT_Free(ss->peerID);
|
|
|
|
ss->peerID = NULL;
|
|
|
|
}
|
|
|
|
if (peerID)
|
|
|
|
ss->peerID = PORT_Strdup(peerID);
|
|
|
|
return (ss->peerID || !peerID) ? SECSuccess : SECFailure;
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#define PR_POLL_RW (PR_POLL_WRITE | PR_POLL_READ)
|
|
|
|
|
|
|
|
static PRInt16 PR_CALLBACK
|
|
|
|
ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
PRInt16 new_flags = how_flags; /* should select on these flags. */
|
|
|
|
PRNetAddr addr;
|
|
|
|
|
|
|
|
*p_out_flags = 0;
|
|
|
|
ss = ssl_GetPrivate(fd);
|
|
|
|
if (!ss) {
|
|
|
|
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_Poll",
|
|
|
|
SSL_GETPID(), fd));
|
|
|
|
return 0; /* don't poll on this socket */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ss->opt.useSecurity &&
|
|
|
|
ss->handshaking != sslHandshakingUndetermined &&
|
|
|
|
!ss->firstHsDone &&
|
|
|
|
(how_flags & PR_POLL_RW)) {
|
|
|
|
if (!ss->TCPconnected) {
|
|
|
|
ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
|
|
|
|
}
|
|
|
|
/* If it's not connected, then presumably the application is polling
|
|
|
|
** on read or write appropriately, so don't change it.
|
|
|
|
*/
|
|
|
|
if (ss->TCPconnected) {
|
|
|
|
if (!ss->handshakeBegun) {
|
|
|
|
/* If the handshake has not begun, poll on read or write
|
|
|
|
** based on the local application's role in the handshake,
|
|
|
|
** not based on what the application requested.
|
|
|
|
*/
|
|
|
|
new_flags &= ~PR_POLL_RW;
|
|
|
|
if (ss->handshaking == sslHandshakingAsClient) {
|
|
|
|
new_flags |= PR_POLL_WRITE;
|
|
|
|
} else { /* handshaking as server */
|
|
|
|
new_flags |= PR_POLL_READ;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
/* First handshake is in progress */
|
|
|
|
if (ss->lastWriteBlocked) {
|
|
|
|
if (new_flags & PR_POLL_READ) {
|
|
|
|
/* The caller is waiting for data to be received,
|
|
|
|
** but the initial handshake is blocked on write, or the
|
|
|
|
** client's first handshake record has not been written.
|
|
|
|
** The code should select on write, not read.
|
|
|
|
*/
|
|
|
|
new_flags ^= PR_POLL_READ; /* don't select on read. */
|
|
|
|
new_flags |= PR_POLL_WRITE; /* do select on write. */
|
|
|
|
}
|
|
|
|
} else if (new_flags & PR_POLL_WRITE) {
|
|
|
|
/* The caller is trying to write, but the handshake is
|
|
|
|
** blocked waiting for data to read, and the first
|
|
|
|
** handshake has been sent. so do NOT to poll on write.
|
|
|
|
*/
|
|
|
|
new_flags ^= PR_POLL_WRITE; /* don't select on write. */
|
|
|
|
new_flags |= PR_POLL_READ; /* do select on read. */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ((new_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) {
|
|
|
|
*p_out_flags = PR_POLL_READ; /* it's ready already. */
|
|
|
|
return new_flags;
|
|
|
|
} else if ((ss->lastWriteBlocked) && (how_flags & PR_POLL_READ) &&
|
|
|
|
(ss->pendingBuf.len != 0)) { /* write data waiting to be sent */
|
|
|
|
new_flags |= PR_POLL_WRITE; /* also select on write. */
|
|
|
|
}
|
|
|
|
if (new_flags && (fd->lower->methods->poll != NULL)) {
|
|
|
|
PRInt16 lower_out_flags = 0;
|
|
|
|
PRInt16 lower_new_flags;
|
|
|
|
lower_new_flags = fd->lower->methods->poll(fd->lower, new_flags,
|
|
|
|
&lower_out_flags);
|
|
|
|
if ((lower_new_flags & lower_out_flags) && (how_flags != new_flags)) {
|
|
|
|
PRInt16 out_flags = lower_out_flags & ~PR_POLL_RW;
|
|
|
|
if (lower_out_flags & PR_POLL_READ)
|
|
|
|
out_flags |= PR_POLL_WRITE;
|
|
|
|
if (lower_out_flags & PR_POLL_WRITE)
|
|
|
|
out_flags |= PR_POLL_READ;
|
|
|
|
*p_out_flags = out_flags;
|
|
|
|
new_flags = how_flags;
|
|
|
|
} else {
|
|
|
|
*p_out_flags = lower_out_flags;
|
|
|
|
new_flags = lower_new_flags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRInt32 PR_CALLBACK
|
|
|
|
ssl_TransmitFile(PRFileDesc *sd, PRFileDesc *fd,
|
|
|
|
const void *headers, PRInt32 hlen,
|
|
|
|
PRTransmitFileFlags flags, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PRSendFileData sfd;
|
|
|
|
|
|
|
|
sfd.fd = fd;
|
|
|
|
sfd.file_offset = 0;
|
|
|
|
sfd.file_nbytes = 0;
|
|
|
|
sfd.header = headers;
|
|
|
|
sfd.hlen = hlen;
|
|
|
|
sfd.trailer = NULL;
|
|
|
|
sfd.tlen = 0;
|
|
|
|
|
|
|
|
return sd->methods->sendfile(sd, &sfd, flags, timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
ssl_FdIsBlocking(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
PRSocketOptionData opt;
|
|
|
|
PRStatus status;
|
|
|
|
|
|
|
|
opt.option = PR_SockOpt_Nonblocking;
|
|
|
|
opt.value.non_blocking = PR_FALSE;
|
|
|
|
status = PR_GetSocketOption(fd, &opt);
|
|
|
|
if (status != PR_SUCCESS)
|
|
|
|
return PR_FALSE;
|
|
|
|
return (PRBool)!opt.value.non_blocking;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
ssl_SocketIsBlocking(sslSocket *ss)
|
|
|
|
{
|
|
|
|
return ssl_FdIsBlocking(ss->fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 sslFirstBufSize = 8 * 1024;
|
|
|
|
PRInt32 sslCopyLimit = 1024;
|
|
|
|
|
|
|
|
static PRInt32 PR_CALLBACK
|
|
|
|
ssl_WriteV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 vectors,
|
|
|
|
PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PRInt32 bufLen;
|
|
|
|
PRInt32 left;
|
|
|
|
PRInt32 rv;
|
|
|
|
PRInt32 sent = 0;
|
|
|
|
const PRInt32 first_len = sslFirstBufSize;
|
|
|
|
const PRInt32 limit = sslCopyLimit;
|
|
|
|
PRBool blocking;
|
|
|
|
PRIOVec myIov = { 0, 0 };
|
|
|
|
char buf[MAX_FRAGMENT_LENGTH];
|
|
|
|
|
|
|
|
if (vectors > PR_MAX_IOVECTOR_SIZE) {
|
|
|
|
PORT_SetError(PR_BUFFER_OVERFLOW_ERROR);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
blocking = ssl_FdIsBlocking(fd);
|
|
|
|
|
|
|
|
#define K16 sizeof(buf)
|
|
|
|
#define KILL_VECTORS while (vectors && !iov->iov_len) { ++iov; --vectors; }
|
|
|
|
#define GET_VECTOR do { myIov = *iov++; --vectors; KILL_VECTORS } while (0)
|
|
|
|
#define HANDLE_ERR(rv, len) \
|
|
|
|
if (rv != len) { \
|
|
|
|
if (rv < 0) { \
|
|
|
|
if (!blocking \
|
|
|
|
&& (PR_GetError() == PR_WOULD_BLOCK_ERROR) \
|
|
|
|
&& (sent > 0)) { \
|
|
|
|
return sent; \
|
|
|
|
} else { \
|
|
|
|
return -1; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
/* Only a nonblocking socket can have partial sends */ \
|
|
|
|
PR_ASSERT(!blocking); \
|
|
|
|
return sent + rv; \
|
|
|
|
}
|
|
|
|
#define SEND(bfr, len) \
|
|
|
|
do { \
|
|
|
|
rv = ssl_Send(fd, bfr, len, 0, timeout); \
|
|
|
|
HANDLE_ERR(rv, len) \
|
|
|
|
sent += len; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* Make sure the first write is at least 8 KB, if possible. */
|
|
|
|
KILL_VECTORS
|
|
|
|
if (!vectors)
|
|
|
|
return ssl_Send(fd, 0, 0, 0, timeout);
|
|
|
|
GET_VECTOR;
|
|
|
|
if (!vectors) {
|
|
|
|
return ssl_Send(fd, myIov.iov_base, myIov.iov_len, 0, timeout);
|
|
|
|
}
|
|
|
|
if (myIov.iov_len < first_len) {
|
|
|
|
PORT_Memcpy(buf, myIov.iov_base, myIov.iov_len);
|
|
|
|
bufLen = myIov.iov_len;
|
|
|
|
left = first_len - bufLen;
|
|
|
|
while (vectors && left) {
|
|
|
|
int toCopy;
|
|
|
|
GET_VECTOR;
|
|
|
|
toCopy = PR_MIN(left, myIov.iov_len);
|
|
|
|
PORT_Memcpy(buf + bufLen, myIov.iov_base, toCopy);
|
|
|
|
bufLen += toCopy;
|
|
|
|
left -= toCopy;
|
|
|
|
myIov.iov_base += toCopy;
|
|
|
|
myIov.iov_len -= toCopy;
|
|
|
|
}
|
|
|
|
SEND( buf, bufLen );
|
|
|
|
}
|
|
|
|
|
|
|
|
while (vectors || myIov.iov_len) {
|
|
|
|
PRInt32 addLen;
|
|
|
|
if (!myIov.iov_len) {
|
|
|
|
GET_VECTOR;
|
|
|
|
}
|
|
|
|
while (myIov.iov_len >= K16) {
|
|
|
|
SEND(myIov.iov_base, K16);
|
|
|
|
myIov.iov_base += K16;
|
|
|
|
myIov.iov_len -= K16;
|
|
|
|
}
|
|
|
|
if (!myIov.iov_len)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!vectors || myIov.iov_len > limit) {
|
|
|
|
addLen = 0;
|
|
|
|
} else if ((addLen = iov->iov_len % K16) + myIov.iov_len <= limit) {
|
|
|
|
/* Addlen is already computed. */;
|
|
|
|
} else if (vectors > 1 &&
|
|
|
|
iov[1].iov_len % K16 + addLen + myIov.iov_len <= 2 * limit) {
|
|
|
|
addLen = limit - myIov.iov_len;
|
|
|
|
} else
|
|
|
|
addLen = 0;
|
|
|
|
|
|
|
|
if (!addLen) {
|
|
|
|
SEND( myIov.iov_base, myIov.iov_len );
|
|
|
|
myIov.iov_len = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
PORT_Memcpy(buf, myIov.iov_base, myIov.iov_len);
|
|
|
|
bufLen = myIov.iov_len;
|
|
|
|
do {
|
|
|
|
GET_VECTOR;
|
|
|
|
PORT_Memcpy(buf + bufLen, myIov.iov_base, addLen);
|
|
|
|
myIov.iov_base += addLen;
|
|
|
|
myIov.iov_len -= addLen;
|
|
|
|
bufLen += addLen;
|
|
|
|
|
|
|
|
left = PR_MIN( limit, K16 - bufLen);
|
|
|
|
if (!vectors /* no more left */
|
|
|
|
|| myIov.iov_len > 0 /* we didn't use that one all up */
|
|
|
|
|| bufLen >= K16 /* it's full. */
|
|
|
|
) {
|
|
|
|
addLen = 0;
|
|
|
|
} else if ((addLen = iov->iov_len % K16) <= left) {
|
|
|
|
/* Addlen is already computed. */;
|
|
|
|
} else if (vectors > 1 &&
|
|
|
|
iov[1].iov_len % K16 + addLen <= left + limit) {
|
|
|
|
addLen = left;
|
|
|
|
} else
|
|
|
|
addLen = 0;
|
|
|
|
|
|
|
|
} while (addLen);
|
|
|
|
SEND( buf, bufLen );
|
|
|
|
}
|
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These functions aren't implemented.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static PRInt32 PR_CALLBACK
|
|
|
|
ssl_Available(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRInt64 PR_CALLBACK
|
|
|
|
ssl_Available64(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
PRInt64 res;
|
|
|
|
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
LL_I2L(res, -1L);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_FSync(PRFileDesc *fd)
|
|
|
|
{
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRInt32 PR_CALLBACK
|
|
|
|
ssl_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence how) {
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRInt64 PR_CALLBACK
|
|
|
|
ssl_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence how) {
|
|
|
|
PRInt64 res;
|
|
|
|
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
LL_I2L(res, -1L);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_FileInfo(PRFileDesc *fd, PRFileInfo *info)
|
|
|
|
{
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus PR_CALLBACK
|
|
|
|
ssl_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
|
|
|
|
{
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRInt32 PR_CALLBACK
|
|
|
|
ssl_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
|
|
|
|
PRNetAddr *addr, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRInt32 PR_CALLBACK
|
|
|
|
ssl_SendTo(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
|
|
|
|
const PRNetAddr *addr, PRIntervalTime timeout)
|
|
|
|
{
|
|
|
|
PORT_Assert(0);
|
|
|
|
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const PRIOMethods ssl_methods = {
|
|
|
|
PR_DESC_LAYERED,
|
|
|
|
ssl_Close, /* close */
|
|
|
|
ssl_Read, /* read */
|
|
|
|
ssl_Write, /* write */
|
|
|
|
ssl_Available, /* available */
|
|
|
|
ssl_Available64, /* available64 */
|
|
|
|
ssl_FSync, /* fsync */
|
|
|
|
ssl_Seek, /* seek */
|
|
|
|
ssl_Seek64, /* seek64 */
|
|
|
|
ssl_FileInfo, /* fileInfo */
|
|
|
|
ssl_FileInfo64, /* fileInfo64 */
|
|
|
|
ssl_WriteV, /* writev */
|
|
|
|
ssl_Connect, /* connect */
|
|
|
|
ssl_Accept, /* accept */
|
|
|
|
ssl_Bind, /* bind */
|
|
|
|
ssl_Listen, /* listen */
|
|
|
|
ssl_Shutdown, /* shutdown */
|
|
|
|
ssl_Recv, /* recv */
|
|
|
|
ssl_Send, /* send */
|
|
|
|
ssl_RecvFrom, /* recvfrom */
|
|
|
|
ssl_SendTo, /* sendto */
|
|
|
|
ssl_Poll, /* poll */
|
|
|
|
PR_EmulateAcceptRead, /* acceptread */
|
|
|
|
ssl_TransmitFile, /* transmitfile */
|
|
|
|
ssl_GetSockName, /* getsockname */
|
|
|
|
ssl_GetPeerName, /* getpeername */
|
|
|
|
NULL, /* getsockopt OBSOLETE */
|
|
|
|
NULL, /* setsockopt OBSOLETE */
|
|
|
|
NULL, /* getsocketoption */
|
|
|
|
NULL, /* setsocketoption */
|
|
|
|
PR_EmulateSendFile, /* Send a (partial) file with header/trailer*/
|
|
|
|
NULL, /* reserved for future use */
|
|
|
|
NULL, /* reserved for future use */
|
|
|
|
NULL, /* reserved for future use */
|
|
|
|
NULL, /* reserved for future use */
|
|
|
|
NULL /* reserved for future use */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PRIOMethods combined_methods;
|
|
|
|
|
|
|
|
static void
|
|
|
|
ssl_SetupIOMethods(void)
|
|
|
|
{
|
|
|
|
PRIOMethods *new_methods = &combined_methods;
|
|
|
|
const PRIOMethods *nspr_methods = PR_GetDefaultIOMethods();
|
|
|
|
const PRIOMethods *my_methods = &ssl_methods;
|
|
|
|
|
|
|
|
*new_methods = *nspr_methods;
|
|
|
|
|
|
|
|
new_methods->file_type = my_methods->file_type;
|
|
|
|
new_methods->close = my_methods->close;
|
|
|
|
new_methods->read = my_methods->read;
|
|
|
|
new_methods->write = my_methods->write;
|
|
|
|
new_methods->available = my_methods->available;
|
|
|
|
new_methods->available64 = my_methods->available64;
|
|
|
|
new_methods->fsync = my_methods->fsync;
|
|
|
|
new_methods->seek = my_methods->seek;
|
|
|
|
new_methods->seek64 = my_methods->seek64;
|
|
|
|
new_methods->fileInfo = my_methods->fileInfo;
|
|
|
|
new_methods->fileInfo64 = my_methods->fileInfo64;
|
|
|
|
new_methods->writev = my_methods->writev;
|
|
|
|
new_methods->connect = my_methods->connect;
|
|
|
|
new_methods->accept = my_methods->accept;
|
|
|
|
new_methods->bind = my_methods->bind;
|
|
|
|
new_methods->listen = my_methods->listen;
|
|
|
|
new_methods->shutdown = my_methods->shutdown;
|
|
|
|
new_methods->recv = my_methods->recv;
|
|
|
|
new_methods->send = my_methods->send;
|
|
|
|
new_methods->recvfrom = my_methods->recvfrom;
|
|
|
|
new_methods->sendto = my_methods->sendto;
|
|
|
|
new_methods->poll = my_methods->poll;
|
|
|
|
new_methods->acceptread = my_methods->acceptread;
|
|
|
|
new_methods->transmitfile = my_methods->transmitfile;
|
|
|
|
new_methods->getsockname = my_methods->getsockname;
|
|
|
|
new_methods->getpeername = my_methods->getpeername;
|
|
|
|
/* new_methods->getsocketoption = my_methods->getsocketoption; */
|
|
|
|
/* new_methods->setsocketoption = my_methods->setsocketoption; */
|
|
|
|
new_methods->sendfile = my_methods->sendfile;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRCallOnceType initIoLayerOnce;
|
|
|
|
|
|
|
|
static PRStatus
|
|
|
|
ssl_InitIOLayer(void)
|
|
|
|
{
|
|
|
|
ssl_layer_id = PR_GetUniqueIdentity("SSL");
|
|
|
|
ssl_SetupIOMethods();
|
|
|
|
ssl_inited = PR_TRUE;
|
|
|
|
return PR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRStatus
|
|
|
|
ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, PRDescIdentity id)
|
|
|
|
{
|
|
|
|
PRFileDesc *layer = NULL;
|
|
|
|
PRStatus status;
|
|
|
|
|
|
|
|
if (!ssl_inited) {
|
2011-08-19 08:27:10 -07:00
|
|
|
status = PR_CallOnce(&initIoLayerOnce, &ssl_InitIOLayer);
|
|
|
|
if (status != PR_SUCCESS)
|
|
|
|
goto loser;
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ns == NULL)
|
|
|
|
goto loser;
|
|
|
|
|
|
|
|
layer = PR_CreateIOLayerStub(ssl_layer_id, &combined_methods);
|
|
|
|
if (layer == NULL)
|
|
|
|
goto loser;
|
|
|
|
layer->secret = (PRFilePrivate *)ns;
|
|
|
|
|
|
|
|
/* Here, "stack" points to the PRFileDesc on the top of the stack.
|
|
|
|
** "layer" points to a new FD that is to be inserted into the stack.
|
|
|
|
** If layer is being pushed onto the top of the stack, then
|
|
|
|
** PR_PushIOLayer switches the contents of stack and layer, and then
|
|
|
|
** puts stack on top of layer, so that after it is done, the top of
|
|
|
|
** stack is the same "stack" as it was before, and layer is now the
|
|
|
|
** FD for the former top of stack.
|
|
|
|
** After this call, stack always points to the top PRFD on the stack.
|
|
|
|
** If this function fails, the contents of stack and layer are as
|
|
|
|
** they were before the call.
|
|
|
|
*/
|
|
|
|
status = PR_PushIOLayer(stack, id, layer);
|
|
|
|
if (status != PR_SUCCESS)
|
|
|
|
goto loser;
|
|
|
|
|
|
|
|
ns->fd = (id == PR_TOP_IO_LAYER) ? stack : layer;
|
|
|
|
return PR_SUCCESS;
|
|
|
|
|
|
|
|
loser:
|
|
|
|
if (layer) {
|
|
|
|
layer->dtor(layer); /* free layer */
|
|
|
|
}
|
|
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if this fails, caller must destroy socket. */
|
|
|
|
static SECStatus
|
|
|
|
ssl_MakeLocks(sslSocket *ss)
|
|
|
|
{
|
|
|
|
ss->firstHandshakeLock = PZ_NewMonitor(nssILockSSL);
|
|
|
|
if (!ss->firstHandshakeLock)
|
|
|
|
goto loser;
|
|
|
|
ss->ssl3HandshakeLock = PZ_NewMonitor(nssILockSSL);
|
|
|
|
if (!ss->ssl3HandshakeLock)
|
|
|
|
goto loser;
|
|
|
|
ss->specLock = NSSRWLock_New(SSL_LOCK_RANK_SPEC, NULL);
|
|
|
|
if (!ss->specLock)
|
|
|
|
goto loser;
|
|
|
|
ss->recvBufLock = PZ_NewMonitor(nssILockSSL);
|
|
|
|
if (!ss->recvBufLock)
|
|
|
|
goto loser;
|
|
|
|
ss->xmitBufLock = PZ_NewMonitor(nssILockSSL);
|
|
|
|
if (!ss->xmitBufLock)
|
|
|
|
goto loser;
|
|
|
|
ss->writerThread = NULL;
|
|
|
|
if (ssl_lock_readers) {
|
|
|
|
ss->recvLock = PZ_NewLock(nssILockSSL);
|
|
|
|
if (!ss->recvLock)
|
|
|
|
goto loser;
|
|
|
|
ss->sendLock = PZ_NewLock(nssILockSSL);
|
|
|
|
if (!ss->sendLock)
|
|
|
|
goto loser;
|
|
|
|
}
|
|
|
|
return SECSuccess;
|
|
|
|
loser:
|
|
|
|
ssl_DestroyLocks(ss);
|
|
|
|
return SECFailure;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
|
|
|
|
#define NSS_HAVE_GETENV 1
|
|
|
|
#endif
|
|
|
|
|
2010-02-07 03:54:28 -08:00
|
|
|
#define LOWER(x) (x | 0x20) /* cheap ToLower function ignores LOCALE */
|
|
|
|
|
Bug 673382: Update NSS to NSS_3_12_11_BETA1, which includes the fixes for
Bug 661609, Bug 650276 (code not used by Mozilla), Bug 602509, Bug 655411,
Bug 655850, Bug 671711, Bug 617565, Bug 668001, Bug 346583, Bug 661061.
2011-07-27 09:07:32 -07:00
|
|
|
static void
|
|
|
|
ssl_SetDefaultsFromEnvironment(void)
|
2008-06-06 05:40:11 -07:00
|
|
|
{
|
|
|
|
#if defined( NSS_HAVE_GETENV )
|
|
|
|
static int firsttime = 1;
|
|
|
|
|
|
|
|
if (firsttime) {
|
|
|
|
char * ev;
|
|
|
|
firsttime = 0;
|
|
|
|
#ifdef DEBUG
|
|
|
|
ev = getenv("SSLDEBUGFILE");
|
|
|
|
if (ev && ev[0]) {
|
|
|
|
ssl_trace_iob = fopen(ev, "w");
|
|
|
|
}
|
|
|
|
if (!ssl_trace_iob) {
|
|
|
|
ssl_trace_iob = stderr;
|
|
|
|
}
|
|
|
|
#ifdef TRACE
|
|
|
|
ev = getenv("SSLTRACE");
|
|
|
|
if (ev && ev[0]) {
|
|
|
|
ssl_trace = atoi(ev);
|
|
|
|
SSL_TRACE(("SSL: tracing set to %d", ssl_trace));
|
|
|
|
}
|
2010-02-07 03:54:28 -08:00
|
|
|
ev = getenv("SSLKEYLOGFILE");
|
|
|
|
if (ev && ev[0]) {
|
|
|
|
ssl_keylog_iob = fopen(ev, "a");
|
|
|
|
if (ftell(ssl_keylog_iob) == 0) {
|
|
|
|
fputs("# pre-master secret log file, generated by NSS\n",
|
|
|
|
ssl_keylog_iob);
|
|
|
|
}
|
|
|
|
SSL_TRACE(("SSL: logging pre-master secrets to %s", ev));
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
#endif /* TRACE */
|
|
|
|
ev = getenv("SSLDEBUG");
|
|
|
|
if (ev && ev[0]) {
|
|
|
|
ssl_debug = atoi(ev);
|
|
|
|
SSL_TRACE(("SSL: debugging set to %d", ssl_debug));
|
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
ev = getenv("SSLBYPASS");
|
|
|
|
if (ev && ev[0]) {
|
|
|
|
ssl_defaults.bypassPKCS11 = (ev[0] == '1');
|
|
|
|
SSL_TRACE(("SSL: bypass default set to %d", \
|
|
|
|
ssl_defaults.bypassPKCS11));
|
|
|
|
}
|
|
|
|
ev = getenv("SSLFORCELOCKS");
|
|
|
|
if (ev && ev[0] == '1') {
|
|
|
|
ssl_force_locks = PR_TRUE;
|
|
|
|
ssl_defaults.noLocks = 0;
|
|
|
|
strcpy(lockStatus + LOCKSTATUS_OFFSET, "FORCED. ");
|
|
|
|
SSL_TRACE(("SSL: force_locks set to %d", ssl_force_locks));
|
|
|
|
}
|
2010-02-07 03:54:28 -08:00
|
|
|
ev = getenv("NSS_SSL_ENABLE_RENEGOTIATION");
|
|
|
|
if (ev) {
|
|
|
|
if (ev[0] == '1' || LOWER(ev[0]) == 'u')
|
|
|
|
ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_UNRESTRICTED;
|
|
|
|
else if (ev[0] == '0' || LOWER(ev[0]) == 'n')
|
|
|
|
ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER;
|
2010-03-05 05:44:10 -08:00
|
|
|
else if (ev[0] == '2' || LOWER(ev[0]) == 'r')
|
|
|
|
ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN;
|
|
|
|
else if (ev[0] == '3' || LOWER(ev[0]) == 't')
|
|
|
|
ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_TRANSITIONAL;
|
2010-02-07 03:54:28 -08:00
|
|
|
SSL_TRACE(("SSL: enableRenegotiation set to %d",
|
|
|
|
ssl_defaults.enableRenegotiation));
|
|
|
|
}
|
|
|
|
ev = getenv("NSS_SSL_REQUIRE_SAFE_NEGOTIATION");
|
|
|
|
if (ev && ev[0] == '1') {
|
|
|
|
ssl_defaults.requireSafeNegotiation = PR_TRUE;
|
|
|
|
SSL_TRACE(("SSL: requireSafeNegotiation set to %d",
|
|
|
|
PR_TRUE));
|
|
|
|
}
|
2011-10-07 13:37:26 -07:00
|
|
|
ev = getenv("NSS_SSL_CBC_RANDOM_IV");
|
|
|
|
if (ev && ev[0] == '0') {
|
|
|
|
ssl_defaults.cbcRandomIV = PR_FALSE;
|
|
|
|
SSL_TRACE(("SSL: cbcRandomIV set to 0"));
|
|
|
|
}
|
2008-06-06 05:40:11 -07:00
|
|
|
}
|
|
|
|
#endif /* NSS_HAVE_GETENV */
|
Bug 673382: Update NSS to NSS_3_12_11_BETA1, which includes the fixes for
Bug 661609, Bug 650276 (code not used by Mozilla), Bug 602509, Bug 655411,
Bug 655850, Bug 671711, Bug 617565, Bug 668001, Bug 346583, Bug 661061.
2011-07-27 09:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Create a newsocket structure for a file descriptor.
|
|
|
|
*/
|
|
|
|
static sslSocket *
|
|
|
|
ssl_NewSocket(PRBool makeLocks)
|
|
|
|
{
|
|
|
|
sslSocket *ss;
|
|
|
|
|
|
|
|
ssl_SetDefaultsFromEnvironment();
|
|
|
|
|
2008-06-06 05:40:11 -07:00
|
|
|
if (ssl_force_locks)
|
|
|
|
makeLocks = PR_TRUE;
|
|
|
|
|
|
|
|
/* Make a new socket and get it ready */
|
|
|
|
ss = (sslSocket*) PORT_ZAlloc(sizeof(sslSocket));
|
|
|
|
if (ss) {
|
|
|
|
/* This should be of type SSLKEAType, but CC on IRIX
|
|
|
|
* complains during the for loop.
|
|
|
|
*/
|
|
|
|
int i;
|
|
|
|
SECStatus status;
|
|
|
|
|
|
|
|
ss->opt = ssl_defaults;
|
|
|
|
ss->opt.useSocks = PR_FALSE;
|
|
|
|
ss->opt.noLocks = !makeLocks;
|
|
|
|
|
|
|
|
ss->peerID = NULL;
|
|
|
|
ss->rTimeout = PR_INTERVAL_NO_TIMEOUT;
|
|
|
|
ss->wTimeout = PR_INTERVAL_NO_TIMEOUT;
|
|
|
|
ss->cTimeout = PR_INTERVAL_NO_TIMEOUT;
|
|
|
|
ss->cipherSpecs = NULL;
|
|
|
|
ss->sizeCipherSpecs = 0; /* produced lazily */
|
|
|
|
ss->preferredCipher = NULL;
|
|
|
|
ss->url = NULL;
|
|
|
|
|
|
|
|
for (i=kt_null; i < kt_kea_size; i++) {
|
|
|
|
sslServerCerts * sc = ss->serverCerts + i;
|
|
|
|
sc->serverCert = NULL;
|
|
|
|
sc->serverCertChain = NULL;
|
|
|
|
sc->serverKeyPair = NULL;
|
|
|
|
sc->serverKeyBits = 0;
|
|
|
|
}
|
|
|
|
ss->stepDownKeyPair = NULL;
|
|
|
|
ss->dbHandle = CERT_GetDefaultCertDB();
|
|
|
|
|
|
|
|
/* Provide default implementation of hooks */
|
|
|
|
ss->authCertificate = SSL_AuthCertificate;
|
|
|
|
ss->authCertificateArg = (void *)ss->dbHandle;
|
2010-02-07 03:54:28 -08:00
|
|
|
ss->sniSocketConfig = NULL;
|
|
|
|
ss->sniSocketConfigArg = NULL;
|
2008-06-06 05:40:11 -07:00
|
|
|
ss->getClientAuthData = NULL;
|
|
|
|
ss->handleBadCert = NULL;
|
|
|
|
ss->badCertArg = NULL;
|
|
|
|
ss->pkcs11PinArg = NULL;
|
|
|
|
|
|
|
|
ssl_ChooseOps(ss);
|
|
|
|
ssl2_InitSocketPolicy(ss);
|
|
|
|
ssl3_InitSocketPolicy(ss);
|
|
|
|
|
|
|
|
if (makeLocks) {
|
|
|
|
status = ssl_MakeLocks(ss);
|
|
|
|
if (status != SECSuccess)
|
|
|
|
goto loser;
|
|
|
|
}
|
|
|
|
status = ssl_CreateSecurityInfo(ss);
|
|
|
|
if (status != SECSuccess)
|
|
|
|
goto loser;
|
|
|
|
status = ssl_InitGather(&ss->gs);
|
|
|
|
if (status != SECSuccess) {
|
|
|
|
loser:
|
|
|
|
ssl_DestroySocketContents(ss);
|
|
|
|
ssl_DestroyLocks(ss);
|
|
|
|
PORT_Free(ss);
|
|
|
|
ss = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
|