/src/nss/lib/ssl/ssl3ecc.c
Line | Count | Source |
1 | | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * SSL3 Protocol |
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 | | /* ECC code moved here from ssl3con.c */ |
10 | | |
11 | | #include "cert.h" |
12 | | #include "ssl.h" |
13 | | #include "cryptohi.h" /* for DSAU_ stuff */ |
14 | | #include "keyhi.h" |
15 | | #include "secder.h" |
16 | | #include "secitem.h" |
17 | | |
18 | | #include "sslimpl.h" |
19 | | #include "sslproto.h" |
20 | | #include "sslerr.h" |
21 | | #include "ssl3ext.h" |
22 | | #include "prtime.h" |
23 | | #include "prinrval.h" |
24 | | #include "prerror.h" |
25 | | #include "pratom.h" |
26 | | #include "prthread.h" |
27 | | #include "prinit.h" |
28 | | |
29 | | #include "pk11func.h" |
30 | | #include "secmod.h" |
31 | | |
32 | | #include <stdio.h> |
33 | | |
34 | | SECStatus |
35 | | ssl_NamedGroup2ECParams(PLArenaPool *arena, const sslNamedGroupDef *ecGroup, |
36 | | SECKEYECParams *params) |
37 | 81.0k | { |
38 | 81.0k | SECOidData *oidData = NULL; |
39 | | |
40 | 81.0k | if (!params) { |
41 | 0 | PORT_Assert(0); |
42 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
43 | 0 | return SECFailure; |
44 | 0 | } |
45 | | |
46 | 81.0k | if (!ecGroup || ecGroup->keaType != ssl_kea_ecdh || |
47 | 81.0k | (oidData = SECOID_FindOIDByTag(ecGroup->oidTag)) == NULL) { |
48 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
49 | 0 | return SECFailure; |
50 | 0 | } |
51 | | |
52 | 81.0k | if (SECITEM_AllocItem(arena, params, (2 + oidData->oid.len)) == NULL) { |
53 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
54 | 0 | return SECFailure; |
55 | 0 | } |
56 | | |
57 | | /* |
58 | | * params->data needs to contain the ASN encoding of an object ID (OID) |
59 | | * representing the named curve. The actual OID is in |
60 | | * oidData->oid.data so we simply prepend 0x06 and OID length |
61 | | */ |
62 | 81.0k | params->data[0] = SEC_ASN1_OBJECT_ID; |
63 | 81.0k | params->data[1] = oidData->oid.len; |
64 | 81.0k | memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); |
65 | | |
66 | 81.0k | return SECSuccess; |
67 | 81.0k | } |
68 | | |
69 | | const sslNamedGroupDef * |
70 | | ssl_ECPubKey2NamedGroup(const SECKEYPublicKey *pubKey) |
71 | 57.5k | { |
72 | 57.5k | SECItem oid = { siBuffer, NULL, 0 }; |
73 | 57.5k | SECOidData *oidData = NULL; |
74 | 57.5k | PRUint32 policyFlags = 0; |
75 | 57.5k | unsigned int i; |
76 | 57.5k | const SECKEYECParams *params; |
77 | | |
78 | 57.5k | if (pubKey->keyType != ecKey) { |
79 | 0 | PORT_Assert(0); |
80 | 0 | return NULL; |
81 | 0 | } |
82 | | |
83 | 57.5k | params = &pubKey->u.ec.DEREncodedParams; |
84 | | |
85 | | /* |
86 | | * params->data needs to contain the ASN encoding of an object ID (OID) |
87 | | * representing a named curve. Here, we strip away everything |
88 | | * before the actual OID and use the OID to look up a named curve. |
89 | | */ |
90 | 57.5k | if (params->data[0] != SEC_ASN1_OBJECT_ID) |
91 | 0 | return NULL; |
92 | 57.5k | oid.len = params->len - 2; |
93 | 57.5k | oid.data = params->data + 2; |
94 | 57.5k | if ((oidData = SECOID_FindOID(&oid)) == NULL) |
95 | 0 | return NULL; |
96 | 57.5k | if ((NSS_GetAlgorithmPolicy(oidData->offset, &policyFlags) == |
97 | 57.5k | SECSuccess) && |
98 | 57.5k | !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) { |
99 | 0 | return NULL; |
100 | 0 | } |
101 | 175k | for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { |
102 | 175k | if (ssl_named_groups[i].oidTag == oidData->offset) { |
103 | 57.4k | return &ssl_named_groups[i]; |
104 | 57.4k | } |
105 | 175k | } |
106 | | |
107 | 17 | return NULL; |
108 | 57.5k | } |
109 | | |
110 | | /* Caller must set hiLevel error code. */ |
111 | | static SECStatus |
112 | | ssl3_ComputeECDHKeyHash(SSLHashType hashAlg, |
113 | | SECItem ec_params, SECItem server_ecpoint, |
114 | | PRUint8 *client_rand, PRUint8 *server_rand, |
115 | | SSL3Hashes *hashes) |
116 | 29.5k | { |
117 | 29.5k | PRUint8 *hashBuf; |
118 | 29.5k | PRUint8 *pBuf; |
119 | 29.5k | SECStatus rv = SECSuccess; |
120 | 29.5k | unsigned int bufLen; |
121 | | /* |
122 | | * We only support named curves (the appropriate checks are made before this |
123 | | * method is called) so ec_params takes up only two bytes. ECPoint needs to |
124 | | * fit in 256 bytes because the spec says the length must fit in one byte. |
125 | | */ |
126 | 29.5k | PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 1 + 256]; |
127 | | |
128 | 29.5k | bufLen = 2 * SSL3_RANDOM_LENGTH + ec_params.len + 1 + server_ecpoint.len; |
129 | 29.5k | if (bufLen <= sizeof buf) { |
130 | 29.5k | hashBuf = buf; |
131 | 29.5k | } else { |
132 | 0 | hashBuf = PORT_Alloc(bufLen); |
133 | 0 | if (!hashBuf) { |
134 | 0 | return SECFailure; |
135 | 0 | } |
136 | 0 | } |
137 | | |
138 | 29.5k | memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); |
139 | 29.5k | pBuf = hashBuf + SSL3_RANDOM_LENGTH; |
140 | 29.5k | memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); |
141 | 29.5k | pBuf += SSL3_RANDOM_LENGTH; |
142 | 29.5k | memcpy(pBuf, ec_params.data, ec_params.len); |
143 | 29.5k | pBuf += ec_params.len; |
144 | 29.5k | pBuf[0] = (PRUint8)(server_ecpoint.len); |
145 | 29.5k | pBuf += 1; |
146 | 29.5k | memcpy(pBuf, server_ecpoint.data, server_ecpoint.len); |
147 | 29.5k | pBuf += server_ecpoint.len; |
148 | 29.5k | PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); |
149 | | |
150 | 29.5k | rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes); |
151 | | |
152 | 29.5k | PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); |
153 | 29.5k | PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", |
154 | 29.5k | hashes->u.s.md5, MD5_LENGTH)); |
155 | 29.5k | PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", |
156 | 29.5k | hashes->u.s.sha, SHA1_LENGTH)); |
157 | | |
158 | 29.5k | if (hashBuf != buf) |
159 | 0 | PORT_Free(hashBuf); |
160 | 29.5k | return rv; |
161 | 29.5k | } |
162 | | |
163 | | /* Called from ssl3_SendClientKeyExchange(). */ |
164 | | SECStatus |
165 | | ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) |
166 | 33.1k | { |
167 | 33.1k | PK11SymKey *pms = NULL; |
168 | 33.1k | SECStatus rv = SECFailure; |
169 | 33.1k | PRBool isTLS, isTLS12; |
170 | 33.1k | CK_MECHANISM_TYPE target; |
171 | 33.1k | const sslNamedGroupDef *groupDef; |
172 | 33.1k | sslEphemeralKeyPair *keyPair = NULL; |
173 | 33.1k | SECKEYPublicKey *pubKey; |
174 | | |
175 | 33.1k | PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
176 | 33.1k | PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
177 | | |
178 | 33.1k | isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0); |
179 | 33.1k | isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
180 | | |
181 | | /* Generate ephemeral EC keypair */ |
182 | 33.1k | if (svrPubKey->keyType != ecKey) { |
183 | 18 | PORT_SetError(SEC_ERROR_BAD_KEY); |
184 | 18 | goto loser; |
185 | 18 | } |
186 | 33.1k | groupDef = ssl_ECPubKey2NamedGroup(svrPubKey); |
187 | 33.1k | if (!groupDef) { |
188 | 17 | PORT_SetError(SEC_ERROR_BAD_KEY); |
189 | 17 | goto loser; |
190 | 17 | } |
191 | 33.0k | ss->sec.keaGroup = groupDef; |
192 | 33.0k | rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, &keyPair); |
193 | 33.0k | if (rv != SECSuccess) { |
194 | 60 | ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); |
195 | 60 | goto loser; |
196 | 60 | } |
197 | | |
198 | 33.0k | pubKey = keyPair->keys->pubKey; |
199 | 33.0k | PRINT_BUF(50, (ss, "ECDH public value:", |
200 | 33.0k | pubKey->u.ec.publicValue.data, |
201 | 33.0k | pubKey->u.ec.publicValue.len)); |
202 | | |
203 | 33.0k | if (isTLS12) { |
204 | 2.31k | target = CKM_TLS12_MASTER_KEY_DERIVE_DH; |
205 | 30.7k | } else if (isTLS) { |
206 | 30.7k | target = CKM_TLS_MASTER_KEY_DERIVE_DH; |
207 | 30.7k | } else { |
208 | 0 | target = CKM_SSL3_MASTER_KEY_DERIVE_DH; |
209 | 0 | } |
210 | | |
211 | | /* Determine the PMS */ |
212 | 33.0k | pms = PK11_PubDeriveWithKDF(keyPair->keys->privKey, svrPubKey, |
213 | 33.0k | PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, |
214 | 33.0k | CKA_DERIVE, 0, CKD_NULL, NULL, NULL); |
215 | | |
216 | 33.0k | if (pms == NULL) { |
217 | 257 | (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); |
218 | 257 | ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); |
219 | 257 | goto loser; |
220 | 257 | } |
221 | | |
222 | 32.7k | rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange, |
223 | 32.7k | pubKey->u.ec.publicValue.len + 1); |
224 | 32.7k | if (rv != SECSuccess) { |
225 | 0 | goto loser; /* err set by ssl3_AppendHandshake* */ |
226 | 0 | } |
227 | | |
228 | 32.7k | rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, |
229 | 32.7k | pubKey->u.ec.publicValue.len, 1); |
230 | | |
231 | 32.7k | if (rv != SECSuccess) { |
232 | 0 | goto loser; /* err set by ssl3_AppendHandshake* */ |
233 | 0 | } |
234 | | |
235 | 32.7k | rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); |
236 | 32.7k | if (rv != SECSuccess) { |
237 | 0 | ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); |
238 | 0 | goto loser; |
239 | 0 | } |
240 | | |
241 | 32.7k | PK11_FreeSymKey(pms); |
242 | 32.7k | ssl_FreeEphemeralKeyPair(keyPair); |
243 | 32.7k | return SECSuccess; |
244 | | |
245 | 352 | loser: |
246 | 352 | if (pms) |
247 | 0 | PK11_FreeSymKey(pms); |
248 | 352 | if (keyPair) |
249 | 257 | ssl_FreeEphemeralKeyPair(keyPair); |
250 | 352 | return SECFailure; |
251 | 32.7k | } |
252 | | |
253 | | /* |
254 | | ** Called from ssl3_HandleClientKeyExchange() |
255 | | */ |
256 | | SECStatus |
257 | | ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b, |
258 | | PRUint32 length, |
259 | | sslKeyPair *serverKeyPair) |
260 | 22.1k | { |
261 | 22.1k | PK11SymKey *pms; |
262 | 22.1k | SECStatus rv; |
263 | 22.1k | SECKEYPublicKey clntPubKey; |
264 | 22.1k | CK_MECHANISM_TYPE target; |
265 | 22.1k | PRBool isTLS, isTLS12; |
266 | 22.1k | int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH; |
267 | | |
268 | 22.1k | PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); |
269 | 22.1k | PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
270 | | |
271 | 22.1k | clntPubKey.keyType = ecKey; |
272 | 22.1k | clntPubKey.u.ec.DEREncodedParams.len = |
273 | 22.1k | serverKeyPair->pubKey->u.ec.DEREncodedParams.len; |
274 | 22.1k | clntPubKey.u.ec.DEREncodedParams.data = |
275 | 22.1k | serverKeyPair->pubKey->u.ec.DEREncodedParams.data; |
276 | 22.1k | clntPubKey.u.ec.encoding = ECPoint_Undefined; |
277 | | |
278 | 22.1k | rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, |
279 | 22.1k | 1, &b, &length); |
280 | 22.1k | if (rv != SECSuccess) { |
281 | 26 | PORT_SetError(errCode); |
282 | 26 | return SECFailure; |
283 | 26 | } |
284 | | |
285 | | /* we have to catch the case when the client's public key has length 0. */ |
286 | 22.1k | if (!clntPubKey.u.ec.publicValue.len) { |
287 | 12 | (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); |
288 | 12 | PORT_SetError(errCode); |
289 | 12 | return SECFailure; |
290 | 12 | } |
291 | | |
292 | 22.1k | isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
293 | 22.1k | isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
294 | | |
295 | 22.1k | if (isTLS12) { |
296 | 19.6k | target = CKM_TLS12_MASTER_KEY_DERIVE_DH; |
297 | 19.6k | } else if (isTLS) { |
298 | 2.45k | target = CKM_TLS_MASTER_KEY_DERIVE_DH; |
299 | 2.45k | } else { |
300 | 0 | target = CKM_SSL3_MASTER_KEY_DERIVE_DH; |
301 | 0 | } |
302 | | |
303 | | /* Determine the PMS */ |
304 | 22.1k | pms = PK11_PubDeriveWithKDF(serverKeyPair->privKey, &clntPubKey, |
305 | 22.1k | PR_FALSE, NULL, NULL, |
306 | 22.1k | CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, |
307 | 22.1k | CKD_NULL, NULL, NULL); |
308 | | |
309 | 22.1k | if (pms == NULL) { |
310 | | /* last gasp. */ |
311 | 667 | errCode = ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); |
312 | 667 | PORT_SetError(errCode); |
313 | 667 | return SECFailure; |
314 | 667 | } |
315 | | |
316 | 21.4k | rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE); |
317 | 21.4k | PK11_FreeSymKey(pms); |
318 | 21.4k | if (rv != SECSuccess) { |
319 | | /* error code set by ssl3_InitPendingCipherSpec */ |
320 | 0 | return SECFailure; |
321 | 0 | } |
322 | 21.4k | ss->sec.keaGroup = ssl_ECPubKey2NamedGroup(&clntPubKey); |
323 | 21.4k | return SECSuccess; |
324 | 21.4k | } |
325 | | |
326 | | /* |
327 | | ** Take an encoded key share and make a public key out of it. |
328 | | */ |
329 | | SECStatus |
330 | | ssl_ImportECDHKeyShare(SECKEYPublicKey *peerKey, |
331 | | PRUint8 *b, PRUint32 length, |
332 | | const sslNamedGroupDef *ecGroup) |
333 | 5.58k | { |
334 | 5.58k | SECStatus rv; |
335 | 5.58k | SECItem ecPoint = { siBuffer, NULL, 0 }; |
336 | | |
337 | 5.58k | if (!length) { |
338 | 7 | PORT_SetError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE); |
339 | 7 | return SECFailure; |
340 | 7 | } |
341 | | |
342 | | /* Fail if the ec point uses compressed representation */ |
343 | 5.58k | if (b[0] != EC_POINT_FORM_UNCOMPRESSED && |
344 | 3.51k | ecGroup->name != ssl_grp_ec_curve25519) { |
345 | 20 | PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); |
346 | 20 | return SECFailure; |
347 | 20 | } |
348 | | |
349 | 5.56k | peerKey->keyType = ecKey; |
350 | | /* Set up the encoded params */ |
351 | 5.56k | rv = ssl_NamedGroup2ECParams(peerKey->arena, ecGroup, |
352 | 5.56k | &peerKey->u.ec.DEREncodedParams); |
353 | 5.56k | if (rv != SECSuccess) { |
354 | 0 | ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE); |
355 | 0 | return SECFailure; |
356 | 0 | } |
357 | 5.56k | peerKey->u.ec.encoding = ECPoint_Undefined; |
358 | | |
359 | | /* copy publicValue in peerKey */ |
360 | 5.56k | ecPoint.data = b; |
361 | 5.56k | ecPoint.len = length; |
362 | | |
363 | 5.56k | rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.ec.publicValue, &ecPoint); |
364 | 5.56k | if (rv != SECSuccess) { |
365 | 0 | return SECFailure; |
366 | 0 | } |
367 | | |
368 | 5.56k | return SECSuccess; |
369 | 5.56k | } |
370 | | |
371 | | const sslNamedGroupDef * |
372 | | ssl_GetECGroupWithStrength(sslSocket *ss, unsigned int requiredECCbits) |
373 | 25.2k | { |
374 | 25.2k | int i; |
375 | | |
376 | 25.2k | PORT_Assert(ss); |
377 | | |
378 | 78.2k | for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { |
379 | 78.2k | const sslNamedGroupDef *group = ss->namedGroupPreferences[i]; |
380 | 78.2k | if (group && group->keaType == ssl_kea_ecdh && |
381 | 25.2k | group->bits >= requiredECCbits) { |
382 | 25.2k | return group; |
383 | 25.2k | } |
384 | 78.2k | } |
385 | | |
386 | 13 | PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); |
387 | 13 | return NULL; |
388 | 25.2k | } |
389 | | |
390 | | /* Find the "weakest link". Get the strength of the signature and symmetric |
391 | | * keys and choose a curve based on the weakest of those two. */ |
392 | | const sslNamedGroupDef * |
393 | | ssl_GetECGroupForServerSocket(sslSocket *ss) |
394 | 25.2k | { |
395 | 25.2k | const sslServerCert *cert = ss->sec.serverCert; |
396 | 25.2k | unsigned int certKeySize; |
397 | 25.2k | const ssl3BulkCipherDef *bulkCipher; |
398 | 25.2k | unsigned int requiredECCbits; |
399 | | |
400 | 25.2k | PORT_Assert(cert); |
401 | 25.2k | if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) { |
402 | 0 | PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); |
403 | 0 | return NULL; |
404 | 0 | } |
405 | | |
406 | 25.2k | if (SSL_CERT_IS(cert, ssl_auth_rsa_sign) || |
407 | 17.3k | SSL_CERT_IS(cert, ssl_auth_rsa_pss)) { |
408 | 17.3k | certKeySize = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey); |
409 | 17.3k | certKeySize = SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize); |
410 | 17.3k | } else if (SSL_CERT_IS_EC(cert)) { |
411 | | /* We won't select a certificate unless the named curve has been |
412 | | * negotiated (or supported_curves was absent), double check that. */ |
413 | 7.91k | PORT_Assert(cert->namedCurve->keaType == ssl_kea_ecdh); |
414 | 7.91k | PORT_Assert(ssl_NamedGroupEnabled(ss, cert->namedCurve)); |
415 | 7.91k | if (!ssl_NamedGroupEnabled(ss, cert->namedCurve)) { |
416 | 0 | return NULL; |
417 | 0 | } |
418 | 7.91k | certKeySize = cert->namedCurve->bits; |
419 | 7.91k | } else { |
420 | 0 | PORT_Assert(0); |
421 | 0 | return NULL; |
422 | 0 | } |
423 | 25.2k | bulkCipher = ssl_GetBulkCipherDef(ss->ssl3.hs.suite_def); |
424 | 25.2k | requiredECCbits = bulkCipher->key_size * BPB * 2; |
425 | 25.2k | PORT_Assert(requiredECCbits || |
426 | 25.2k | ss->ssl3.hs.suite_def->bulk_cipher_alg == cipher_null); |
427 | 25.2k | if (requiredECCbits > certKeySize) { |
428 | 23.2k | requiredECCbits = certKeySize; |
429 | 23.2k | } |
430 | | |
431 | 25.2k | return ssl_GetECGroupWithStrength(ss, requiredECCbits); |
432 | 25.2k | } |
433 | | |
434 | | /* ssl_CreateECDHEPrivateKey is a variant of SECKEY_CreateECPrivateKey that |
435 | | * tries to use CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN instead of CKM_EC_KEY_PAIR_GEN. |
436 | | * Softoken's implementation of CKM_EC_KEY_PAIR_GEN always performs the |
437 | | * SP800-56A pairwise consistency check, even though Section 5.6.2.1.4 of that |
438 | | * document only requires that check for static keys. The |
439 | | * CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN mechanism skips the pairwise consistency |
440 | | * check, but is otherwise identical to CKM_EC_KEY_PAIR_GEN. */ |
441 | | static SECKEYPrivateKey * |
442 | | ssl_CreateECDHEPrivateKey(SECKEYECParams *param, SECKEYPublicKey **pubk, void *cx) |
443 | 75.4k | { |
444 | 75.4k | SECKEYPrivateKey *privk = NULL; |
445 | 75.4k | CK_MECHANISM_TYPE type = CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN; |
446 | | |
447 | 75.4k | PK11SlotInfo *slot = PK11_GetInternalSlot(); |
448 | 75.4k | if (!slot || !PK11_DoesMechanism(slot, type) || PK11_IsFIPS()) { |
449 | 0 | if (slot) { |
450 | 0 | PK11_FreeSlot(slot); |
451 | 0 | } |
452 | 0 | return SECKEY_CreateECPrivateKey(param, pubk, cx); |
453 | 0 | } |
454 | | |
455 | 75.4k | privk = PK11_GenerateKeyPairWithOpFlags(slot, type, param, pubk, |
456 | 75.4k | PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC, |
457 | 75.4k | CKF_DERIVE, CKF_DERIVE, cx); |
458 | 75.4k | if (!privk) { |
459 | 371 | privk = PK11_GenerateKeyPairWithOpFlags(slot, type, param, pubk, |
460 | 371 | PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE, |
461 | 371 | CKF_DERIVE, CKF_DERIVE, cx); |
462 | 371 | } |
463 | | |
464 | 75.4k | PK11_FreeSlot(slot); |
465 | 75.4k | return privk; |
466 | 75.4k | } |
467 | | |
468 | | /* Create an ECDHE key pair for a given curve */ |
469 | | SECStatus |
470 | | ssl_CreateECDHEphemeralKeyPair(const sslSocket *ss, |
471 | | const sslNamedGroupDef *ecGroup, |
472 | | sslEphemeralKeyPair **keyPair) |
473 | 75.4k | { |
474 | 75.4k | SECKEYPrivateKey *privKey = NULL; |
475 | 75.4k | SECKEYPublicKey *pubKey = NULL; |
476 | 75.4k | SECKEYECParams ecParams = { siBuffer, NULL, 0 }; |
477 | 75.4k | sslEphemeralKeyPair *pair; |
478 | | |
479 | 75.4k | if (ssl_NamedGroup2ECParams(NULL, ecGroup, &ecParams) != SECSuccess) { |
480 | 0 | return SECFailure; |
481 | 0 | } |
482 | 75.4k | privKey = ssl_CreateECDHEPrivateKey(&ecParams, &pubKey, ss->pkcs11PinArg); |
483 | 75.4k | SECITEM_FreeItem(&ecParams, PR_FALSE); |
484 | | |
485 | 75.4k | if (!privKey || !pubKey || |
486 | 75.0k | !(pair = ssl_NewEphemeralKeyPair(ecGroup, privKey, pubKey))) { |
487 | 371 | if (privKey) { |
488 | 0 | SECKEY_DestroyPrivateKey(privKey); |
489 | 0 | } |
490 | 371 | if (pubKey) { |
491 | 0 | SECKEY_DestroyPublicKey(pubKey); |
492 | 0 | } |
493 | 371 | ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); |
494 | 371 | return SECFailure; |
495 | 371 | } |
496 | | |
497 | 75.0k | *keyPair = pair; |
498 | 75.0k | SSL_TRC(50, ("%d: SSL[%d]: Create ECDH ephemeral key %d", |
499 | 75.0k | SSL_GETPID(), ss ? ss->fd : NULL, ecGroup->name)); |
500 | 75.0k | PRINT_BUF(50, (ss, "Public Key", pubKey->u.ec.publicValue.data, |
501 | 75.0k | pubKey->u.ec.publicValue.len)); |
502 | 75.0k | #ifdef TRACE |
503 | 75.0k | if (ssl_trace >= 50) { |
504 | 0 | SECItem d = { siBuffer, NULL, 0 }; |
505 | 0 | SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, |
506 | 0 | CKA_VALUE, &d); |
507 | 0 | if (rv == SECSuccess) { |
508 | 0 | PRINT_BUF(50, (ss, "Private Key", d.data, d.len)); |
509 | 0 | SECITEM_FreeItem(&d, PR_FALSE); |
510 | 0 | } else { |
511 | 0 | SSL_TRC(50, ("Error extracting private key")); |
512 | 0 | } |
513 | 0 | } |
514 | 75.0k | #endif |
515 | 75.0k | return SECSuccess; |
516 | 75.4k | } |
517 | | |
518 | | SECStatus |
519 | | ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) |
520 | 4.57k | { |
521 | 4.57k | PLArenaPool *arena = NULL; |
522 | 4.57k | SECKEYPublicKey *peerKey = NULL; |
523 | 4.57k | PRBool isTLS; |
524 | 4.57k | SECStatus rv; |
525 | 4.57k | int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; |
526 | 4.57k | SSL3AlertDescription desc = illegal_parameter; |
527 | 4.57k | SSL3Hashes hashes; |
528 | 4.57k | SECItem signature = { siBuffer, NULL, 0 }; |
529 | 4.57k | SSLHashType hashAlg; |
530 | 4.57k | SSLSignatureScheme sigScheme; |
531 | | |
532 | 4.57k | SECItem ec_params = { siBuffer, NULL, 0 }; |
533 | 4.57k | SECItem ec_point = { siBuffer, NULL, 0 }; |
534 | 4.57k | unsigned char paramBuf[3]; |
535 | 4.57k | const sslNamedGroupDef *ecGroup; |
536 | | |
537 | 4.57k | isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); |
538 | | |
539 | 4.57k | ec_params.len = sizeof paramBuf; |
540 | 4.57k | ec_params.data = paramBuf; |
541 | 4.57k | rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length); |
542 | 4.57k | if (rv != SECSuccess) { |
543 | 7 | goto loser; /* malformed. */ |
544 | 7 | } |
545 | | |
546 | | /* Fail if the curve is not a named curve */ |
547 | 4.56k | if (ec_params.data[0] != ec_type_named) { |
548 | 12 | errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; |
549 | 12 | desc = handshake_failure; |
550 | 12 | goto alert_loser; |
551 | 12 | } |
552 | 4.55k | ecGroup = ssl_LookupNamedGroup(ec_params.data[1] << 8 | ec_params.data[2]); |
553 | 4.55k | if (!ecGroup || ecGroup->keaType != ssl_kea_ecdh) { |
554 | 27 | errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; |
555 | 27 | desc = handshake_failure; |
556 | 27 | goto alert_loser; |
557 | 27 | } |
558 | | |
559 | 4.52k | rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length); |
560 | 4.52k | if (rv != SECSuccess) { |
561 | 6 | goto loser; /* malformed. */ |
562 | 6 | } |
563 | | |
564 | | /* Fail if the provided point has length 0. */ |
565 | 4.51k | if (!ec_point.len) { |
566 | | /* desc and errCode are initialized already */ |
567 | 4 | goto alert_loser; |
568 | 4 | } |
569 | | |
570 | | /* Fail if the ec point is not uncompressed for any curve that's not 25519. */ |
571 | 4.51k | if (ecGroup->name != ssl_grp_ec_curve25519 && |
572 | 294 | ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
573 | 15 | errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM; |
574 | 15 | desc = handshake_failure; |
575 | 15 | goto alert_loser; |
576 | 15 | } |
577 | | |
578 | 4.49k | PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2); |
579 | 4.49k | if (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) { |
580 | 3.36k | rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); |
581 | 3.36k | if (rv != SECSuccess) { |
582 | 47 | errCode = PORT_GetError(); |
583 | 47 | goto alert_loser; /* malformed or unsupported. */ |
584 | 47 | } |
585 | 3.31k | rv = ssl_CheckSignatureSchemeConsistency( |
586 | 3.31k | ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo); |
587 | 3.31k | if (rv != SECSuccess) { |
588 | 98 | errCode = PORT_GetError(); |
589 | 98 | goto alert_loser; |
590 | 98 | } |
591 | 3.21k | hashAlg = ssl_SignatureSchemeToHashType(sigScheme); |
592 | 3.21k | } else { |
593 | | /* Use ssl_hash_none to represent the MD5+SHA1 combo. */ |
594 | 1.13k | hashAlg = ssl_hash_none; |
595 | 1.13k | sigScheme = ssl_sig_none; |
596 | 1.13k | } |
597 | | |
598 | 4.35k | rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); |
599 | 4.35k | if (rv != SECSuccess) { |
600 | 13 | goto loser; /* malformed. */ |
601 | 13 | } |
602 | | |
603 | 4.34k | if (length != 0) { |
604 | 9 | if (isTLS) |
605 | 9 | desc = decode_error; |
606 | 9 | goto alert_loser; /* malformed. */ |
607 | 9 | } |
608 | | |
609 | 4.33k | PRINT_BUF(60, (NULL, "Server EC params", ec_params.data, ec_params.len)); |
610 | 4.33k | PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len)); |
611 | | |
612 | | /* failures after this point are not malformed handshakes. */ |
613 | | /* TLS: send decrypt_error if signature failed. */ |
614 | 4.33k | desc = isTLS ? decrypt_error : handshake_failure; |
615 | | |
616 | | /* |
617 | | * check to make sure the hash is signed by right guy |
618 | | */ |
619 | 4.33k | rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, ec_point, |
620 | 4.33k | ss->ssl3.hs.client_random, |
621 | 4.33k | ss->ssl3.hs.server_random, |
622 | 4.33k | &hashes); |
623 | | |
624 | 4.33k | if (rv != SECSuccess) { |
625 | 0 | errCode = |
626 | 0 | ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); |
627 | 0 | goto alert_loser; |
628 | 0 | } |
629 | 4.33k | rv = ssl3_VerifySignedHashes(ss, sigScheme, &hashes, &signature); |
630 | 4.33k | if (rv != SECSuccess) { |
631 | 1.80k | errCode = |
632 | 1.80k | ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); |
633 | 1.80k | goto alert_loser; |
634 | 1.80k | } |
635 | | |
636 | 2.52k | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
637 | 2.52k | if (arena == NULL) { |
638 | 0 | errCode = SEC_ERROR_NO_MEMORY; |
639 | 0 | goto loser; |
640 | 0 | } |
641 | | |
642 | 2.52k | peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); |
643 | 2.52k | if (peerKey == NULL) { |
644 | 0 | errCode = SEC_ERROR_NO_MEMORY; |
645 | 0 | goto loser; |
646 | 0 | } |
647 | 2.52k | peerKey->arena = arena; |
648 | | |
649 | | /* create public key from point data */ |
650 | 2.52k | rv = ssl_ImportECDHKeyShare(peerKey, ec_point.data, ec_point.len, |
651 | 2.52k | ecGroup); |
652 | 2.52k | if (rv != SECSuccess) { |
653 | | /* error code is set */ |
654 | 0 | desc = handshake_failure; |
655 | 0 | errCode = PORT_GetError(); |
656 | 0 | goto alert_loser; |
657 | 0 | } |
658 | 2.52k | peerKey->pkcs11Slot = NULL; |
659 | 2.52k | peerKey->pkcs11ID = CK_INVALID_HANDLE; |
660 | | |
661 | 2.52k | ss->sec.peerKey = peerKey; |
662 | 2.52k | return SECSuccess; |
663 | | |
664 | 2.02k | alert_loser: |
665 | 2.02k | (void)SSL3_SendAlert(ss, alert_fatal, desc); |
666 | 2.04k | loser: |
667 | 2.04k | if (arena) { |
668 | 0 | PORT_FreeArena(arena, PR_FALSE); |
669 | 0 | } |
670 | 2.04k | PORT_SetError(errCode); |
671 | 2.04k | return SECFailure; |
672 | 2.02k | } |
673 | | |
674 | | SECStatus |
675 | | ssl3_SendECDHServerKeyExchange(sslSocket *ss) |
676 | 25.2k | { |
677 | 25.2k | SECStatus rv = SECFailure; |
678 | 25.2k | int length; |
679 | 25.2k | PRBool isTLS12; |
680 | 25.2k | SECItem signed_hash = { siBuffer, NULL, 0 }; |
681 | 25.2k | SSLHashType hashAlg; |
682 | 25.2k | SSL3Hashes hashes; |
683 | | |
684 | 25.2k | SECItem ec_params = { siBuffer, NULL, 0 }; |
685 | 25.2k | unsigned char paramBuf[3]; |
686 | 25.2k | const sslNamedGroupDef *ecGroup; |
687 | 25.2k | sslEphemeralKeyPair *keyPair; |
688 | 25.2k | SECKEYPublicKey *pubKey; |
689 | | |
690 | | /* Generate ephemeral ECDH key pair and send the public key */ |
691 | 25.2k | ecGroup = ssl_GetECGroupForServerSocket(ss); |
692 | 25.2k | if (!ecGroup) { |
693 | 13 | goto loser; |
694 | 13 | } |
695 | | |
696 | 25.2k | PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); |
697 | 25.2k | if (ss->opt.reuseServerECDHEKey) { |
698 | 0 | rv = ssl_CreateStaticECDHEKey(ss, ecGroup); |
699 | 0 | if (rv != SECSuccess) { |
700 | 0 | goto loser; |
701 | 0 | } |
702 | 0 | keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); |
703 | 25.2k | } else { |
704 | 25.2k | rv = ssl_CreateECDHEphemeralKeyPair(ss, ecGroup, &keyPair); |
705 | 25.2k | if (rv != SECSuccess) { |
706 | 36 | goto loser; |
707 | 36 | } |
708 | 25.1k | PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs); |
709 | 25.1k | } |
710 | | |
711 | 25.1k | PORT_Assert(keyPair); |
712 | 25.1k | if (!keyPair) { |
713 | 0 | PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); |
714 | 0 | return SECFailure; |
715 | 0 | } |
716 | | |
717 | 25.1k | ec_params.len = sizeof(paramBuf); |
718 | 25.1k | ec_params.data = paramBuf; |
719 | 25.1k | PORT_Assert(keyPair->group); |
720 | 25.1k | PORT_Assert(keyPair->group->keaType == ssl_kea_ecdh); |
721 | 25.1k | ec_params.data[0] = ec_type_named; |
722 | 25.1k | ec_params.data[1] = keyPair->group->name >> 8; |
723 | 25.1k | ec_params.data[2] = keyPair->group->name & 0xff; |
724 | | |
725 | 25.1k | pubKey = keyPair->keys->pubKey; |
726 | 25.1k | if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) { |
727 | 22.5k | hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme); |
728 | 22.5k | } else { |
729 | | /* Use ssl_hash_none to represent the MD5+SHA1 combo. */ |
730 | 2.66k | hashAlg = ssl_hash_none; |
731 | 2.66k | } |
732 | 25.1k | rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, |
733 | 25.1k | pubKey->u.ec.publicValue, |
734 | 25.1k | ss->ssl3.hs.client_random, |
735 | 25.1k | ss->ssl3.hs.server_random, |
736 | 25.1k | &hashes); |
737 | 25.1k | if (rv != SECSuccess) { |
738 | 0 | ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); |
739 | 0 | goto loser; |
740 | 0 | } |
741 | | |
742 | 25.1k | isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2); |
743 | | |
744 | 25.1k | rv = ssl3_SignHashes(ss, &hashes, |
745 | 25.1k | ss->sec.serverCert->serverKeyPair->privKey, &signed_hash); |
746 | 25.1k | if (rv != SECSuccess) { |
747 | 0 | goto loser; /* ssl3_SignHashes has set err. */ |
748 | 0 | } |
749 | | |
750 | 25.1k | length = ec_params.len + |
751 | 25.1k | 1 + pubKey->u.ec.publicValue.len + |
752 | 25.1k | (isTLS12 ? 2 : 0) + 2 + signed_hash.len; |
753 | | |
754 | 25.1k | rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length); |
755 | 25.1k | if (rv != SECSuccess) { |
756 | 0 | goto loser; /* err set by AppendHandshake. */ |
757 | 0 | } |
758 | | |
759 | 25.1k | rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len); |
760 | 25.1k | if (rv != SECSuccess) { |
761 | 0 | goto loser; /* err set by AppendHandshake. */ |
762 | 0 | } |
763 | | |
764 | 25.1k | rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, |
765 | 25.1k | pubKey->u.ec.publicValue.len, 1); |
766 | 25.1k | if (rv != SECSuccess) { |
767 | 0 | goto loser; /* err set by AppendHandshake. */ |
768 | 0 | } |
769 | | |
770 | 25.1k | if (isTLS12) { |
771 | 22.5k | rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.signatureScheme, 2); |
772 | 22.5k | if (rv != SECSuccess) { |
773 | 0 | goto loser; /* err set by AppendHandshake. */ |
774 | 0 | } |
775 | 22.5k | } |
776 | | |
777 | 25.1k | rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, |
778 | 25.1k | signed_hash.len, 2); |
779 | 25.1k | if (rv != SECSuccess) { |
780 | 0 | goto loser; /* err set by AppendHandshake. */ |
781 | 0 | } |
782 | | |
783 | 25.1k | PORT_Free(signed_hash.data); |
784 | 25.1k | return SECSuccess; |
785 | | |
786 | 49 | loser: |
787 | 49 | if (signed_hash.data != NULL) |
788 | 0 | PORT_Free(signed_hash.data); |
789 | 49 | return SECFailure; |
790 | 25.1k | } |
791 | | |
792 | | /* List of all ECC cipher suites */ |
793 | | static const ssl3CipherSuite ssl_all_ec_suites[] = { |
794 | | TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, |
795 | | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, |
796 | | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, |
797 | | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
798 | | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, |
799 | | TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, |
800 | | TLS_ECDHE_ECDSA_WITH_NULL_SHA, |
801 | | TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, |
802 | | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, |
803 | | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, |
804 | | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, |
805 | | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, |
806 | | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, |
807 | | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
808 | | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, |
809 | | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, |
810 | | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, |
811 | | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, |
812 | | TLS_ECDHE_RSA_WITH_NULL_SHA, |
813 | | TLS_ECDHE_RSA_WITH_RC4_128_SHA, |
814 | | TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, |
815 | | TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, |
816 | | TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, |
817 | | TLS_ECDH_ECDSA_WITH_NULL_SHA, |
818 | | TLS_ECDH_ECDSA_WITH_RC4_128_SHA, |
819 | | TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, |
820 | | TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, |
821 | | TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, |
822 | | TLS_ECDH_RSA_WITH_NULL_SHA, |
823 | | TLS_ECDH_RSA_WITH_RC4_128_SHA, |
824 | | 0 /* end of list marker */ |
825 | | }; |
826 | | |
827 | | static const ssl3CipherSuite ssl_dhe_suites[] = { |
828 | | TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, |
829 | | TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, |
830 | | TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, |
831 | | TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, |
832 | | TLS_DHE_RSA_WITH_AES_128_CBC_SHA, |
833 | | TLS_DHE_DSS_WITH_AES_128_CBC_SHA, |
834 | | TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, |
835 | | TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, |
836 | | TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, |
837 | | TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, |
838 | | TLS_DHE_RSA_WITH_AES_256_CBC_SHA, |
839 | | TLS_DHE_DSS_WITH_AES_256_CBC_SHA, |
840 | | TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, |
841 | | TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, |
842 | | TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, |
843 | | TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, |
844 | | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, |
845 | | TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, |
846 | | TLS_DHE_DSS_WITH_RC4_128_SHA, |
847 | | TLS_DHE_RSA_WITH_DES_CBC_SHA, |
848 | | TLS_DHE_DSS_WITH_DES_CBC_SHA, |
849 | | 0 |
850 | | }; |
851 | | |
852 | | /* Order(N^2). Yuk. */ |
853 | | static PRBool |
854 | | ssl_IsSuiteEnabled(const sslSocket *ss, const ssl3CipherSuite *list) |
855 | 171k | { |
856 | 171k | const ssl3CipherSuite *suite; |
857 | | |
858 | 171k | for (suite = list; *suite; ++suite) { |
859 | 171k | PRBool enabled = PR_FALSE; |
860 | 171k | SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled); |
861 | | |
862 | 171k | PORT_Assert(rv == SECSuccess); /* else is coding error */ |
863 | 171k | if (rv == SECSuccess && enabled) |
864 | 171k | return PR_TRUE; |
865 | 171k | } |
866 | 0 | return PR_FALSE; |
867 | 171k | } |
868 | | |
869 | | /* Ask: is ANY ECC cipher suite enabled on this socket? */ |
870 | | PRBool |
871 | | ssl_IsECCEnabled(const sslSocket *ss) |
872 | 142k | { |
873 | 142k | PK11SlotInfo *slot; |
874 | | |
875 | | /* make sure we can do ECC */ |
876 | 142k | slot = PK11_GetBestSlot(CKM_ECDH1_DERIVE, ss->pkcs11PinArg); |
877 | 142k | if (!slot) { |
878 | 0 | return PR_FALSE; |
879 | 0 | } |
880 | 142k | PK11_FreeSlot(slot); |
881 | | |
882 | | /* make sure an ECC cipher is enabled */ |
883 | 142k | return ssl_IsSuiteEnabled(ss, ssl_all_ec_suites); |
884 | 142k | } |
885 | | |
886 | | PRBool |
887 | | ssl_IsDHEEnabled(const sslSocket *ss) |
888 | 29.1k | { |
889 | 29.1k | return ssl_IsSuiteEnabled(ss, ssl_dhe_suites); |
890 | 29.1k | } |
891 | | |
892 | | /* Send our Supported Groups extension. */ |
893 | | SECStatus |
894 | | ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData, |
895 | | sslBuffer *buf, PRBool *added) |
896 | 79.9k | { |
897 | 79.9k | unsigned int i; |
898 | 79.9k | PRBool ec; |
899 | 79.9k | PRBool ec_hybrid = PR_FALSE; |
900 | 79.9k | PRBool ff = PR_FALSE; |
901 | 79.9k | PRBool found = PR_FALSE; |
902 | 79.9k | SECStatus rv; |
903 | 79.9k | unsigned int lengthOffset; |
904 | | |
905 | | /* We only send FF supported groups if we require DH named groups |
906 | | * or if TLS 1.3 is a possibility. */ |
907 | 79.9k | if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { |
908 | 60.0k | ec = ssl_IsECCEnabled(ss); |
909 | 60.0k | if (ss->opt.requireDHENamedGroups) { |
910 | 29.1k | ff = ssl_IsDHEEnabled(ss); |
911 | 29.1k | } |
912 | 60.0k | if (!ec && !ff) { |
913 | 0 | return SECSuccess; |
914 | 0 | } |
915 | 60.0k | } else { |
916 | 19.8k | ec = ec_hybrid = ff = PR_TRUE; |
917 | 19.8k | } |
918 | | |
919 | | /* Mark the location of the length. */ |
920 | 79.9k | rv = sslBuffer_Skip(buf, 2, &lengthOffset); |
921 | 79.9k | if (rv != SECSuccess) { |
922 | 0 | return SECFailure; |
923 | 0 | } |
924 | | |
925 | 2.87M | for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { |
926 | 2.79M | const sslNamedGroupDef *group = ss->namedGroupPreferences[i]; |
927 | 2.79M | if (!group) { |
928 | 1.86M | continue; |
929 | 1.86M | } |
930 | 929k | if (group->keaType == ssl_kea_ecdh && !ec) { |
931 | 0 | continue; |
932 | 0 | } |
933 | 929k | if (group->keaType == ssl_kea_ecdh_hybrid && !ec_hybrid) { |
934 | 180k | continue; |
935 | 180k | } |
936 | 749k | if (group->keaType == ssl_kea_dh && !ff) { |
937 | 154k | continue; |
938 | 154k | } |
939 | | |
940 | 594k | found = PR_TRUE; |
941 | 594k | rv = sslBuffer_AppendNumber(buf, group->name, 2); |
942 | 594k | if (rv != SECSuccess) { |
943 | 0 | return SECFailure; |
944 | 0 | } |
945 | 594k | } |
946 | | |
947 | | /* GREASE SupportedGroups: |
948 | | * A client MAY select one or more GREASE named group values and advertise |
949 | | * them in the "supported_groups" extension, if sent [RFC8701, Section 3.1]. |
950 | | */ |
951 | 79.9k | if (!ss->sec.isServer && |
952 | 77.1k | ss->opt.enableGrease && |
953 | 39.8k | ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) { |
954 | 8.72k | rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_group], 2); |
955 | 8.72k | if (rv != SECSuccess) { |
956 | 0 | return SECFailure; |
957 | 0 | } |
958 | 8.72k | found = PR_TRUE; |
959 | 8.72k | } |
960 | | |
961 | 79.9k | if (!found) { |
962 | | /* We added nothing, don't send the extension. */ |
963 | 0 | return SECSuccess; |
964 | 0 | } |
965 | | |
966 | 79.9k | rv = sslBuffer_InsertLength(buf, lengthOffset, 2); |
967 | 79.9k | if (rv != SECSuccess) { |
968 | 0 | return SECFailure; |
969 | 0 | } |
970 | | |
971 | 79.9k | *added = PR_TRUE; |
972 | 79.9k | return SECSuccess; |
973 | 79.9k | } |
974 | | |
975 | | /* Send our "canned" (precompiled) Supported Point Formats extension, |
976 | | * which says that we only support uncompressed points. |
977 | | */ |
978 | | SECStatus |
979 | | ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData, |
980 | | sslBuffer *buf, PRBool *added) |
981 | 82.3k | { |
982 | 82.3k | SECStatus rv; |
983 | | |
984 | | /* No point in doing this unless we have a socket that supports ECC. |
985 | | * Similarly, no point if we are going to do TLS 1.3 only or we have already |
986 | | * picked TLS 1.3 (server) given that it doesn't use point formats. */ |
987 | 82.3k | if (!ss || !ssl_IsECCEnabled(ss) || |
988 | 82.3k | ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_3 || |
989 | 80.3k | (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)) { |
990 | 1.94k | return SECSuccess; |
991 | 1.94k | } |
992 | 80.3k | rv = sslBuffer_AppendNumber(buf, 1, 1); /* length */ |
993 | 80.3k | if (rv != SECSuccess) { |
994 | 0 | return SECFailure; |
995 | 0 | } |
996 | 80.3k | rv = sslBuffer_AppendNumber(buf, 0, 1); /* uncompressed type only */ |
997 | 80.3k | if (rv != SECSuccess) { |
998 | 0 | return SECFailure; |
999 | 0 | } |
1000 | | |
1001 | 80.3k | *added = PR_TRUE; |
1002 | 80.3k | return SECSuccess; |
1003 | 80.3k | } |