4
* ***** BEGIN LICENSE BLOCK *****
5
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
7
* The contents of this file are subject to the Mozilla Public License Version
8
* 1.1 (the "License"); you may not use this file except in compliance with
9
* the License. You may obtain a copy of the License at
10
* http://www.mozilla.org/MPL/
12
* Software distributed under the License is distributed on an "AS IS" basis,
13
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14
* for the specific language governing rights and limitations under the
17
* The Original Code is the Netscape security libraries.
19
* The Initial Developer of the Original Code is
20
* Netscape Communications Corporation.
21
* Portions created by the Initial Developer are Copyright (C) 1994-2000
22
* the Initial Developer. All Rights Reserved.
25
* Dr Vipul Gupta <vipul.gupta@sun.com> and
26
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
28
* Alternatively, the contents of this file may be used under the terms of
29
* either the GNU General Public License Version 2 or later (the "GPL"), or
30
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31
* in which case the provisions of the GPL or the LGPL are applicable instead
32
* of those above. If you wish to allow use of your version of this file only
33
* under the terms of either the GPL or the LGPL, and not to allow others to
34
* use your version of this file under the terms of the MPL, indicate your
35
* decision by deleting the provisions above and replace them with the notice
36
* and other provisions required by the GPL or the LGPL. If you do not delete
37
* the provisions above, a recipient may use your version of this file under
38
* the terms of any one of the MPL, the GPL or the LGPL.
40
* ***** END LICENSE BLOCK ***** */
42
/* ECC code moved here from ssl3con.c */
43
/* $Id: ssl3ecc.c,v 1.3.2.9 2006/08/05 01:54:03 julien.pierre.bugs%sun.com Exp $ */
49
#include "cryptohi.h" /* for DSAU_ stuff */
75
#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
76
(x)->pValue=(v); (x)->ulValueLen = (l);
79
#define SSL_GET_SERVER_PUBLIC_KEY(sock, type) \
80
(ss->serverCerts[type].serverKeyPair ? \
81
ss->serverCerts[type].serverKeyPair->pubKey : NULL)
83
#define SSL_IS_CURVE_NEGOTIATED(ss, curveName) \
84
((curveName > ec_noName) && \
85
(curveName < ec_pastLastName) && \
86
((1UL << curveName) & ss->ssl3.hs.negotiatedECCurves) != 0)
88
/* Types and names of elliptic curves used in TLS */
89
typedef enum { ec_type_explicitPrime = 1,
90
ec_type_explicitChar2Curve = 2,
94
typedef enum { ec_noName = 0,
123
static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve);
125
#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
127
/* Table containing OID tags for elliptic curves named in the
128
* ECC-TLS IETF draft.
130
static const SECOidTag ecName2OIDTag[] = {
132
SEC_OID_SECG_EC_SECT163K1, /* 1 */
133
SEC_OID_SECG_EC_SECT163R1, /* 2 */
134
SEC_OID_SECG_EC_SECT163R2, /* 3 */
135
SEC_OID_SECG_EC_SECT193R1, /* 4 */
136
SEC_OID_SECG_EC_SECT193R2, /* 5 */
137
SEC_OID_SECG_EC_SECT233K1, /* 6 */
138
SEC_OID_SECG_EC_SECT233R1, /* 7 */
139
SEC_OID_SECG_EC_SECT239K1, /* 8 */
140
SEC_OID_SECG_EC_SECT283K1, /* 9 */
141
SEC_OID_SECG_EC_SECT283R1, /* 10 */
142
SEC_OID_SECG_EC_SECT409K1, /* 11 */
143
SEC_OID_SECG_EC_SECT409R1, /* 12 */
144
SEC_OID_SECG_EC_SECT571K1, /* 13 */
145
SEC_OID_SECG_EC_SECT571R1, /* 14 */
146
SEC_OID_SECG_EC_SECP160K1, /* 15 */
147
SEC_OID_SECG_EC_SECP160R1, /* 16 */
148
SEC_OID_SECG_EC_SECP160R2, /* 17 */
149
SEC_OID_SECG_EC_SECP192K1, /* 18 */
150
SEC_OID_SECG_EC_SECP192R1, /* 19 */
151
SEC_OID_SECG_EC_SECP224K1, /* 20 */
152
SEC_OID_SECG_EC_SECP224R1, /* 21 */
153
SEC_OID_SECG_EC_SECP256K1, /* 22 */
154
SEC_OID_SECG_EC_SECP256R1, /* 23 */
155
SEC_OID_SECG_EC_SECP384R1, /* 24 */
156
SEC_OID_SECG_EC_SECP521R1, /* 25 */
159
static const PRUint16 curve2bits[] = {
160
0, /* ec_noName = 0, */
161
163, /* ec_sect163k1 = 1, */
162
163, /* ec_sect163r1 = 2, */
163
163, /* ec_sect163r2 = 3, */
164
193, /* ec_sect193r1 = 4, */
165
193, /* ec_sect193r2 = 5, */
166
233, /* ec_sect233k1 = 6, */
167
233, /* ec_sect233r1 = 7, */
168
239, /* ec_sect239k1 = 8, */
169
283, /* ec_sect283k1 = 9, */
170
283, /* ec_sect283r1 = 10, */
171
409, /* ec_sect409k1 = 11, */
172
409, /* ec_sect409r1 = 12, */
173
571, /* ec_sect571k1 = 13, */
174
571, /* ec_sect571r1 = 14, */
175
160, /* ec_secp160k1 = 15, */
176
160, /* ec_secp160r1 = 16, */
177
160, /* ec_secp160r2 = 17, */
178
192, /* ec_secp192k1 = 18, */
179
192, /* ec_secp192r1 = 19, */
180
224, /* ec_secp224k1 = 20, */
181
224, /* ec_secp224r1 = 21, */
182
256, /* ec_secp256k1 = 22, */
183
256, /* ec_secp256r1 = 23, */
184
384, /* ec_secp384r1 = 24, */
185
521, /* ec_secp521r1 = 25, */
186
65535 /* ec_pastLastName */
189
typedef struct Bits2CurveStr {
194
static const Bits2Curve bits2curve [] = {
195
{ 192, ec_secp192r1 /* = 19, fast */ },
196
{ 160, ec_secp160r2 /* = 17, fast */ },
197
{ 160, ec_secp160k1 /* = 15, */ },
198
{ 160, ec_secp160r1 /* = 16, */ },
199
{ 163, ec_sect163k1 /* = 1, */ },
200
{ 163, ec_sect163r1 /* = 2, */ },
201
{ 163, ec_sect163r2 /* = 3, */ },
202
{ 192, ec_secp192k1 /* = 18, */ },
203
{ 193, ec_sect193r1 /* = 4, */ },
204
{ 193, ec_sect193r2 /* = 5, */ },
205
{ 224, ec_secp224r1 /* = 21, fast */ },
206
{ 224, ec_secp224k1 /* = 20, */ },
207
{ 233, ec_sect233k1 /* = 6, */ },
208
{ 233, ec_sect233r1 /* = 7, */ },
209
{ 239, ec_sect239k1 /* = 8, */ },
210
{ 256, ec_secp256r1 /* = 23, fast */ },
211
{ 256, ec_secp256k1 /* = 22, */ },
212
{ 283, ec_sect283k1 /* = 9, */ },
213
{ 283, ec_sect283r1 /* = 10, */ },
214
{ 384, ec_secp384r1 /* = 24, fast */ },
215
{ 409, ec_sect409k1 /* = 11, */ },
216
{ 409, ec_sect409r1 /* = 12, */ },
217
{ 521, ec_secp521r1 /* = 25, fast */ },
218
{ 571, ec_sect571k1 /* = 13, */ },
219
{ 571, ec_sect571r1 /* = 14, */ },
223
typedef struct ECDHEKeyPairStr {
229
/* arrays of ECDHE KeyPairs */
230
static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName];
233
ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
235
SECOidData *oidData = NULL;
237
if ((curve <= ec_noName) || (curve >= ec_pastLastName) ||
238
((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) {
239
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
243
SECITEM_AllocItem(arena, params, (2 + oidData->oid.len));
245
* params->data needs to contain the ASN encoding of an object ID (OID)
246
* representing the named curve. The actual OID is in
247
* oidData->oid.data so we simply prepend 0x06 and OID length
249
params->data[0] = SEC_ASN1_OBJECT_ID;
250
params->data[1] = oidData->oid.len;
251
memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
257
params2ecName(SECKEYECParams * params)
259
SECItem oid = { siBuffer, NULL, 0};
260
SECOidData *oidData = NULL;
264
* params->data needs to contain the ASN encoding of an object ID (OID)
265
* representing a named curve. Here, we strip away everything
266
* before the actual OID and use the OID to look up a named curve.
268
if (params->data[0] != SEC_ASN1_OBJECT_ID) return ec_noName;
269
oid.len = params->len - 2;
270
oid.data = params->data + 2;
271
if ((oidData = SECOID_FindOID(&oid)) == NULL) return ec_noName;
272
for (i = ec_noName + 1; i < ec_pastLastName; i++) {
273
if (ecName2OIDTag[i] == oidData->offset)
280
/* Caller must set hiLevel error code. */
282
ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint,
283
SSL3Random *client_rand, SSL3Random *server_rand,
284
SSL3Hashes *hashes, PRBool bypassPKCS11)
288
SECStatus rv = SECSuccess;
291
* XXX For now, we only support named curves (the appropriate
292
* checks are made before this method is called) so ec_params
293
* takes up only two bytes. ECPoint needs to fit in 256 bytes
294
* (because the spec says the length must fit in one byte)
296
PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 1 + 256];
298
bufLen = 2*SSL3_RANDOM_LENGTH + ec_params.len + 1 + server_ecpoint.len;
299
if (bufLen <= sizeof buf) {
302
hashBuf = PORT_Alloc(bufLen);
308
memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH);
309
pBuf = hashBuf + SSL3_RANDOM_LENGTH;
310
memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH);
311
pBuf += SSL3_RANDOM_LENGTH;
312
memcpy(pBuf, ec_params.data, ec_params.len);
313
pBuf += ec_params.len;
314
pBuf[0] = (PRUint8)(server_ecpoint.len);
316
memcpy(pBuf, server_ecpoint.data, server_ecpoint.len);
317
pBuf += server_ecpoint.len;
318
PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
320
rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11);
322
PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen));
323
PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH));
324
PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH));
326
if (hashBuf != buf && hashBuf != NULL)
332
/* Called from ssl3_SendClientKeyExchange(). */
334
ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
336
PK11SymKey * pms = NULL;
337
SECStatus rv = SECFailure;
339
CK_MECHANISM_TYPE target;
340
SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */
341
SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */
343
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
344
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
346
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
348
/* Generate ephemeral EC keypair */
349
/* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */
350
privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams,
352
if (!privKey || !pubKey) {
353
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
357
PRINT_BUF(50, (ss, "ECDH public value:",
358
pubKey->u.ec.publicValue.data,
359
pubKey->u.ec.publicValue.len));
361
if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH;
362
else target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
364
/* Determine the PMS */
365
pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL,
366
CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
367
CKD_NULL, NULL, NULL);
370
SSL3AlertDescription desc = illegal_parameter;
371
(void)SSL3_SendAlert(ss, alert_fatal, desc);
372
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
376
SECKEY_DestroyPrivateKey(privKey);
379
rv = ssl3_InitPendingCipherSpec(ss, pms);
380
PK11_FreeSymKey(pms); pms = NULL;
382
if (rv != SECSuccess) {
383
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
387
rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
388
pubKey->u.ec.publicValue.len + 1);
389
if (rv != SECSuccess) {
390
goto loser; /* err set by ssl3_AppendHandshake* */
393
rv = ssl3_AppendHandshakeVariable(ss,
394
pubKey->u.ec.publicValue.data,
395
pubKey->u.ec.publicValue.len, 1);
396
SECKEY_DestroyPublicKey(pubKey);
399
if (rv != SECSuccess) {
400
goto loser; /* err set by ssl3_AppendHandshake* */
406
if(pms) PK11_FreeSymKey(pms);
407
if(privKey) SECKEY_DestroyPrivateKey(privKey);
408
if(pubKey) SECKEY_DestroyPublicKey(pubKey);
414
** Called from ssl3_HandleClientKeyExchange()
417
ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
419
SECKEYPublicKey *srvrPubKey,
420
SECKEYPrivateKey *srvrPrivKey)
424
SECKEYPublicKey clntPubKey;
425
CK_MECHANISM_TYPE target;
428
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
429
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
431
clntPubKey.keyType = ecKey;
432
clntPubKey.u.ec.DEREncodedParams.len =
433
srvrPubKey->u.ec.DEREncodedParams.len;
434
clntPubKey.u.ec.DEREncodedParams.data =
435
srvrPubKey->u.ec.DEREncodedParams.data;
437
rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue,
439
if (rv != SECSuccess) {
441
return SECFailure; /* XXX Who sets the error code?? */
444
isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
446
if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH;
447
else target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
449
/* Determine the PMS */
450
pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL,
451
CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
452
CKD_NULL, NULL, NULL);
456
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
460
rv = ssl3_InitPendingCipherSpec(ss, pms);
461
PK11_FreeSymKey(pms);
462
if (rv != SECSuccess) {
464
return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
469
/* find the "weakest link". Get strength of signature key and of sym key.
470
* choose curve for the weakest of those two.
473
ssl3_GetCurveNameForServerSocket(sslSocket *ss)
475
SECKEYPublicKey * svrPublicKey = NULL;
476
ECName ec_curve = ec_noName;
477
int signatureKeyStrength = 521;
478
int requiredECCbits = ss->sec.secretKeyBits * 2;
481
if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) {
482
svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh);
484
ec_curve = params2ecName(&svrPublicKey->u.ec.DEREncodedParams);
485
if (!SSL_IS_CURVE_NEGOTIATED(ss, ec_curve)) {
486
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
489
signatureKeyStrength = curve2bits[ ec_curve ];
491
/* RSA is our signing cert */
492
int serverKeyStrengthInBits;
494
svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa);
496
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
500
/* currently strength in bytes */
501
serverKeyStrengthInBits = svrPublicKey->u.rsa.modulus.len;
502
if (svrPublicKey->u.rsa.modulus.data[0] == 0) {
503
serverKeyStrengthInBits--;
505
/* convert to strength in bits */
506
serverKeyStrengthInBits *= BPB;
508
if (serverKeyStrengthInBits <= 1024) {
509
signatureKeyStrength = 160;
510
} else if (serverKeyStrengthInBits <= 2048) {
511
signatureKeyStrength = 224;
512
} else if (serverKeyStrengthInBits <= 3072) {
513
signatureKeyStrength = 256;
514
} else if (serverKeyStrengthInBits <= 7168) {
515
signatureKeyStrength = 384;
517
signatureKeyStrength = 521;
520
if ( requiredECCbits > signatureKeyStrength )
521
requiredECCbits = signatureKeyStrength;
523
for ( i = 0; bits2curve[i].curve != ec_noName; i++) {
524
if (bits2curve[i].bits < requiredECCbits)
526
if (SSL_IS_CURVE_NEGOTIATED(ss, bits2curve[i].curve)) {
527
return bits2curve[i].curve;
530
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
534
/* function to clear out the lists */
536
ssl3_ShutdownECDHECurves(void *appData, void *nssData)
539
ECDHEKeyPair *keyPair = &gECDHEKeyPairs[0];
541
for (i=0; i < ec_pastLastName; i++, keyPair++) {
543
ssl3_FreeKeyPair(keyPair->pair);
546
memset(gECDHEKeyPairs, 0, sizeof gECDHEKeyPairs);
551
ssl3_ECRegister(void)
554
rv = NSS_RegisterShutdown(ssl3_ShutdownECDHECurves, gECDHEKeyPairs);
558
/* CallOnce function, called once for each named curve. */
560
ssl3_CreateECDHEphemeralKeyPair(void * arg)
562
SECKEYPrivateKey * privKey = NULL;
563
SECKEYPublicKey * pubKey = NULL;
564
ssl3KeyPair * keyPair = NULL;
565
ECName ec_curve = (ECName)arg;
566
SECKEYECParams ecParams = { siBuffer, NULL, 0 };
568
PORT_Assert(gECDHEKeyPairs[ec_curve].pair == NULL);
570
/* ok, no one has generated a global key for this curve yet, do so */
571
if (ecName2params(NULL, ec_curve, &ecParams) != SECSuccess) {
575
privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL);
576
SECITEM_FreeItem(&ecParams, PR_FALSE);
578
if (!privKey || !pubKey || !(keyPair = ssl3_NewKeyPair(privKey, pubKey))) {
580
SECKEY_DestroyPrivateKey(privKey);
583
SECKEY_DestroyPublicKey(pubKey);
585
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
589
gECDHEKeyPairs[ec_curve].pair = keyPair;
594
* Creates the ephemeral public and private ECDH keys used by
595
* server in ECDHE_RSA and ECDHE_ECDSA handshakes.
596
* For now, the elliptic curve is chosen to be the same
597
* strength as the signing certificate (ECC or RSA).
598
* We need an API to specify the curve. This won't be a real
599
* issue until we further develop server-side support for ECC
603
ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve)
605
ssl3KeyPair * keyPair = NULL;
607
/* if there's no global key for this curve, make one. */
608
if (gECDHEKeyPairs[ec_curve].pair == NULL) {
611
status = PR_CallOnce(&gECDHEKeyPairs[ec_noName].once, ssl3_ECRegister);
612
if (status != PR_SUCCESS) {
615
status = PR_CallOnceWithArg(&gECDHEKeyPairs[ec_curve].once,
616
ssl3_CreateECDHEphemeralKeyPair,
618
if (status != PR_SUCCESS) {
623
keyPair = gECDHEKeyPairs[ec_curve].pair;
624
PORT_Assert(keyPair != NULL);
627
ss->ephemeralECDHKeyPair = ssl3_GetKeyPairRef(keyPair);
633
ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
635
PRArenaPool * arena = NULL;
636
SECKEYPublicKey *peerKey = NULL;
639
int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
640
SSL3AlertDescription desc = illegal_parameter;
642
SECItem signature = {siBuffer, NULL, 0};
644
SECItem ec_params = {siBuffer, NULL, 0};
645
SECItem ec_point = {siBuffer, NULL, 0};
646
unsigned char paramBuf[3]; /* only for curve_type == named_curve */
648
isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
650
/* XXX This works only for named curves, revisit this when
651
* we support generic curves.
653
ec_params.len = sizeof paramBuf;
654
ec_params.data = paramBuf;
655
rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length);
656
if (rv != SECSuccess) {
657
goto loser; /* malformed. */
660
/* Fail if the curve is not a named curve */
661
if ((ec_params.data[0] != ec_type_named) ||
662
(ec_params.data[1] != 0) ||
663
!supportedCurve(ec_params.data[2])) {
664
errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
665
desc = handshake_failure;
669
rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length);
670
if (rv != SECSuccess) {
671
goto loser; /* malformed. */
673
/* Fail if the ec point uses compressed representation */
674
if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
675
errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM;
676
desc = handshake_failure;
680
rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
681
if (rv != SECSuccess) {
682
goto loser; /* malformed. */
688
goto alert_loser; /* malformed. */
691
PRINT_BUF(60, (NULL, "Server EC params", ec_params.data,
693
PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len));
695
/* failures after this point are not malformed handshakes. */
696
/* TLS: send decrypt_error if signature failed. */
697
desc = isTLS ? decrypt_error : handshake_failure;
700
* check to make sure the hash is signed by right guy
702
rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point,
703
&ss->ssl3.hs.client_random,
704
&ss->ssl3.hs.server_random,
705
&hashes, ss->opt.bypassPKCS11);
707
if (rv != SECSuccess) {
709
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
712
rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
713
isTLS, ss->pkcs11PinArg);
714
if (rv != SECSuccess) {
716
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
720
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
725
ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
726
if (peerKey == NULL) {
730
peerKey->arena = arena;
731
peerKey->keyType = ecKey;
733
/* set up EC parameters in peerKey */
734
if (ecName2params(arena, ec_params.data[2],
735
&peerKey->u.ec.DEREncodedParams) != SECSuccess) {
736
/* we should never get here since we already
737
* checked that we are dealing with a supported curve
739
errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
743
/* copy publicValue in peerKey */
744
if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point))
746
PORT_FreeArena(arena, PR_FALSE);
749
peerKey->pkcs11Slot = NULL;
750
peerKey->pkcs11ID = CK_INVALID_HANDLE;
752
ss->sec.peerKey = peerKey;
753
ss->ssl3.hs.ws = wait_cert_request;
758
(void)SSL3_SendAlert(ss, alert_fatal, desc);
760
PORT_SetError( errCode );
763
no_memory: /* no-memory error has already been set. */
764
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
769
ssl3_SendECDHServerKeyExchange(sslSocket *ss)
771
const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
772
SECStatus rv = SECFailure;
775
SECItem signed_hash = {siBuffer, NULL, 0};
778
SECKEYPublicKey * ecdhePub;
779
SECItem ec_params = {siBuffer, NULL, 0};
780
unsigned char paramBuf[3];
782
SSL3KEAType certIndex;
785
/* Generate ephemeral ECDH key pair and send the public key */
786
curve = ssl3_GetCurveNameForServerSocket(ss);
787
if (curve == ec_noName) {
790
rv = ssl3_CreateECDHEphemeralKeys(ss, curve);
791
if (rv != SECSuccess) {
792
goto loser; /* err set by AppendHandshake. */
794
ecdhePub = ss->ephemeralECDHKeyPair->pubKey;
795
PORT_Assert(ecdhePub != NULL);
797
PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
801
ec_params.len = sizeof paramBuf;
802
ec_params.data = paramBuf;
803
curve = params2ecName(&ecdhePub->u.ec.DEREncodedParams);
804
if (curve != ec_noName) {
805
ec_params.data[0] = ec_type_named;
806
ec_params.data[1] = 0x00;
807
ec_params.data[2] = curve;
809
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
813
rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue,
814
&ss->ssl3.hs.client_random,
815
&ss->ssl3.hs.server_random,
816
&hashes, ss->opt.bypassPKCS11);
817
if (rv != SECSuccess) {
818
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
822
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
824
/* XXX SSLKEAType isn't really a good choice for
825
* indexing certificates but that's all we have
828
if (kea_def->kea == kea_ecdhe_rsa)
830
else /* kea_def->kea == kea_ecdhe_ecdsa */
833
rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY,
834
&signed_hash, isTLS);
835
if (rv != SECSuccess) {
836
goto loser; /* ssl3_SignHashes has set err. */
838
if (signed_hash.data == NULL) {
839
/* how can this happen and rv == SECSuccess ?? */
840
PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
844
length = ec_params.len +
845
1 + ecdhePub->u.ec.publicValue.len +
848
rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
849
if (rv != SECSuccess) {
850
goto loser; /* err set by AppendHandshake. */
853
rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len);
854
if (rv != SECSuccess) {
855
goto loser; /* err set by AppendHandshake. */
858
rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data,
859
ecdhePub->u.ec.publicValue.len, 1);
860
if (rv != SECSuccess) {
861
goto loser; /* err set by AppendHandshake. */
864
rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data,
866
if (rv != SECSuccess) {
867
goto loser; /* err set by AppendHandshake. */
870
PORT_Free(signed_hash.data);
874
if (signed_hash.data != NULL)
875
PORT_Free(signed_hash.data);
879
/* Lists of ECC cipher suites for searching and disabling. */
881
static const ssl3CipherSuite ecdh_suites[] = {
882
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
883
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
884
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
885
TLS_ECDH_ECDSA_WITH_NULL_SHA,
886
TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
887
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
888
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
889
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
890
TLS_ECDH_RSA_WITH_NULL_SHA,
891
TLS_ECDH_RSA_WITH_RC4_128_SHA,
892
0 /* end of list marker */
895
static const ssl3CipherSuite ecdh_ecdsa_suites[] = {
896
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
897
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
898
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
899
TLS_ECDH_ECDSA_WITH_NULL_SHA,
900
TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
901
0 /* end of list marker */
904
static const ssl3CipherSuite ecdh_rsa_suites[] = {
905
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
906
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
907
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
908
TLS_ECDH_RSA_WITH_NULL_SHA,
909
TLS_ECDH_RSA_WITH_RC4_128_SHA,
910
0 /* end of list marker */
913
static const ssl3CipherSuite ecdhe_ecdsa_suites[] = {
914
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
915
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
916
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
917
TLS_ECDHE_ECDSA_WITH_NULL_SHA,
918
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
919
0 /* end of list marker */
922
static const ssl3CipherSuite ecdhe_rsa_suites[] = {
923
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
924
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
925
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
926
TLS_ECDHE_RSA_WITH_NULL_SHA,
927
TLS_ECDHE_RSA_WITH_RC4_128_SHA,
928
0 /* end of list marker */
931
/* List of all ECC cipher suites */
932
static const ssl3CipherSuite ecSuites[] = {
933
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
934
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
935
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
936
TLS_ECDHE_ECDSA_WITH_NULL_SHA,
937
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
938
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
939
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
940
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
941
TLS_ECDHE_RSA_WITH_NULL_SHA,
942
TLS_ECDHE_RSA_WITH_RC4_128_SHA,
943
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
944
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
945
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
946
TLS_ECDH_ECDSA_WITH_NULL_SHA,
947
TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
948
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
949
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
950
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
951
TLS_ECDH_RSA_WITH_NULL_SHA,
952
TLS_ECDH_RSA_WITH_RC4_128_SHA,
953
0 /* end of list marker */
956
/* On this socket, Disable the ECC cipher suites in the argument's list */
958
ssl3_DisableECCSuites(sslSocket * ss, const ssl3CipherSuite * suite)
962
for (; *suite; ++suite) {
963
SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE);
965
PORT_Assert(rv == SECSuccess); /* else is coding error */
970
/* Look at the server certs configured on this socket, and disable any
971
* ECC cipher suites that are not supported by those certs.
974
ssl3_FilterECCipherSuitesByServerCerts(sslSocket * ss)
976
CERTCertificate * svrCert;
978
svrCert = ss->serverCerts[kt_rsa].serverCert;
980
ssl3_DisableECCSuites(ss, ecdhe_rsa_suites);
983
svrCert = ss->serverCerts[kt_ecdh].serverCert;
985
ssl3_DisableECCSuites(ss, ecdh_suites);
986
ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
988
SECOidTag sigTag = SECOID_GetAlgorithmTag(&svrCert->signature);
991
case SEC_OID_PKCS1_RSA_ENCRYPTION:
992
case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
993
case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
994
case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
995
case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
996
case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
997
case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
998
case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
999
ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
1001
case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
1002
case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
1003
case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
1004
case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
1005
case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
1006
case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
1007
case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
1008
ssl3_DisableECCSuites(ss, ecdh_rsa_suites);
1011
ssl3_DisableECCSuites(ss, ecdh_suites);
1017
/* Ask: is ANY ECC cipher suite enabled on this socket? */
1018
/* Order(N^2). Yuk. Also, this ignores export policy. */
1020
ssl3_IsECCEnabled(sslSocket * ss)
1022
const ssl3CipherSuite * suite;
1024
for (suite = ecSuites; *suite; ++suite) {
1025
PRBool enabled = PR_FALSE;
1026
SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled);
1028
PORT_Assert(rv == SECSuccess); /* else is coding error */
1029
if (rv == SECSuccess && enabled)
1037
#ifndef NSS_ECC_MORE_THAN_SUITE_B
1038
/* Prefabricated TLS client hello extension, Elliptic Curves List,
1039
* offers only 3 curves, the Suite B curves, 23-25
1041
static const PRUint8 EClist[12] = {
1042
BE(10), /* Extension type */
1043
BE( 8), /* octets that follow ( 3 pairs + 1 length pair) */
1044
BE( 6), /* octets that follow ( 3 pairs) */
1045
BE(23), BE(24), BE(25)
1048
/* Prefabricated TLS client hello extension, Elliptic Curves List,
1049
* offers curves 1-25.
1051
static const PRUint8 EClist[56] = {
1052
BE(10), /* Extension type */
1053
BE(52), /* octets that follow (25 pairs + 1 length pair) */
1054
BE(50), /* octets that follow (25 pairs) */
1055
BE( 1), BE( 2), BE( 3), BE( 4), BE( 5), BE( 6), BE( 7),
1056
BE( 8), BE( 9), BE(10), BE(11), BE(12), BE(13), BE(14), BE(15),
1057
BE(16), BE(17), BE(18), BE(19), BE(20), BE(21), BE(22), BE(23),
1062
static const PRUint8 ECPtFmt[6] = {
1063
BE(11), /* Extension type */
1064
BE( 2), /* octets that follow */
1065
1, /* octets that follow */
1066
0 /* uncompressed type only */
1069
/* Send our "canned" (precompiled) Supported Elliptic Curves extension,
1070
* which says that we support all TLS-defined named curves.
1073
ssl3_SendSupportedEllipticCurvesExtension(
1078
if (!ss || !ssl3_IsECCEnabled(ss))
1080
if (append && maxBytes >= (sizeof EClist)) {
1081
SECStatus rv = ssl3_AppendHandshake(ss, EClist, (sizeof EClist));
1083
return (sizeof EClist);
1086
/* Send our "canned" (precompiled) Supported Point Formats extension,
1087
* which says that we only support uncompressed points.
1090
ssl3_SendSupportedPointFormatsExtension(
1095
if (!ss || !ssl3_IsECCEnabled(ss))
1097
if (append && maxBytes >= (sizeof ECPtFmt)) {
1098
SECStatus rv = ssl3_AppendHandshake(ss, ECPtFmt, (sizeof ECPtFmt));
1100
return (sizeof ECPtFmt);
1103
/* Just make sure that the remote client supports uncompressed points,
1104
* Since that is all we support. Disable ECC cipher suites if it doesn't.
1107
ssl3_HandleSupportedPointFormatsExtension(sslSocket * ss, PRUint16 ex_type,
1112
if (data->len < 2 || data->len > 255 || !data->data ||
1113
data->len != (unsigned int)data->data[0] + 1) {
1117
for (i = data->len; --i > 0; ) {
1118
if (data->data[i] == 0) {
1119
/* indicate that we should send a reply */
1121
rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
1122
&ssl3_SendSupportedPointFormatsExtension);
1127
/* evil client doesn't support uncompressed */
1128
ssl3_DisableECCSuites(ss, ecSuites);
1133
#define SSL3_GET_SERVER_PUBLICKEY(sock, type) \
1134
(ss->serverCerts[type].serverKeyPair ? \
1135
ss->serverCerts[type].serverKeyPair->pubKey : NULL)
1137
/* Extract the TLS curve name for the public key in our EC server cert. */
1138
ECName ssl3_GetSvrCertCurveName(sslSocket *ss)
1140
SECKEYPublicKey *srvPublicKey;
1141
ECName ec_curve = ec_noName;
1143
srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh);
1145
ec_curve = params2ecName(&srvPublicKey->u.ec.DEREncodedParams);
1150
/* Ensure that the curve in our server cert is one of the ones suppored
1151
* by the remote client, and disable all ECC cipher suites if not.
1154
ssl3_HandleSupportedEllipticCurvesExtension(sslSocket * ss, PRUint16 ex_type,
1158
PRUint32 peerCurves = 0;
1159
PRUint32 mutualCurves = 0;
1160
PRUint16 svrCertCurveName;
1162
if (!data->data || data->len < 4 || data->len > 65535)
1164
/* get the length of elliptic_curve_list */
1165
list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
1166
if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
1170
/* build bit vector of peer's supported curve names */
1172
PRInt32 curve_name =
1173
ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
1174
if (curve_name > ec_noName && curve_name < ec_pastLastName) {
1175
peerCurves |= (1U << curve_name);
1178
/* What curves do we support in common? */
1179
mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves;
1180
if (!mutualCurves) { /* no mutually supported EC Curves */
1184
/* if our ECC cert doesn't use one of these supported curves,
1185
* disable ECC cipher suites that require an ECC cert.
1187
svrCertCurveName = ssl3_GetSvrCertCurveName(ss);
1188
if (svrCertCurveName != ec_noName &&
1189
(mutualCurves & (1U << svrCertCurveName)) != 0) {
1192
/* Our EC cert doesn't contain a mutually supported curve.
1193
* Disable all ECC cipher suites that require an EC cert
1195
ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
1196
ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
1200
/* no common curve supported */
1201
ssl3_DisableECCSuites(ss, ecSuites);
1205
#endif /* NSS_ENABLE_ECC */
1207
/* Format an SNI extension, using the name from the socket's URL,
1208
* unless that name is a dotted decimal string.
1211
ssl3_SendServerNameIndicationExtension(
1217
/* must have a hostname */
1218
if (!ss || !ss->url || !ss->url[0])
1220
/* must have at lest one character other than [0-9\.] */
1221
len = PORT_Strlen(ss->url);
1222
span = strspn(ss->url, "0123456789.");
1224
/* is a dotted decimal IP address */
1227
if (append && maxBytes >= len + 9) {
1229
/* extension_type */
1230
rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
1231
if (rv != SECSuccess) return 0;
1232
/* length of extension_data */
1233
rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2);
1234
if (rv != SECSuccess) return 0;
1235
/* length of server_name_list */
1236
rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2);
1237
if (rv != SECSuccess) return 0;
1238
/* Name Type (host_name) */
1239
rv = ssl3_AppendHandshake(ss, "\0", 1);
1240
if (rv != SECSuccess) return 0;
1241
/* HostName (length and value) */
1242
rv = ssl3_AppendHandshakeVariable(ss, ss->url, len, 2);
1243
if (rv != SECSuccess) return 0;
1248
/* handle an incoming SNI extension, by ignoring it. */
1250
ssl3_HandleServerNameIndicationExtension(sslSocket * ss, PRUint16 ex_type,
1253
/* For now, we ignore this, as if we didn't understand it. :-) */
1257
/* Table of handlers for received TLS hello extensions, one per extension.
1258
* In the second generation, this table will be dynamic, and functions
1259
* will be registered here.
1261
static const ssl3HelloExtensionHandler handlers[] = {
1262
{ 0, &ssl3_HandleServerNameIndicationExtension },
1263
#ifdef NSS_ENABLE_ECC
1264
{ 10, &ssl3_HandleSupportedEllipticCurvesExtension },
1265
{ 11, &ssl3_HandleSupportedPointFormatsExtension },
1270
/* Table of functions to format TLS hello extensions, one per extension.
1271
* This static table is for the formatting of client hello extensions.
1272
* The server's table of hello senders is dynamic, in the socket struct,
1273
* and sender functions are registered there.
1276
ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSION_SENDERS] = {
1277
{ 0, &ssl3_SendServerNameIndicationExtension },
1278
#ifdef NSS_ENABLE_ECC
1279
{ 10, &ssl3_SendSupportedEllipticCurvesExtension },
1280
{ 11, &ssl3_SendSupportedPointFormatsExtension },
1286
/* go through hello extensions in buffer "b".
1287
* For each one, find the extension handler in the table above, and
1288
* if present, invoke that handler.
1289
* ignore any extensions with unknown extension types.
1292
ssl3_HandleClientHelloExtensions(sslSocket *ss,
1297
const ssl3HelloExtensionHandler * handler;
1299
PRInt32 extension_type;
1300
SECItem extension_data;
1302
/* Get the extension's type field */
1303
extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
1304
if (extension_type < 0) /* failure to decode extension_type */
1305
return SECFailure; /* alert already sent */
1307
/* get the data for this extension, so we can pass it or skip it. */
1308
rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length);
1309
if (rv != SECSuccess)
1312
/* find extension_type in table of Client Hello Extension Handlers */
1313
for (handler = handlers; handler->ex_type >= 0; handler++) {
1314
if (handler->ex_type == extension_type)
1318
/* if found, Call this handler */
1319
if (handler->ex_type == extension_type) {
1320
rv = (*handler->ex_handler)(ss, (PRUint16)extension_type,
1322
/* Ignore this result */
1323
/* Essentially, treat all bad extensions as unrecognized types. */
1329
/* Add a callback function to the table of senders of server hello extensions.
1332
ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type,
1333
ssl3HelloExtensionSenderFunc cb)
1336
ssl3HelloExtensionSender *sender = &ss->serverExtensionSenders[0];
1338
for (i = 0; i < MAX_EXTENSION_SENDERS; ++i, ++sender) {
1339
if (!sender->ex_sender) {
1340
sender->ex_type = ex_type;
1341
sender->ex_sender = cb;
1344
/* detect duplicate senders */
1345
PORT_Assert(sender->ex_type != ex_type);
1346
if (sender->ex_type == ex_type) {
1351
PORT_Assert(i < MAX_EXTENSION_SENDERS); /* table needs to grow */
1352
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1356
/* call each of the extension senders and return the accumulated length */
1358
ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
1359
const ssl3HelloExtensionSender *sender)
1361
PRInt32 total_exten_len = 0;
1365
sender = &clientHelloSenders[0];
1367
for (i = 0; i < MAX_EXTENSION_SENDERS; ++i, ++sender) {
1368
if (sender->ex_sender) {
1369
PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes);
1373
total_exten_len += extLen;
1376
return total_exten_len;