Coverage Report

Created: 2025-12-20 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/ssl/sslgrp.c
Line
Count
Source
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
8
{
28
8
    unsigned int i;
29
30
288
    for (i = 0; i < SSL_NAMED_GROUP_COUNT; i++) {
31
280
        if (gECDHEKeyPairs[i].keyPair) {
32
0
            ssl_FreeEphemeralKeyPair(gECDHEKeyPairs[i].keyPair);
33
0
        }
34
280
    }
35
8
    memset(gECDHEKeyPairs, 0, sizeof(gECDHEKeyPairs));
36
8
    return SECSuccess;
37
8
}
38
39
/* Only run the cleanup once. */
40
static PRCallOnceType cleanupECDHEKeysOnce;
41
static PRStatus
42
ssl_SetupCleanupECDHEKeysOnce(void)
43
8
{
44
8
    SECStatus rv = NSS_RegisterShutdown(ssl_CleanupECDHEKeys, NULL);
45
8
    return (rv != SECSuccess) ? PR_FAILURE : PR_SUCCESS;
46
8
}
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
176
{
56
176
    const sslSocketAndGroupArg *typed_arg = (sslSocketAndGroupArg *)arg;
57
176
    const sslNamedGroupDef *group = typed_arg->group;
58
176
    const sslSocket *ss = typed_arg->ss;
59
176
    unsigned int i = group - ssl_named_groups;
60
176
    SECStatus rv;
61
62
176
    PORT_Assert(group->keaType == ssl_kea_ecdh);
63
176
    PORT_Assert(i < SSL_NAMED_GROUP_COUNT);
64
176
    rv = ssl_CreateECDHEphemeralKeyPair(ss, group,
65
176
                                        &gECDHEKeyPairs[i].keyPair);
66
176
    if (rv != SECSuccess) {
67
176
        gECDHEKeyPairs[i].keyPair = NULL;
68
176
        SSL_TRC(5, ("%d: SSL[-]: disabling group %d",
69
176
                    SSL_GETPID(), group->name));
70
176
    }
71
72
176
    return PR_SUCCESS;
73
176
}
74
75
void
76
ssl_FilterSupportedGroups(sslSocket *ss)
77
231k
{
78
231k
    unsigned int i;
79
231k
    PRStatus prv;
80
231k
    sslSocketAndGroupArg arg = { NULL, ss };
81
82
231k
    prv = PR_CallOnce(&cleanupECDHEKeysOnce, ssl_SetupCleanupECDHEKeysOnce);
83
231k
    PORT_Assert(prv == PR_SUCCESS);
84
231k
    if (prv != PR_SUCCESS) {
85
0
        return;
86
0
    }
87
88
8.32M
    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
89
8.09M
        PRUint32 policy;
90
8.09M
        SECStatus srv;
91
8.09M
        unsigned int index;
92
8.09M
        const sslNamedGroupDef *group = ss->namedGroupPreferences[i];
93
8.09M
        if (!group) {
94
4.38M
            continue;
95
4.38M
        }
96
97
3.70M
        srv = NSS_GetAlgorithmPolicy(group->oidTag, &policy);
98
3.70M
        if (srv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL_KX)) {
99
53.1k
            ss->namedGroupPreferences[i] = NULL;
100
53.1k
            continue;
101
53.1k
        }
102
103
3.65M
        if (group->assumeSupported) {
104
2.48M
            continue;
105
2.48M
        }
106
107
1.16M
        if (group->name == ssl_grp_kem_xyber768d00) {
108
#ifdef NSS_DISABLE_KYBER
109
            ss->namedGroupPreferences[i] = NULL;
110
#endif
111
0
            continue;
112
0
        }
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
1.16M
        index = group - ssl_named_groups;
117
1.16M
        PORT_Assert(index < SSL_NAMED_GROUP_COUNT);
118
119
1.16M
        arg.group = group;
120
1.16M
        prv = PR_CallOnceWithArg(&gECDHEKeyPairs[index].once,
121
1.16M
                                 ssl_CreateStaticECDHEKeyPair,
122
1.16M
                                 (void *)&arg);
123
1.16M
        PORT_Assert(prv == PR_SUCCESS);
124
1.16M
        if (prv != PR_SUCCESS) {
125
0
            continue;
126
0
        }
127
128
1.16M
        if (!gECDHEKeyPairs[index].keyPair) {
129
1.16M
            ss->namedGroupPreferences[i] = NULL;
130
1.16M
        }
131
1.16M
    }
132
231k
}
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
0
{
141
0
    sslEphemeralKeyPair *keyPair;
142
    /* We index gECDHEKeyPairs by the named group.  Pointer arithmetic! */
143
0
    unsigned int index = ecGroup - ssl_named_groups;
144
0
    PRStatus prv;
145
0
    sslSocketAndGroupArg arg = { ecGroup, ss };
146
147
0
    prv = PR_CallOnceWithArg(&gECDHEKeyPairs[index].once,
148
0
                             ssl_CreateStaticECDHEKeyPair,
149
0
                             (void *)&arg);
150
0
    PORT_Assert(prv == PR_SUCCESS);
151
0
    if (prv != PR_SUCCESS) {
152
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
153
0
        return SECFailure;
154
0
    }
155
156
0
    keyPair = gECDHEKeyPairs[index].keyPair;
157
0
    if (!keyPair) {
158
        /* Attempting to use a key pair for an unsupported group. */
159
0
        PORT_Assert(keyPair);
160
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
161
0
        return SECFailure;
162
0
    }
163
164
0
    keyPair = ssl_CopyEphemeralKeyPair(keyPair);
165
0
    if (!keyPair)
166
0
        return SECFailure;
167
168
0
    PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
169
0
    PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
170
0
    return SECSuccess;
171
0
}