tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sslgrp.c (5266B)


      1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /*
      3 * This file contains prototypes for the public SSL functions.
      4 *
      5 * This Source Code Form is subject to the terms of the Mozilla Public
      6 * License, v. 2.0. If a copy of the MPL was not distributed with this
      7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      8 
      9 #include "nss.h"
     10 #include "pk11func.h"
     11 #include "ssl.h"
     12 #include "sslimpl.h"
     13 
     14 struct {
     15    sslEphemeralKeyPair *keyPair;
     16    PRCallOnceType once;
     17 } gECDHEKeyPairs[SSL_NAMED_GROUP_COUNT];
     18 
     19 typedef struct sslSocketAndGroupArgStr {
     20    const sslNamedGroupDef *group;
     21    const sslSocket *ss;
     22 } sslSocketAndGroupArg;
     23 
     24 /* Function to clear out the ECDHE keys. */
     25 static SECStatus
     26 ssl_CleanupECDHEKeys(void *appData, void *nssData)
     27 {
     28    unsigned int i;
     29 
     30    for (i = 0; i < SSL_NAMED_GROUP_COUNT; i++) {
     31        if (gECDHEKeyPairs[i].keyPair) {
     32            ssl_FreeEphemeralKeyPair(gECDHEKeyPairs[i].keyPair);
     33        }
     34    }
     35    memset(gECDHEKeyPairs, 0, sizeof(gECDHEKeyPairs));
     36    return SECSuccess;
     37 }
     38 
     39 /* Only run the cleanup once. */
     40 static PRCallOnceType cleanupECDHEKeysOnce;
     41 static PRStatus
     42 ssl_SetupCleanupECDHEKeysOnce(void)
     43 {
     44    SECStatus rv = NSS_RegisterShutdown(ssl_CleanupECDHEKeys, NULL);
     45    return (rv != SECSuccess) ? PR_FAILURE : PR_SUCCESS;
     46 }
     47 
     48 /* This creates a key pair for each of the supported EC groups.  If that works,
     49 * we assume that the token supports that group.  Since this is relatively
     50 * expensive, this is only done for the first socket that is used.  That means
     51 * that if tokens are added or removed, then this will not pick up any changes.
     52 */
     53 static PRStatus
     54 ssl_CreateStaticECDHEKeyPair(void *arg)
     55 {
     56    const sslSocketAndGroupArg *typed_arg = (sslSocketAndGroupArg *)arg;
     57    const sslNamedGroupDef *group = typed_arg->group;
     58    const sslSocket *ss = typed_arg->ss;
     59    unsigned int i = group - ssl_named_groups;
     60    SECStatus rv;
     61 
     62    PORT_Assert(group->keaType == ssl_kea_ecdh);
     63    PORT_Assert(i < SSL_NAMED_GROUP_COUNT);
     64    rv = ssl_CreateECDHEphemeralKeyPair(ss, group,
     65                                        &gECDHEKeyPairs[i].keyPair);
     66    if (rv != SECSuccess) {
     67        gECDHEKeyPairs[i].keyPair = NULL;
     68        SSL_TRC(5, ("%d: SSL[-]: disabling group %d",
     69                    SSL_GETPID(), group->name));
     70    }
     71 
     72    return PR_SUCCESS;
     73 }
     74 
     75 void
     76 ssl_FilterSupportedGroups(sslSocket *ss)
     77 {
     78    unsigned int i;
     79    PRStatus prv;
     80    sslSocketAndGroupArg arg = { NULL, ss };
     81 
     82    prv = PR_CallOnce(&cleanupECDHEKeysOnce, ssl_SetupCleanupECDHEKeysOnce);
     83    PORT_Assert(prv == PR_SUCCESS);
     84    if (prv != PR_SUCCESS) {
     85        return;
     86    }
     87 
     88    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
     89        PRUint32 policy;
     90        SECStatus srv;
     91        unsigned int index;
     92        const sslNamedGroupDef *group = ss->namedGroupPreferences[i];
     93        if (!group) {
     94            continue;
     95        }
     96 
     97        srv = NSS_GetAlgorithmPolicy(group->oidTag, &policy);
     98        if (srv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL_KX)) {
     99            ss->namedGroupPreferences[i] = NULL;
    100            continue;
    101        }
    102 
    103        if (group->assumeSupported) {
    104            continue;
    105        }
    106 
    107        if (group->name == ssl_grp_kem_xyber768d00) {
    108 #ifdef NSS_DISABLE_KYBER
    109            ss->namedGroupPreferences[i] = NULL;
    110 #endif
    111            continue;
    112        }
    113 
    114        /* For EC groups, we have to test that a key pair can be created. This
    115         * is gross, and expensive, so only do it once. */
    116        index = group - ssl_named_groups;
    117        PORT_Assert(index < SSL_NAMED_GROUP_COUNT);
    118 
    119        arg.group = group;
    120        prv = PR_CallOnceWithArg(&gECDHEKeyPairs[index].once,
    121                                 ssl_CreateStaticECDHEKeyPair,
    122                                 (void *)&arg);
    123        PORT_Assert(prv == PR_SUCCESS);
    124        if (prv != PR_SUCCESS) {
    125            continue;
    126        }
    127 
    128        if (!gECDHEKeyPairs[index].keyPair) {
    129            ss->namedGroupPreferences[i] = NULL;
    130        }
    131    }
    132 }
    133 
    134 /*
    135 * Creates the static "ephemeral" public and private ECDH keys used by server in
    136 * ECDHE_RSA and ECDHE_ECDSA handshakes when we reuse the same key.
    137 */
    138 SECStatus
    139 ssl_CreateStaticECDHEKey(sslSocket *ss, const sslNamedGroupDef *ecGroup)
    140 {
    141    sslEphemeralKeyPair *keyPair;
    142    /* We index gECDHEKeyPairs by the named group.  Pointer arithmetic! */
    143    unsigned int index = ecGroup - ssl_named_groups;
    144    PRStatus prv;
    145    sslSocketAndGroupArg arg = { ecGroup, ss };
    146 
    147    prv = PR_CallOnceWithArg(&gECDHEKeyPairs[index].once,
    148                             ssl_CreateStaticECDHEKeyPair,
    149                             (void *)&arg);
    150    PORT_Assert(prv == PR_SUCCESS);
    151    if (prv != PR_SUCCESS) {
    152        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    153        return SECFailure;
    154    }
    155 
    156    keyPair = gECDHEKeyPairs[index].keyPair;
    157    if (!keyPair) {
    158        /* Attempting to use a key pair for an unsupported group. */
    159        PORT_Assert(keyPair);
    160        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    161        return SECFailure;
    162    }
    163 
    164    keyPair = ssl_CopyEphemeralKeyPair(keyPair);
    165    if (!keyPair)
    166        return SECFailure;
    167 
    168    PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
    169    PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
    170    return SECSuccess;
    171 }