Source code

Revision control

Other Tools

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* vtables (and methods that call through them) for the 4 types of
* SSLSockets supported. Only one type is still supported.
* Various other functions.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "seccomon.h"
#include "cert.h"
#include "keyhi.h"
#include "ssl.h"
#include "sslexp.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "nspr.h"
#include "private/pprio.h"
#include "nss.h"
#include "pk11pqg.h"
#include "pk11pub.h"
#include "tls13ech.h"
#include "tls13psk.h"
#include "tls13subcerts.h"
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 = {
.nextProtoNego = { siBuffer, NULL, 0 },
.maxEarlyDataSize = 1 << 16,
.recordSizeLimit = MAX_FRAGMENT_LENGTH + 1,
.useSecurity = PR_TRUE,
.useSocks = PR_FALSE,
.requestCertificate = PR_FALSE,
.requireCertificate = SSL_REQUIRE_FIRST_HANDSHAKE,
.handshakeAsClient = PR_FALSE,
.handshakeAsServer = PR_FALSE,
.noCache = PR_FALSE,
.fdx = PR_FALSE,
.detectRollBack = PR_TRUE,
.noLocks = PR_FALSE,
.enableSessionTickets = PR_FALSE,
.enableDeflate = PR_FALSE,
.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN,
.requireSafeNegotiation = PR_FALSE,
.enableFalseStart = PR_FALSE,
.cbcRandomIV = PR_TRUE,
.enableOCSPStapling = PR_FALSE,
.enableDelegatedCredentials = PR_FALSE,
.enableALPN = PR_TRUE,
.reuseServerECDHEKey = PR_TRUE,
.enableFallbackSCSV = PR_FALSE,
.enableServerDhe = PR_TRUE,
.enableExtendedMS = PR_TRUE,
.enableSignedCertTimestamps = PR_FALSE,
.requireDHENamedGroups = PR_FALSE,
.enable0RttData = PR_FALSE,
.enableTls13CompatMode = PR_FALSE,
.enableDtls13VersionCompat = PR_FALSE,
.enableDtlsShortHeader = PR_FALSE,
.enableHelloDowngradeCheck = PR_FALSE,
.enableV2CompatibleHello = PR_FALSE,
.enablePostHandshakeAuth = PR_FALSE,
.suppressEndOfEarlyData = PR_FALSE,
.enableTls13GreaseEch = PR_FALSE,
.enableTls13BackendEch = PR_FALSE
};
/*
* default range of enabled SSL/TLS protocols
*/
static SSLVersionRange versions_defaults_stream = {
SSL_LIBRARY_VERSION_TLS_1_0,
SSL_LIBRARY_VERSION_TLS_1_3
};
static SSLVersionRange versions_defaults_datagram = {
SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_2
};
#define VERSIONS_DEFAULTS(variant) \
(variant == ssl_variant_stream ? &versions_defaults_stream : &versions_defaults_datagram)
#define VERSIONS_POLICY_MIN(variant) \
(variant == ssl_variant_stream ? NSS_TLS_VERSION_MIN_POLICY : NSS_DTLS_VERSION_MIN_POLICY)
#define VERSIONS_POLICY_MAX(variant) \
(variant == ssl_variant_stream ? NSS_TLS_VERSION_MAX_POLICY : NSS_DTLS_VERSION_MAX_POLICY)
sslSessionIDLookupFunc ssl_sid_lookup;
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;
#ifdef NSS_ALLOW_SSLKEYLOGFILE
FILE *ssl_keylog_iob;
PZLock *ssl_keylog_lock;
#endif
char lockStatus[] = "Locks are ENABLED. ";
#define LOCKSTATUS_OFFSET 10 /* offset of ENABLED */
/* SRTP_NULL_HMAC_SHA1_80 and SRTP_NULL_HMAC_SHA1_32 are not implemented. */
static const PRUint16 srtpCiphers[] = {
SRTP_AES128_CM_HMAC_SHA1_80,
SRTP_AES128_CM_HMAC_SHA1_32,
0
};
/* This list is in preference order. Note that while some smaller groups appear
* early in the list, smaller groups are generally ignored when iterating
* through this list. ffdhe_custom must not appear in this list. */
#define ECGROUP(name, size, oid, assumeSupported) \
{ \
ssl_grp_ec_##name, size, ssl_kea_ecdh, \
SEC_OID_SECG_EC_##oid, assumeSupported \
}
#define FFGROUP(size) \
{ \
ssl_grp_ffdhe_##size, size, ssl_kea_dh, \
SEC_OID_TLS_FFDHE_##size, PR_TRUE \
}
const sslNamedGroupDef ssl_named_groups[] = {
/* Note that 256 for 25519 is a lie, but we only use it for checking bit
* security and expect 256 bits there (not 255). */
{ ssl_grp_ec_curve25519, 256, ssl_kea_ecdh, SEC_OID_CURVE25519, PR_TRUE },
ECGROUP(secp256r1, 256, SECP256R1, PR_TRUE),
ECGROUP(secp384r1, 384, SECP384R1, PR_TRUE),
ECGROUP(secp521r1, 521, SECP521R1, PR_TRUE),
FFGROUP(2048),
FFGROUP(3072),
FFGROUP(4096),
FFGROUP(6144),
FFGROUP(8192),
ECGROUP(secp192r1, 192, SECP192R1, PR_FALSE),
ECGROUP(secp160r2, 160, SECP160R2, PR_FALSE),
ECGROUP(secp160k1, 160, SECP160K1, PR_FALSE),
ECGROUP(secp160r1, 160, SECP160R1, PR_FALSE),
ECGROUP(sect163k1, 163, SECT163K1, PR_FALSE),
ECGROUP(sect163r1, 163, SECT163R1, PR_FALSE),
ECGROUP(sect163r2, 163, SECT163R2, PR_FALSE),
ECGROUP(secp192k1, 192, SECP192K1, PR_FALSE),
ECGROUP(sect193r1, 193, SECT193R1, PR_FALSE),
ECGROUP(sect193r2, 193, SECT193R2, PR_FALSE),
ECGROUP(secp224r1, 224, SECP224R1, PR_FALSE),
ECGROUP(secp224k1, 224, SECP224K1, PR_FALSE),
ECGROUP(sect233k1, 233, SECT233K1, PR_FALSE),
ECGROUP(sect233r1, 233, SECT233R1, PR_FALSE),
ECGROUP(sect239k1, 239, SECT239K1, PR_FALSE),
ECGROUP(secp256k1, 256, SECP256K1, PR_FALSE),
ECGROUP(sect283k1, 283, SECT283K1, PR_FALSE),
ECGROUP(sect283r1, 283, SECT283R1, PR_FALSE),
ECGROUP(sect409k1, 409, SECT409K1, PR_FALSE),
ECGROUP(sect409r1, 409, SECT409R1, PR_FALSE),
ECGROUP(sect571k1, 571, SECT571K1, PR_FALSE),
ECGROUP(sect571r1, 571, SECT571R1, PR_FALSE),
};
PR_STATIC_ASSERT(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(ssl_named_groups));
#undef ECGROUP
#undef FFGROUP
/* forward declarations. */
static sslSocket *ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant variant);
static SECStatus ssl_MakeLocks(sslSocket *ss);
static void ssl_SetDefaultsFromEnvironment(void);
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;
/* Set ss->fd lazily. We can't rely on the value of ss->fd set by
* ssl_PushIOLayer because another PR_PushIOLayer call will switch the
* contents of the PRFileDesc pointed by ss->fd and the new layer.
* See bug 807250.
*/
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;
/* Set ss->fd lazily. We can't rely on the value of ss->fd set by
* ssl_PushIOLayer because another PR_PushIOLayer call will switch the
* contents of the PRFileDesc pointed by ss->fd and the new layer.
* See bug 807250.
*/
ss->fd = layer;
return ss;
}
static sslSocket *
ssl_DupSocket(sslSocket *os)
{
sslSocket *ss;
SECStatus rv;
ss = ssl_NewSocket((PRBool)(!os->opt.noLocks), os->protocolVariant);
if (!ss) {
return NULL;
}
ss->opt = os->opt;
ss->opt.useSocks = PR_FALSE;
rv = SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &os->opt.nextProtoNego);
if (rv != SECSuccess) {
goto loser;
}
ss->vrange = os->vrange;
ss->now = os->now;
ss->nowArg = os->nowArg;
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) */
PORT_Memcpy(ss->cipherSuites, os->cipherSuites, sizeof os->cipherSuites);
PORT_Memcpy(ss->ssl3.dtlsSRTPCiphers, os->ssl3.dtlsSRTPCiphers,
sizeof(PRUint16) * os->ssl3.dtlsSRTPCipherCount);
ss->ssl3.dtlsSRTPCipherCount = os->ssl3.dtlsSRTPCipherCount;
PORT_Memcpy(ss->ssl3.signatureSchemes, os->ssl3.signatureSchemes,
sizeof(ss->ssl3.signatureSchemes[0]) *
os->ssl3.signatureSchemeCount);
ss->ssl3.signatureSchemeCount = os->ssl3.signatureSchemeCount;
ss->ssl3.downgradeCheckVersion = os->ssl3.downgradeCheckVersion;
ss->ssl3.dheWeakGroupEnabled = os->ssl3.dheWeakGroupEnabled;
if (ss->opt.useSecurity) {
PRCList *cursor;
for (cursor = PR_NEXT_LINK(&os->serverCerts);
cursor != &os->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *sc = ssl_CopyServerCert((sslServerCert *)cursor);
if (!sc)
goto loser;
PR_APPEND_LINK(&sc->link, &ss->serverCerts);
}
for (cursor = PR_NEXT_LINK(&os->ephemeralKeyPairs);
cursor != &os->ephemeralKeyPairs;
cursor = PR_NEXT_LINK(cursor)) {
sslEphemeralKeyPair *okp = (sslEphemeralKeyPair *)cursor;
sslEphemeralKeyPair *skp = ssl_CopyEphemeralKeyPair(okp);
if (!skp)
goto loser;
PR_APPEND_LINK(&skp->link, &ss->ephemeralKeyPairs);
}
for (cursor = PR_NEXT_LINK(&os->extensionHooks);
cursor != &os->extensionHooks;
cursor = PR_NEXT_LINK(cursor)) {
sslCustomExtensionHooks *oh = (sslCustomExtensionHooks *)cursor;
sslCustomExtensionHooks *sh = PORT_ZNew(sslCustomExtensionHooks);
if (!sh) {
goto loser;
}
*sh = *oh;
PR_APPEND_LINK(&sh->link, &ss->extensionHooks);
}
/*
* XXX the preceding CERT_ and SECKEY_ functions can fail and return NULL.
* 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;
ss->sniSocketConfig = os->sniSocketConfig;
ss->sniSocketConfigArg = os->sniSocketConfigArg;
ss->alertReceivedCallback = os->alertReceivedCallback;
ss->alertReceivedCallbackArg = os->alertReceivedCallbackArg;
ss->alertSentCallback = os->alertSentCallback;
ss->alertSentCallbackArg = os->alertSentCallbackArg;
ss->handleBadCert = os->handleBadCert;
ss->badCertArg = os->badCertArg;
ss->handshakeCallback = os->handshakeCallback;
ss->handshakeCallbackData = os->handshakeCallbackData;
ss->canFalseStartCallback = os->canFalseStartCallback;
ss->canFalseStartCallbackData = os->canFalseStartCallbackData;
ss->pkcs11PinArg = os->pkcs11PinArg;
ss->nextProtoCallback = os->nextProtoCallback;
ss->nextProtoArg = os->nextProtoArg;
PORT_Memcpy((void *)ss->namedGroupPreferences,
os->namedGroupPreferences,
sizeof(ss->namedGroupPreferences));
ss->additionalShares = os->additionalShares;
ss->resumptionTokenCallback = os->resumptionTokenCallback;
ss->resumptionTokenContext = os->resumptionTokenContext;
rv = tls13_CopyEchConfigs(&os->echConfigs, &ss->echConfigs);
if (rv != SECSuccess) {
goto loser;
}
if (os->echPrivKey && os->echPubKey) {
ss->echPrivKey = SECKEY_CopyPrivateKey(os->echPrivKey);
ss->echPubKey = SECKEY_CopyPublicKey(os->echPubKey);
if (!ss->echPrivKey || !ss->echPubKey) {
goto loser;
}
}
if (os->antiReplay) {
ss->antiReplay = tls13_RefAntiReplayContext(os->antiReplay);
PORT_Assert(ss->antiReplay); /* Can't fail. */
if (!ss->antiReplay) {
goto loser;
}
}
if (os->psk) {
ss->psk = tls13_CopyPsk(os->psk);
if (!ss->psk) {
goto loser;
}
}
/* 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)
{
PRCList *cursor;
/* Free up socket */
ssl_DestroySecurityInfo(&ss->sec);
ssl3_DestroySSL3Info(ss);
PORT_Free(ss->saveBuf.buf);
PORT_Free(ss->pendingBuf.buf);
ssl3_DestroyGather(&ss->gs);
if (ss->peerID != NULL)
PORT_Free(ss->peerID);
if (ss->url != NULL)
PORT_Free((void *)ss->url); /* CONST */
/* Clean up server certificates and sundries. */
while (!PR_CLIST_IS_EMPTY(&ss->serverCerts)) {
cursor = PR_LIST_TAIL(&ss->serverCerts);
PR_REMOVE_LINK(cursor);
ssl_FreeServerCert((sslServerCert *)cursor);
}
/* Remove extension handlers. */
ssl_ClearPRCList(&ss->extensionHooks, NULL);
ssl_FreeEphemeralKeyPairs(ss);
SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
ssl3_FreeSniNameArray(&ss->xtnData);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
tls13_DestroyPskList(&ss->ssl3.hs.psks);
tls13_ReleaseAntiReplayContext(ss->antiReplay);
tls13_DestroyPsk(ss->psk);
tls13_DestroyEchConfigs(&ss->echConfigs);
SECKEY_DestroyPrivateKey(ss->echPrivKey);
SECKEY_DestroyPublicKey(ss->echPubKey);
}
/*
* free an sslSocket struct, and all the stuff that hangs off of it
*/
void
ssl_FreeSocket(sslSocket *ss)
{
/* 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);
ssl_DestroySocketContents(ss);
/* Release all the locks acquired above. */
SSL_UNLOCK_READER(ss);
SSL_UNLOCK_WRITER(ss);
ssl_Release1stHandshakeLock(ss);
ssl_ReleaseRecvBufLock(ss);
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_ReleaseXmitBufLock(ss);
ssl_ReleaseSpecWriteLock(ss);
ssl_DestroyLocks(ss);
#ifdef DEBUG
PORT_Memset(ss, 0x1f, sizeof *ss);
#endif
PORT_Free(ss);
return;
}
/************************************************************************/
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, PRIntn on)
{
return SSL_OptionSet(fd, which, on);
}
static PRBool ssl_VersionIsSupportedByPolicy(
SSLProtocolVariant protocolVariant, SSL3ProtocolVersion version);
/* Implements the semantics for SSL_OptionSet(SSL_ENABLE_TLS, on) described in
* ssl.h in the section "SSL version range setting API".
*/
static void
ssl_EnableTLS(SSLVersionRange *vrange, PRIntn enable)
{
if (enable) {
/* don't turn it on if tls1.0 disallowed by by policy */
if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream,
SSL_LIBRARY_VERSION_TLS_1_0)) {
return;
}
}
if (SSL_ALL_VERSIONS_DISABLED(vrange)) {
if (enable) {
vrange->min = SSL_LIBRARY_VERSION_TLS_1_0;
vrange->max = SSL_LIBRARY_VERSION_TLS_1_0;
} /* else don't change anything */
return;
}
if (enable) {
/* Expand the range of enabled version to include TLS 1.0 */
vrange->min = PR_MIN(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0);
vrange->max = PR_MAX(vrange->max, SSL_LIBRARY_VERSION_TLS_1_0);
} else {
/* Disable all TLS versions, leaving only SSL 3.0 if it was enabled */
if (vrange->min == SSL_LIBRARY_VERSION_3_0) {
vrange->max = SSL_LIBRARY_VERSION_3_0;
} else {
/* Only TLS was enabled, so now no versions are. */
vrange->min = SSL_LIBRARY_VERSION_NONE;
vrange->max = SSL_LIBRARY_VERSION_NONE;
}
}
}
/* Implements the semantics for SSL_OptionSet(SSL_ENABLE_SSL3, on) described in
* ssl.h in the section "SSL version range setting API".
*/
static void
ssl_EnableSSL3(SSLVersionRange *vrange, PRIntn enable)
{
if (enable) {
/* don't turn it on if ssl3 disallowed by by policy */
if (!ssl_VersionIsSupportedByPolicy(ssl_variant_stream,
SSL_LIBRARY_VERSION_3_0)) {
return;
}
}
if (SSL_ALL_VERSIONS_DISABLED(vrange)) {
if (enable) {
vrange->min = SSL_LIBRARY_VERSION_3_0;
vrange->max = SSL_LIBRARY_VERSION_3_0;
} /* else don't change anything */
return;
}
if (enable) {
/* Expand the range of enabled versions to include SSL 3.0. We know
* SSL 3.0 or some version of TLS is already enabled at this point, so
* we don't need to change vrange->max.
*/
vrange->min = SSL_LIBRARY_VERSION_3_0;
} else {
/* Disable SSL 3.0, leaving TLS unaffected. */
if (vrange->max > SSL_LIBRARY_VERSION_3_0) {
vrange->min = PR_MAX(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0);
} else {
/* Only SSL 3.0 was enabled, so now no versions are. */
vrange->min = SSL_LIBRARY_VERSION_NONE;
vrange->max = SSL_LIBRARY_VERSION_NONE;
}
}
}
SECStatus
SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
{
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 (val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
}
break;
case SSL_SECURITY:
ss->opt.useSecurity = val;
rv = PrepareSocket(ss);
break;
case SSL_REQUEST_CERTIFICATE:
ss->opt.requestCertificate = val;
break;
case SSL_REQUIRE_CERTIFICATE:
ss->opt.requireCertificate = val;
break;
case SSL_HANDSHAKE_AS_CLIENT:
if (ss->opt.handshakeAsServer && val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
break;
}
ss->opt.handshakeAsClient = val;
break;
case SSL_HANDSHAKE_AS_SERVER:
if (ss->opt.handshakeAsClient && val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
break;
}
ss->opt.handshakeAsServer = val;
break;
case SSL_ENABLE_TLS:
if (IS_DTLS(ss)) {
if (val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure; /* not allowed */
}
break;
}
ssl_EnableTLS(&ss->vrange, val);
break;
case SSL_ENABLE_SSL3:
if (IS_DTLS(ss)) {
if (val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure; /* not allowed */
}
break;
}
ssl_EnableSSL3(&ss->vrange, val);
break;
case SSL_ENABLE_SSL2:
case SSL_V2_COMPATIBLE_HELLO:
/* We no longer support SSL v2.
* However, if an old application requests to disable SSL v2,
* we shouldn't fail.
*/
if (val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
}
break;
case SSL_NO_CACHE:
ss->opt.noCache = val;
break;
case SSL_ENABLE_FDX:
if (val && ss->opt.noLocks) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
}
ss->opt.fdx = val;
break;
case SSL_ROLLBACK_DETECTION:
ss->opt.detectRollBack = val;
break;
case SSL_NO_STEP_DOWN:
break;
case SSL_BYPASS_PKCS11:
break;
case SSL_NO_LOCKS:
if (val && ss->opt.fdx) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
}
if (val && ssl_force_locks)
val = PR_FALSE; /* silent override */
ss->opt.noLocks = val;
if (val) {
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 = val;
break;
case SSL_ENABLE_DEFLATE:
ss->opt.enableDeflate = val;
break;
case SSL_ENABLE_RENEGOTIATION:
if (IS_DTLS(ss) && val != SSL_RENEGOTIATE_NEVER) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
break;
}
ss->opt.enableRenegotiation = val;
break;
case SSL_REQUIRE_SAFE_NEGOTIATION:
ss->opt.requireSafeNegotiation = val;
break;
case SSL_ENABLE_FALSE_START:
ss->opt.enableFalseStart = val;
break;
case SSL_CBC_RANDOM_IV:
ss->opt.cbcRandomIV = val;
break;
case SSL_ENABLE_OCSP_STAPLING:
ss->opt.enableOCSPStapling = val;
break;
case SSL_ENABLE_DELEGATED_CREDENTIALS:
ss->opt.enableDelegatedCredentials = val;
break;
case SSL_ENABLE_NPN:
break;
case SSL_ENABLE_ALPN:
ss->opt.enableALPN = val;
break;
case SSL_REUSE_SERVER_ECDHE_KEY:
ss->opt.reuseServerECDHEKey = val;
break;
case SSL_ENABLE_FALLBACK_SCSV:
ss->opt.enableFallbackSCSV = val;
break;
case SSL_ENABLE_SERVER_DHE:
ss->opt.enableServerDhe = val;
break;
case SSL_ENABLE_EXTENDED_MASTER_SECRET:
ss->opt.enableExtendedMS = val;
break;
case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
ss->opt.enableSignedCertTimestamps = val;
break;
case SSL_REQUIRE_DH_NAMED_GROUPS:
ss->opt.requireDHENamedGroups = val;
break;
case SSL_ENABLE_0RTT_DATA:
ss->opt.enable0RttData = val;
break;
case SSL_RECORD_SIZE_LIMIT:
if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
} else {
ss->opt.recordSizeLimit = val;
}
break;
case SSL_ENABLE_TLS13_COMPAT_MODE:
ss->opt.enableTls13CompatMode = val;
break;
case SSL_ENABLE_DTLS_SHORT_HEADER:
ss->opt.enableDtlsShortHeader = val;
break;
case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
ss->opt.enableHelloDowngradeCheck = val;
break;
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
ss->opt.enableV2CompatibleHello = val;
break;
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
ss->opt.enablePostHandshakeAuth = val;
break;
case SSL_SUPPRESS_END_OF_EARLY_DATA:
ss->opt.suppressEndOfEarlyData = val;
break;
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, PRIntn *pVal)
{
sslSocket *ss = ssl_FindSocket(fd);
SECStatus rv = SECSuccess;
PRIntn val = PR_FALSE;
if (!pVal) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in Enable", SSL_GETPID(), fd));
*pVal = PR_FALSE;
return SECFailure;
}
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
switch (which) {
case SSL_SOCKS:
val = PR_FALSE;
break;
case SSL_SECURITY:
val = ss->opt.useSecurity;
break;
case SSL_REQUEST_CERTIFICATE:
val = ss->opt.requestCertificate;
break;
case SSL_REQUIRE_CERTIFICATE:
val = ss->opt.requireCertificate;
break;
case SSL_HANDSHAKE_AS_CLIENT:
val = ss->opt.handshakeAsClient;
break;
case SSL_HANDSHAKE_AS_SERVER:
val = ss->opt.handshakeAsServer;
break;
case SSL_ENABLE_TLS:
val = ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_0;
break;
case SSL_ENABLE_SSL3:
val = ss->vrange.min == SSL_LIBRARY_VERSION_3_0;
break;
case SSL_ENABLE_SSL2:
case SSL_V2_COMPATIBLE_HELLO:
val = PR_FALSE;
break;
case SSL_NO_CACHE:
val = ss->opt.noCache;
break;
case SSL_ENABLE_FDX:
val = ss->opt.fdx;
break;
case SSL_ROLLBACK_DETECTION:
val = ss->opt.detectRollBack;
break;
case SSL_NO_STEP_DOWN:
val = PR_FALSE;
break;
case SSL_BYPASS_PKCS11:
val = PR_FALSE;
break;
case SSL_NO_LOCKS:
val = ss->opt.noLocks;
break;
case SSL_ENABLE_SESSION_TICKETS:
val = ss->opt.enableSessionTickets;
break;
case SSL_ENABLE_DEFLATE:
val = ss->opt.enableDeflate;
break;
case SSL_ENABLE_RENEGOTIATION:
val = ss->opt.enableRenegotiation;
break;
case SSL_REQUIRE_SAFE_NEGOTIATION:
val = ss->opt.requireSafeNegotiation;
break;
case SSL_ENABLE_FALSE_START:
val = ss->opt.enableFalseStart;
break;
case SSL_CBC_RANDOM_IV:
val = ss->opt.cbcRandomIV;
break;
case SSL_ENABLE_OCSP_STAPLING:
val = ss->opt.enableOCSPStapling;
break;
case SSL_ENABLE_DELEGATED_CREDENTIALS:
val = ss->opt.enableDelegatedCredentials;
break;
case SSL_ENABLE_NPN:
val = PR_FALSE;
break;
case SSL_ENABLE_ALPN:
val = ss->opt.enableALPN;
break;
case SSL_REUSE_SERVER_ECDHE_KEY:
val = ss->opt.reuseServerECDHEKey;
break;
case SSL_ENABLE_FALLBACK_SCSV:
val = ss->opt.enableFallbackSCSV;
break;
case SSL_ENABLE_SERVER_DHE:
val = ss->opt.enableServerDhe;
break;
case SSL_ENABLE_EXTENDED_MASTER_SECRET:
val = ss->opt.enableExtendedMS;
break;
case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
val = ss->opt.enableSignedCertTimestamps;
break;
case SSL_REQUIRE_DH_NAMED_GROUPS:
val = ss->opt.requireDHENamedGroups;
break;
case SSL_ENABLE_0RTT_DATA:
val = ss->opt.enable0RttData;
break;
case SSL_RECORD_SIZE_LIMIT:
val = ss->opt.recordSizeLimit;
break;
case SSL_ENABLE_TLS13_COMPAT_MODE:
val = ss->opt.enableTls13CompatMode;
break;
case SSL_ENABLE_DTLS_SHORT_HEADER:
val = ss->opt.enableDtlsShortHeader;
break;
case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
val = ss->opt.enableHelloDowngradeCheck;
break;
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
val = ss->opt.enableV2CompatibleHello;
break;
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
val = ss->opt.enablePostHandshakeAuth;
break;
case SSL_SUPPRESS_END_OF_EARLY_DATA:
val = ss->opt.suppressEndOfEarlyData;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
}
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
*pVal = val;
return rv;
}
SECStatus
SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
{
SECStatus rv = SECSuccess;
PRIntn val = PR_FALSE;
if (!pVal) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_SetDefaultsFromEnvironment();
switch (which) {
case SSL_SOCKS:
val = PR_FALSE;
break;
case SSL_SECURITY:
val = ssl_defaults.useSecurity;
break;
case SSL_REQUEST_CERTIFICATE:
val = ssl_defaults.requestCertificate;
break;
case SSL_REQUIRE_CERTIFICATE:
val = ssl_defaults.requireCertificate;
break;
case SSL_HANDSHAKE_AS_CLIENT:
val = ssl_defaults.handshakeAsClient;
break;
case SSL_HANDSHAKE_AS_SERVER:
val = ssl_defaults.handshakeAsServer;
break;
case SSL_ENABLE_TLS:
val = versions_defaults_stream.max >= SSL_LIBRARY_VERSION_TLS_1_0;
break;
case SSL_ENABLE_SSL3:
val = versions_defaults_stream.min == SSL_LIBRARY_VERSION_3_0;
break;
case SSL_ENABLE_SSL2:
case SSL_V2_COMPATIBLE_HELLO:
val = PR_FALSE;
break;
case SSL_NO_CACHE:
val = ssl_defaults.noCache;
break;
case SSL_ENABLE_FDX:
val = ssl_defaults.fdx;
break;
case SSL_ROLLBACK_DETECTION:
val = ssl_defaults.detectRollBack;
break;
case SSL_NO_STEP_DOWN:
val = PR_FALSE;
break;
case SSL_BYPASS_PKCS11:
val = PR_FALSE;
break;
case SSL_NO_LOCKS:
val = ssl_defaults.noLocks;
break;
case SSL_ENABLE_SESSION_TICKETS:
val = ssl_defaults.enableSessionTickets;
break;
case SSL_ENABLE_DEFLATE:
val = ssl_defaults.enableDeflate;
break;
case SSL_ENABLE_RENEGOTIATION:
val = ssl_defaults.enableRenegotiation;
break;
case SSL_REQUIRE_SAFE_NEGOTIATION:
val = ssl_defaults.requireSafeNegotiation;
break;
case SSL_ENABLE_FALSE_START:
val = ssl_defaults.enableFalseStart;
break;
case SSL_CBC_RANDOM_IV:
val = ssl_defaults.cbcRandomIV;
break;
case SSL_ENABLE_OCSP_STAPLING:
val = ssl_defaults.enableOCSPStapling;
break;
case SSL_ENABLE_DELEGATED_CREDENTIALS:
val = ssl_defaults.enableDelegatedCredentials;
break;
case SSL_ENABLE_NPN:
val = PR_FALSE;
break;
case SSL_ENABLE_ALPN:
val = ssl_defaults.enableALPN;
break;
case SSL_REUSE_SERVER_ECDHE_KEY:
val = ssl_defaults.reuseServerECDHEKey;
break;
case SSL_ENABLE_FALLBACK_SCSV:
val = ssl_defaults.enableFallbackSCSV;
break;
case SSL_ENABLE_SERVER_DHE:
val = ssl_defaults.enableServerDhe;
break;
case SSL_ENABLE_EXTENDED_MASTER_SECRET:
val = ssl_defaults.enableExtendedMS;
break;
case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
val = ssl_defaults.enableSignedCertTimestamps;
break;
case SSL_ENABLE_0RTT_DATA:
val = ssl_defaults.enable0RttData;
break;
case SSL_RECORD_SIZE_LIMIT:
val = ssl_defaults.recordSizeLimit;
break;
case SSL_ENABLE_TLS13_COMPAT_MODE:
val = ssl_defaults.enableTls13CompatMode;
break;
case SSL_ENABLE_DTLS_SHORT_HEADER:
val = ssl_defaults.enableDtlsShortHeader;
break;
case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
val = ssl_defaults.enableHelloDowngradeCheck;
break;
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
val = ssl_defaults.enableV2CompatibleHello;
break;
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
val = ssl_defaults.enablePostHandshakeAuth;
break;
case SSL_SUPPRESS_END_OF_EARLY_DATA:
val = ssl_defaults.suppressEndOfEarlyData;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
}
*pVal = val;
return rv;
}
/* XXX Use Global Lock to protect this stuff. */
SECStatus
SSL_EnableDefault(int which, PRIntn val)
{
return SSL_OptionSetDefault(which, val);
}
SECStatus
SSL_OptionSetDefault(PRInt32 which, PRIntn val)
{
SECStatus status = ssl_Init();
if (status != SECSuccess) {
return status;
}
ssl_SetDefaultsFromEnvironment();
switch (which) {
case SSL_SOCKS:
ssl_defaults.useSocks = PR_FALSE;
if (val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
break;
case SSL_SECURITY:
ssl_defaults.useSecurity = val;
break;
case SSL_REQUEST_CERTIFICATE:
ssl_defaults.requestCertificate = val;
break;
case SSL_REQUIRE_CERTIFICATE:
ssl_defaults.requireCertificate = val;
break;
case SSL_HANDSHAKE_AS_CLIENT:
if (ssl_defaults.handshakeAsServer && val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_defaults.handshakeAsClient = val;
break;
case SSL_HANDSHAKE_AS_SERVER:
if (ssl_defaults.handshakeAsClient && val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_defaults.handshakeAsServer = val;
break;
case SSL_ENABLE_TLS:
ssl_EnableTLS(&versions_defaults_stream, val);
break;
case SSL_ENABLE_SSL3:
ssl_EnableSSL3(&versions_defaults_stream, val);
break;
case SSL_ENABLE_SSL2:
case SSL_V2_COMPATIBLE_HELLO:
/* We no longer support SSL v2.
* However, if an old application requests to disable SSL v2,
* we shouldn't fail.
*/
if (val) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
break;
case SSL_NO_CACHE:
ssl_defaults.noCache = val;
break;
case SSL_ENABLE_FDX:
if (val && ssl_defaults.noLocks) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_defaults.fdx = val;
break;
case SSL_ROLLBACK_DETECTION:
ssl_defaults.detectRollBack = val;
break;
case SSL_NO_STEP_DOWN:
break;
case SSL_BYPASS_PKCS11:
break;
case SSL_NO_LOCKS:
if (val && ssl_defaults.fdx) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (val && ssl_force_locks)
val = PR_FALSE; /* silent override */
ssl_defaults.noLocks = val;
if (val) {
locksEverDisabled = PR_TRUE;
strcpy(lockStatus + LOCKSTATUS_OFFSET, "DISABLED.");
}
break;
case SSL_ENABLE_SESSION_TICKETS:
ssl_defaults.enableSessionTickets = val;
break;
case SSL_ENABLE_DEFLATE:
ssl_defaults.enableDeflate = val;
break;
case SSL_ENABLE_RENEGOTIATION:
ssl_defaults.enableRenegotiation = val;
break;
case SSL_REQUIRE_SAFE_NEGOTIATION:
ssl_defaults.requireSafeNegotiation = val;
break;
case SSL_ENABLE_FALSE_START:
ssl_defaults.enableFalseStart = val;
break;
case SSL_CBC_RANDOM_IV:
ssl_defaults.cbcRandomIV = val;
break;
case SSL_ENABLE_OCSP_STAPLING:
ssl_defaults.enableOCSPStapling = val;
break;
case SSL_ENABLE_DELEGATED_CREDENTIALS:
ssl_defaults.enableDelegatedCredentials = val;
break;
case SSL_ENABLE_NPN:
break;
case SSL_ENABLE_ALPN:
ssl_defaults.enableALPN = val;
break;
case SSL_REUSE_SERVER_ECDHE_KEY:
ssl_defaults.reuseServerECDHEKey = val;
break;
case SSL_ENABLE_FALLBACK_SCSV:
ssl_defaults.enableFallbackSCSV = val;
break;
case SSL_ENABLE_SERVER_DHE:
ssl_defaults.enableServerDhe = val;
break;
case SSL_ENABLE_EXTENDED_MASTER_SECRET:
ssl_defaults.enableExtendedMS = val;
break;
case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
ssl_defaults.enableSignedCertTimestamps = val;
break;
case SSL_ENABLE_0RTT_DATA:
ssl_defaults.enable0RttData = val;
break;
case SSL_RECORD_SIZE_LIMIT:
if (val < 64 || val > (MAX_FRAGMENT_LENGTH + 1)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
ssl_defaults.recordSizeLimit = val;
break;
case SSL_ENABLE_TLS13_COMPAT_MODE:
ssl_defaults.enableTls13CompatMode = val;
break;
case SSL_ENABLE_DTLS_SHORT_HEADER:
ssl_defaults.enableDtlsShortHeader = val;
break;
case SSL_ENABLE_HELLO_DOWNGRADE_CHECK:
ssl_defaults.enableHelloDowngradeCheck = val;
break;
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
ssl_defaults.enableV2CompatibleHello = val;
break;
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
ssl_defaults.enablePostHandshakeAuth = val;
break;
case SSL_SUPPRESS_END_OF_EARLY_DATA:
ssl_defaults.suppressEndOfEarlyData = val;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
return SECSuccess;
}
SECStatus
SSLExp_SetMaxEarlyDataSize(PRFileDesc *fd, PRUint32 size)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure; /* Error code already set. */
}
ss->opt.maxEarlyDataSize = size;
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 (ssl_IsRemovedCipherSuite(which))
return SECSuccess;
return SSL_CipherPolicySet(which, policy);
}
SECStatus
ssl_CipherPolicySet(PRInt32 which, PRInt32 policy)
{
SECStatus rv = SECSuccess;
if (ssl_IsRemovedCipherSuite(which)) {
rv = SECSuccess;
} else {
rv = ssl3_SetPolicy((ssl3CipherSuite)which, policy);
}
return rv;
}
SECStatus
SSL_CipherPolicySet(PRInt32 which, PRInt32 policy)
{
SECStatus rv = ssl_Init();
if (rv != SECSuccess) {
return rv;
}
if (NSS_IsPolicyLocked()) {
PORT_SetError(SEC_ERROR_POLICY_LOCKED);
return SECFailure;
}
return ssl_CipherPolicySet(which, policy);
}
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 {
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 (ssl_IsRemovedCipherSuite(which))
return SECSuccess;
return SSL_CipherPrefSetDefault(which, enabled);
}
SECStatus
ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
{
if (ssl_IsRemovedCipherSuite(which))
return SECSuccess;
return ssl3_CipherPrefSetDefault((ssl3CipherSuite)which, enabled);
}
SECStatus
SSL_CipherPrefSetDefault(PRInt32 which, PRBool enabled)
{
SECStatus rv = ssl_Init();
PRInt32 locks;
if (rv != SECSuccess) {
return rv;
}
rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
if ((rv == SECSuccess) && (locks & NSS_DEFAULT_SSL_LOCK)) {
return SECSuccess;
}
return ssl_CipherPrefSetDefault(which, enabled);
}
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 {
rv = ssl3_CipherPrefGetDefault((ssl3CipherSuite)which, enabled);
}
return rv;
}
SECStatus
SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled)
{
sslSocket *ss = ssl_FindSocket(fd);
PRInt32 locks;
SECStatus rv;
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefSet", SSL_GETPID(), fd));
return SECFailure;
}
rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
if ((rv == SECSuccess) && (locks & NSS_DEFAULT_SSL_LOCK)) {
return SECSuccess;
}
if (ssl_IsRemovedCipherSuite(which))
return SECSuccess;
return ssl3_CipherPrefSet(ss, (ssl3CipherSuite)which, enabled);
}
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 {
rv = ssl3_CipherPrefGet(ss, (ssl3CipherSuite)which, enabled);
}
return rv;
}
/* The client can call this function to be aware of the current
* CipherSuites order. */
SECStatus
SSLExp_CipherSuiteOrderGet(PRFileDesc *fd, PRUint16 *cipherOrder,
unsigned int *numCiphers)
{
if (!fd) {
SSL_DBG(("%d: SSL: file descriptor in CipherSuiteOrderGet is null",
SSL_GETPID()));
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (!cipherOrder || !numCiphers) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in CipherSuiteOrderGet", SSL_GETPID(),
fd));
return SECFailure; /* Error code already set. */
}
unsigned int enabled = 0;
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
for (unsigned int i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
const ssl3CipherSuiteCfg *suiteCfg = &ss->cipherSuites[i];
if (suiteCfg && suiteCfg->enabled &&
suiteCfg->policy != SSL_NOT_ALLOWED) {
cipherOrder[enabled++] = suiteCfg->cipher_suite;
}
}
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
*numCiphers = enabled;
return SECSuccess;
}
/* This function permits reorder the CipherSuites List for the Handshake
* (Client Hello). */
SECStatus
SSLExp_CipherSuiteOrderSet(PRFileDesc *fd, const PRUint16 *cipherOrder,
unsigned int numCiphers)
{
if (!fd) {
SSL_DBG(("%d: SSL: file descriptor in CipherSuiteOrderGet is null",
SSL_GETPID()));
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (!cipherOrder || !numCiphers || numCiphers > ssl_V3_SUITES_IMPLEMENTED) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in CipherSuiteOrderSet", SSL_GETPID(),
fd));
return SECFailure; /* Error code already set. */
}