Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/lib/ssl/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 136 kB image not shown  

Quelle  sslsock.c   Sprache: C

 
/* -*- 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_FALSE,
    .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_TRUE,
    .enableV2CompatibleHello = PR_FALSE,
    .enablePostHandshakeAuth = PR_FALSE,
    .suppressEndOfEarlyData = PR_FALSE,
    .enableTls13GreaseEch = PR_FALSE,
    .enableTls13BackendEch = PR_FALSE,
    .callExtensionWriterOnEchInner = PR_FALSE,
    .enableGrease = PR_FALSE,
    .enableChXtnPermutation = PR_FALSE
};

/*
 * default range of enabled SSL/TLS protocols
 */

static SSLVersionRange versions_defaults_stream = {
    SSL_LIBRARY_VERSION_TLS_1_2,
    SSL_LIBRARY_VERSION_TLS_1_3
};

static SSLVersionRange versions_defaults_datagram = {
    SSL_LIBRARY_VERSION_TLS_1_2,
    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;

static PRCallOnceType ssl_setDefaultsFromEnvironment = { 0 };

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

/* 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),
    { ssl_grp_kem_xyber768d00, 256, ssl_kea_ecdh_hybrid, SEC_OID_XYBER768D00, PR_TRUE },
    { ssl_grp_kem_mlkem768x25519, 256, ssl_kea_ecdh_hybrid, SEC_OID_MLKEM768X25519, 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 PRStatus ssl_SetDefaultsFromEnvironmentCallOnce(void);
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 && !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;

        case SSL_ENABLE_GREASE:
            ss->opt.enableGrease = val;
            break;

        case SSL_ENABLE_CH_EXTENSION_PERMUTATION:
            ss->opt.enableChXtnPermutation = 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;
            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,
                           PRUint16 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. */
    }
    ssl3CipherSuiteCfg tmpSuiteCfg[ssl_V3_SUITES_IMPLEMENTED];
    ssl_Get1stHandshakeLock(ss);
    ssl_GetSSL3HandshakeLock(ss);
    /* For each cipherSuite given as input, verify that it is
     * known to NSS and only present in the list once. */

    for (unsigned int i = 0; i < numCiphers; i++) {
        const ssl3CipherSuiteCfg *suiteCfg =
            ssl_LookupCipherSuiteCfg(cipherOrder[i], ss->cipherSuites);
        if (!suiteCfg) {
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
            ssl_ReleaseSSL3HandshakeLock(ss);
            ssl_Release1stHandshakeLock(ss);
            return SECFailure;
        }
        for (unsigned int j = i + 1; j < numCiphers; j++) {
            /* This is a duplicate entry. */
            if (cipherOrder[i] == cipherOrder[j]) {
                PORT_SetError(SEC_ERROR_INVALID_ARGS);
                ssl_ReleaseSSL3HandshakeLock(ss);
                ssl_Release1stHandshakeLock(ss);
                return SECFailure;
            }
        }
        tmpSuiteCfg[i] = *suiteCfg;
        tmpSuiteCfg[i].enabled = PR_TRUE;
    }
    /* Find all defined ciphersuites not present in the input list and append
     * them after the preferred. This guarantees that the socket will always
     * have a complete list of size ssl_V3_SUITES_IMPLEMENTED */

    unsigned int cfgIdx = numCiphers;
    for (unsigned int i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
        PRBool received = PR_FALSE;
        for (unsigned int j = 0; j < numCiphers; j++) {
            if (ss->cipherSuites[i].cipher_suite ==
                tmpSuiteCfg[j].cipher_suite) {
                received = PR_TRUE;
                break;
            }
        }
        if (!received) {
            tmpSuiteCfg[cfgIdx] = ss->cipherSuites[i];
            tmpSuiteCfg[cfgIdx++].enabled = PR_FALSE;
        }
    }
    PORT_Assert(cfgIdx == ssl_V3_SUITES_IMPLEMENTED);
    /* now we can rewrite the socket with the desired order */
    PORT_Memcpy(ss->cipherSuites, tmpSuiteCfg, sizeof(tmpSuiteCfg));
    ssl_ReleaseSSL3HandshakeLock(ss);
    ssl_Release1stHandshakeLock(ss);
    return SECSuccess;
}

SECStatus
NSS_SetDomesticPolicy(void)
{
    SECStatus status = SECSuccess;
    const PRUint16 *cipher;
    SECStatus rv;
    PRUint32 policy;

    /* If we've already defined some policy oids, skip changing them */
    rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policy);
    if ((rv == SECSuccess) && (policy & NSS_USE_POLICY_IN_SSL)) {
        return ssl_Init(); /* make sure the policies have been loaded */
    }

    for (cipher = SSL_ImplementedCiphers; *cipher != 0; ++cipher) {
        status = SSL_SetPolicy(*cipher, SSL_ALLOWED);
        if (status != SECSuccess)
            break;
    }
    return status;
}

SECStatus
NSS_SetExportPolicy(void)
{
    return NSS_SetDomesticPolicy();
}

SECStatus
NSS_SetFrancePolicy(void)
{
    return NSS_SetDomesticPolicy();
}

SECStatus
SSL_NamedGroupConfig(PRFileDesc *fd, const SSLNamedGroup *groups,
                     unsigned int numGroups)
{
    unsigned int i;
    unsigned int j = 0;
    sslSocket *ss = ssl_FindSocket(fd);

    if (!ss) {
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
        return SECFailure;
    }

    if (!groups) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }
    if (numGroups > SSL_NAMED_GROUP_COUNT) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    memset((void *)ss->namedGroupPreferences, 0,
           sizeof(ss->namedGroupPreferences));
    for (i = 0; i < numGroups; ++i) {
        const sslNamedGroupDef *groupDef = ssl_LookupNamedGroup(groups[i]);
        if (!ssl_NamedGroupEnabled(ss, groupDef)) {
            ss->namedGroupPreferences[j++] = groupDef;
        }
    }

    return SECSuccess;
}

SECStatus
SSL_DHEGroupPrefSet(PRFileDesc *fd, const SSLDHEGroupType *groups,
                    PRUint16 num_groups)
{
    sslSocket *ss;
    const SSLDHEGroupType *list;
    unsigned int count;
    int i, k, j;
    const sslNamedGroupDef *enabled[SSL_NAMED_GROUP_COUNT] = { 0 };
    static const SSLDHEGroupType default_dhe_groups[] = {
        ssl_ff_dhe_2048_group
    };

    if ((num_groups && !groups) || (!num_groups && groups) ||
        num_groups > SSL_NAMED_GROUP_COUNT) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    ss = ssl_FindSocket(fd);
    if (!ss) {
        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DHEGroupPrefSet", SSL_GETPID(), fd));
        return SECFailure;
    }

    if (groups) {
        list = groups;
        count = num_groups;
    } else {
        list = default_dhe_groups;
        count = PR_ARRAY_SIZE(default_dhe_groups);
    }

    /* save enabled ec groups and clear ss->namedGroupPreferences */
    k = 0;
    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
        if (ss->namedGroupPreferences[i] &&
            ss->namedGroupPreferences[i]->keaType != ssl_kea_dh) {
            enabled[k++] = ss->namedGroupPreferences[i];
        }
        ss->namedGroupPreferences[i] = NULL;
    }

    ss->ssl3.dhePreferredGroup = NULL;
    for (i = 0; i < count; ++i) {
        PRBool duplicate = PR_FALSE;
        SSLNamedGroup name;
        const sslNamedGroupDef *groupDef;
        switch (list[i]) {
            case ssl_ff_dhe_2048_group:
                name = ssl_grp_ffdhe_2048;
                break;
            case ssl_ff_dhe_3072_group:
                name = ssl_grp_ffdhe_3072;
                break;
            case ssl_ff_dhe_4096_group:
                name = ssl_grp_ffdhe_4096;
                break;
            case ssl_ff_dhe_6144_group:
                name = ssl_grp_ffdhe_6144;
                break;
            case ssl_ff_dhe_8192_group:
                name = ssl_grp_ffdhe_8192;
                break;
            default:
                PORT_SetError(SEC_ERROR_INVALID_ARGS);
                return SECFailure;
        }
        groupDef = ssl_LookupNamedGroup(name);
        PORT_Assert(groupDef);
        if (!ss->ssl3.dhePreferredGroup) {
            ss->ssl3.dhePreferredGroup = groupDef;
        }
        PORT_Assert(k < SSL_NAMED_GROUP_COUNT);
        for (j = 0; j < k; ++j) {
            /* skip duplicates */
            if (enabled[j] == groupDef) {
                duplicate = PR_TRUE;
                break;
            }
        }
        if (!duplicate) {
            enabled[k++] = groupDef;
        }
    }
    for (i = 0; i < k; ++i) {
        ss->namedGroupPreferences[i] = enabled[i];
    }

    return SECSuccess;
}

PRCallOnceType gWeakDHParamsRegisterOnce;
int gWeakDHParamsRegisterError;

PRCallOnceType gWeakDHParamsOnce;
int gWeakDHParamsError;
/* As our code allocates type PQGParams, we'll keep it around,
 * even though we only make use of it's parameters through gWeakDHParam. */

static PQGParams *gWeakParamsPQG;
static ssl3DHParams *gWeakDHParams;
#define WEAK_DHE_SIZE 1024

static PRStatus
ssl3_CreateWeakDHParams(void)
{
    PQGVerify *vfy;
    SECStatus rv, passed;

    PORT_Assert(!gWeakDHParams && !gWeakParamsPQG);

    rv = PK11_PQG_ParamGenV2(WEAK_DHE_SIZE, 160, 64 /*maximum seed that will work*/,
                             &gWeakParamsPQG, &vfy);
    if (rv != SECSuccess) {
        gWeakDHParamsError = PORT_GetError();
        return PR_FAILURE;
    }

    rv = PK11_PQG_VerifyParams(gWeakParamsPQG, vfy, &passed);
    if (rv != SECSuccess || passed != SECSuccess) {
        SSL_DBG(("%d: PK11_PQG_VerifyParams failed in ssl3_CreateWeakDHParams",
                 SSL_GETPID()));
        gWeakDHParamsError = PORT_GetError();
        return PR_FAILURE;
    }

    gWeakDHParams = PORT_ArenaNew(gWeakParamsPQG->arena, ssl3DHParams);
    if (!gWeakDHParams) {
        gWeakDHParamsError = PORT_GetError();
        return PR_FAILURE;
    }

    gWeakDHParams->name = ssl_grp_ffdhe_custom;
    gWeakDHParams->prime.data = gWeakParamsPQG->prime.data;
    gWeakDHParams->prime.len = gWeakParamsPQG->prime.len;
    gWeakDHParams->base.data = gWeakParamsPQG->base.data;
    gWeakDHParams->base.len = gWeakParamsPQG->base.len;

    PK11_PQG_DestroyVerify(vfy);
    return PR_SUCCESS;
}

static SECStatus
ssl3_WeakDHParamsShutdown(void *appData, void *nssData)
{
    if (gWeakParamsPQG) {
        PK11_PQG_DestroyParams(gWeakParamsPQG);
        gWeakParamsPQG = NULL;
        gWeakDHParams = NULL;
    }
    return SECSuccess;
}

static PRStatus
ssl3_WeakDHParamsRegisterShutdown(void)
{
    SECStatus rv;
    rv = NSS_RegisterShutdown(ssl3_WeakDHParamsShutdown, NULL);
    if (rv != SECSuccess) {
        gWeakDHParamsRegisterError = PORT_GetError();
    }
    return (PRStatus)rv;
}

/* global init strategy inspired by ssl3_CreateECDHEphemeralKeys */
SECStatus
SSL_EnableWeakDHEPrimeGroup(PRFileDesc *fd, PRBool enabled)
{
    sslSocket *ss;
    PRStatus status;

    if (enabled) {
        status = PR_CallOnce(&gWeakDHParamsRegisterOnce,
                             ssl3_WeakDHParamsRegisterShutdown);
        if (status != PR_SUCCESS) {
            PORT_SetError(gWeakDHParamsRegisterError);
            return SECFailure;
        }

        status = PR_CallOnce(&gWeakDHParamsOnce, ssl3_CreateWeakDHParams);
        if (status != PR_SUCCESS) {
            PORT_SetError(gWeakDHParamsError);
            return SECFailure;
        }
    }

    if (!fd)
        return SECSuccess;

    ss = ssl_FindSocket(fd);
    if (!ss) {
        SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DHEGroupPrefSet", SSL_GETPID(), fd));
        return SECFailure;
    }

    ss->ssl3.dheWeakGroupEnabled = enabled;
    return SECSuccess;
}

#include "dhe-param.c"

const ssl3DHParams *
ssl_GetDHEParams(const sslNamedGroupDef *groupDef)
{
    switch (groupDef->name) {
        case ssl_grp_ffdhe_2048:
            return &ff_dhe_2048_params;
        case ssl_grp_ffdhe_3072:
            return &ff_dhe_3072_params;
        case ssl_grp_ffdhe_4096:
            return &ff_dhe_4096_params;
        case ssl_grp_ffdhe_6144:
            return &ff_dhe_6144_params;
        case ssl_grp_ffdhe_8192:
            return &ff_dhe_8192_params;
        case ssl_grp_ffdhe_custom:
            PORT_Assert(gWeakDHParams);
            return gWeakDHParams;
        default:
            PORT_Assert(0);
    }
    return NULL;
}

/* This validates dh_Ys against the group prime. */
PRBool
ssl_IsValidDHEShare(const SECItem *dh_p, const SECItem *dh_Ys)
{
    unsigned int size_p = SECKEY_BigIntegerBitLength(dh_p);
    unsigned int size_y = SECKEY_BigIntegerBitLength(dh_Ys);
    unsigned int commonPart;
    int cmp;

    if (dh_p->len == 0 || dh_Ys->len == 0) {
        return PR_FALSE;
    }
    /* Check that the prime is at least odd. */
    if ((dh_p->data[dh_p->len - 1] & 0x01) == 0) {
        return PR_FALSE;
    }
    /* dh_Ys can't be 1, or bigger than dh_p. */
    if (size_y <= 1 || size_y > size_p) {
        return PR_FALSE;
    }
    /* If dh_Ys is shorter, then it's definitely smaller than p-1. */
    if (size_y < size_p) {
        return PR_TRUE;
    }

    /* Compare the common part of each, minus the final octet. */
    commonPart = (size_p + 7) / 8;
    PORT_Assert(commonPart <= dh_Ys->len);
    PORT_Assert(commonPart <= dh_p->len);
    cmp = PORT_Memcmp(dh_Ys->data + dh_Ys->len - commonPart,
                      dh_p->data + dh_p->len - commonPart, commonPart - 1);
    if (cmp < 0) {
        return PR_TRUE;
    }
    if (cmp > 0) {
        return PR_FALSE;
    }

    /* The last octet of the prime is the only thing that is different and that
     * has to be two greater than the share, otherwise we have Ys == p - 1,
     * and that means small subgroups. */

    if (dh_Ys->data[dh_Ys->len - 1] >= (dh_p->data[dh_p->len - 1] - 1)) {
        return PR_FALSE;
    }

    return PR_TRUE;
}

/* Checks that the provided DH parameters match those in one of the named groups
 * that we have enabled.  The groups are defined in dhe-param.c and are those
 * defined in Appendix A of draft-ietf-tls-negotiated-ff-dhe.
 *
 * |groupDef| and |dhParams| are optional outparams that identify the group and
 * its parameters respectively (if this is successful). */

SECStatus
ssl_ValidateDHENamedGroup(sslSocket *ss,
                          const SECItem *dh_p,
                          const SECItem *dh_g,
                          const sslNamedGroupDef **groupDef,
                          const ssl3DHParams **dhParams)
{
    unsigned int i;

    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
        const ssl3DHParams *params;
        if (!ss->namedGroupPreferences[i]) {
            continue;
        }
        if (ss->namedGroupPreferences[i]->keaType != ssl_kea_dh) {
            continue;
        }

        params = ssl_GetDHEParams(ss->namedGroupPreferences[i]);
        PORT_Assert(params);
        if (SECITEM_ItemsAreEqual(¶ms->prime, dh_p)) {
            if (!SECITEM_ItemsAreEqual(¶ms->base, dh_g)) {
                return SECFailure;
            }
            if (groupDef)
                *groupDef = ss->namedGroupPreferences[i];
            if (dhParams)
                *dhParams = params;
            return SECSuccess;
        }
    }

    return SECFailure;
}

/* Ensure DH parameters have been selected.  This just picks the first enabled
 * FFDHE group in ssl_named_groups, or the weak one if it was enabled. */

SECStatus
ssl_SelectDHEGroup(sslSocket *ss, const sslNamedGroupDef **groupDef)
{
    unsigned int i;
    static const sslNamedGroupDef weak_group_def = {
        ssl_grp_ffdhe_custom, WEAK_DHE_SIZE, ssl_kea_dh,
        SEC_OID_TLS_DHE_CUSTOM, PR_TRUE
    };
    PRInt32 minDH;
    SECStatus rv;

    // make sure we select a group consistent with our
    // current policy policy
    rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH);
    if (rv != SECSuccess || minDH <= 0) {
        minDH = DH_MIN_P_BITS;
    }

    /* Only select weak groups in TLS 1.2 and earlier, but not if the client has
     * indicated that it supports an FFDHE named group. */

    if (ss->ssl3.dheWeakGroupEnabled &&
        ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
        !ss->xtnData.peerSupportsFfdheGroups &&
        weak_group_def.bits >= minDH) {
        *groupDef = &weak_group_def;
        return SECSuccess;
    }
    if (ss->ssl3.dhePreferredGroup &&
        ssl_NamedGroupEnabled(ss, ss->ssl3.dhePreferredGroup) &&
        ss->ssl3.dhePreferredGroup->bits >= minDH) {
        *groupDef = ss->ssl3.dhePreferredGroup;
        return SECSuccess;
    }
    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
        if (ss->namedGroupPreferences[i] &&
            ss->namedGroupPreferences[i]->keaType == ssl_kea_dh &&
            ss->namedGroupPreferences[i]->bits >= minDH) {
            *groupDef = ss->namedGroupPreferences[i];
            return SECSuccess;
        }
    }

    *groupDef = NULL;
    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=94 G=95

¤ Dauer der Verarbeitung: 0.32 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.