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 }