Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/ssl/sslgrp.c
Line
Count
Source (jump to first uncovered line)
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
0
{
28
0
    unsigned int i;
29
0
30
0
    for (i = 0; i < SSL_NAMED_GROUP_COUNT; i++) {
31
0
        if (gECDHEKeyPairs[i].keyPair) {
32
0
            ssl_FreeEphemeralKeyPair(gECDHEKeyPairs[i].keyPair);
33
0
        }
34
0
    }
35
0
    memset(gECDHEKeyPairs, 0, sizeof(gECDHEKeyPairs));
36
0
    return SECSuccess;
37
0
}
38
39
/* Only run the cleanup once. */
40
static PRCallOnceType cleanupECDHEKeysOnce;
41
static PRStatus
42
ssl_SetupCleanupECDHEKeysOnce(void)
43
0
{
44
0
    SECStatus rv = NSS_RegisterShutdown(ssl_CleanupECDHEKeys, NULL);
45
0
    return (rv != SECSuccess) ? PR_FAILURE : PR_SUCCESS;
46
0
}
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
0
{
56
0
    const sslSocketAndGroupArg *typed_arg = (sslSocketAndGroupArg *)arg;
57
0
    const sslNamedGroupDef *group = typed_arg->group;
58
0
    const sslSocket *ss = typed_arg->ss;
59
0
    unsigned int i = group - ssl_named_groups;
60
0
    SECStatus rv;
61
0
62
0
    PORT_Assert(group->keaType == ssl_kea_ecdh);
63
0
    PORT_Assert(i < SSL_NAMED_GROUP_COUNT);
64
0
    rv = ssl_CreateECDHEphemeralKeyPair(ss, group,
65
0
                                        &gECDHEKeyPairs[i].keyPair);
66
0
    if (rv != SECSuccess) {
67
0
        gECDHEKeyPairs[i].keyPair = NULL;
68
0
        SSL_TRC(5, ("%d: SSL[-]: disabling group %d",
69
0
                    SSL_GETPID(), group->name));
70
0
    }
71
0
72
0
    return PR_SUCCESS;
73
0
}
74
75
void
76
ssl_FilterSupportedGroups(sslSocket *ss)
77
0
{
78
0
    unsigned int i;
79
0
    PRStatus prv;
80
0
    sslSocketAndGroupArg arg = { NULL, ss };
81
0
82
0
    prv = PR_CallOnce(&cleanupECDHEKeysOnce, ssl_SetupCleanupECDHEKeysOnce);
83
0
    PORT_Assert(prv == PR_SUCCESS);
84
0
    if (prv != PR_SUCCESS) {
85
0
        return;
86
0
    }
87
0
88
0
    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
89
0
        PRUint32 policy;
90
0
        SECStatus srv;
91
0
        unsigned int index;
92
0
        const sslNamedGroupDef *group = ss->namedGroupPreferences[i];
93
0
        if (!group) {
94
0
            continue;
95
0
        }
96
0
97
0
        srv = NSS_GetAlgorithmPolicy(group->oidTag, &policy);
98
0
        if (srv == SECSuccess && !(policy & NSS_USE_ALG_IN_SSL_KX)) {
99
0
            ss->namedGroupPreferences[i] = NULL;
100
0
            continue;
101
0
        }
102
0
103
0
        if (group->assumeSupported) {
104
0
            continue;
105
0
        }
106
0
107
0
        /* For EC groups, we have to test that a key pair can be created. This
108
0
         * is gross, and expensive, so only do it once. */
109
0
        index = group - ssl_named_groups;
110
0
        PORT_Assert(index < SSL_NAMED_GROUP_COUNT);
111
0
112
0
        arg.group = group;
113
0
        prv = PR_CallOnceWithArg(&gECDHEKeyPairs[index].once,
114
0
                                 ssl_CreateStaticECDHEKeyPair,
115
0
                                 (void *)&arg);
116
0
        PORT_Assert(prv == PR_SUCCESS);
117
0
        if (prv != PR_SUCCESS) {
118
0
            continue;
119
0
        }
120
0
121
0
        if (!gECDHEKeyPairs[index].keyPair) {
122
0
            ss->namedGroupPreferences[i] = NULL;
123
0
        }
124
0
    }
125
0
}
126
127
/*
128
 * Creates the static "ephemeral" public and private ECDH keys used by server in
129
 * ECDHE_RSA and ECDHE_ECDSA handshakes when we reuse the same key.
130
 */
131
SECStatus
132
ssl_CreateStaticECDHEKey(sslSocket *ss, const sslNamedGroupDef *ecGroup)
133
0
{
134
0
    sslEphemeralKeyPair *keyPair;
135
0
    /* We index gECDHEKeyPairs by the named group.  Pointer arithmetic! */
136
0
    unsigned int index = ecGroup - ssl_named_groups;
137
0
    PRStatus prv;
138
0
    sslSocketAndGroupArg arg = { ecGroup, ss };
139
0
140
0
    prv = PR_CallOnceWithArg(&gECDHEKeyPairs[index].once,
141
0
                             ssl_CreateStaticECDHEKeyPair,
142
0
                             (void *)&arg);
143
0
    PORT_Assert(prv == PR_SUCCESS);
144
0
    if (prv != PR_SUCCESS) {
145
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
146
0
        return SECFailure;
147
0
    }
148
0
149
0
    keyPair = gECDHEKeyPairs[index].keyPair;
150
0
    if (!keyPair) {
151
0
        /* Attempting to use a key pair for an unsupported group. */
152
0
        PORT_Assert(keyPair);
153
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
154
0
        return SECFailure;
155
0
    }
156
0
157
0
    keyPair = ssl_CopyEphemeralKeyPair(keyPair);
158
0
    if (!keyPair)
159
0
        return SECFailure;
160
0
161
0
    PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
162
0
    PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
163
0
    return SECSuccess;
164
0
}