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