1 /*
2 * Key Derivation that doesn't use PKCS11
3 *
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
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/
11 *
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
15 * License.
16 *
17 * The Original Code is the Netscape security libraries.
18 *
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2005
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39 /* $Id: derive.c,v 1.12 2008/06/06 01:16:31 wtc%google.com Exp $ */
40
41 #include "ssl.h" /* prereq to sslimpl.h */
42 #include "certt.h" /* prereq to sslimpl.h */
43 #include "keythi.h" /* prereq to sslimpl.h */
44 #include "sslimpl.h"
45 #include "blapi.h"
46
47 #include "keyhi.h"
48 #include "pk11func.h"
49 #include "secasn1.h"
50 #include "cert.h"
51 #include "secmodt.h"
52
53 #include "sslproto.h"
54 #include "sslerr.h"
55
56 /* make this a macro! */
57 #ifdef NOT_A_MACRO
58 static void
buildSSLKey(unsigned char * keyBlock,unsigned int keyLen,SECItem * result,const char * label)59 buildSSLKey(unsigned char * keyBlock, unsigned int keyLen, SECItem * result,
60 const char * label)
61 {
62 result->type = siBuffer;
63 result->data = keyBlock;
64 result->len = keyLen;
65 PRINT_BUF(100, (NULL, label, keyBlock, keyLen));
66 }
67 #else
68 #define buildSSLKey(keyBlock, keyLen, result, label) \
69 { \
70 (result)->type = siBuffer; \
71 (result)->data = keyBlock; \
72 (result)->len = keyLen; \
73 PRINT_BUF(100, (NULL, label, keyBlock, keyLen)); \
74 }
75 #endif
76
77 /*
78 * SSL Key generation given pre master secret
79 */
80 #ifndef NUM_MIXERS
81 #define NUM_MIXERS 9
82 #endif
83 static const char * const mixers[NUM_MIXERS] = {
84 "A",
85 "BB",
86 "CCC",
87 "DDDD",
88 "EEEEE",
89 "FFFFFF",
90 "GGGGGGG",
91 "HHHHHHHH",
92 "IIIIIIIII"
93 };
94
95
96 SECStatus
ssl3_KeyAndMacDeriveBypass(ssl3CipherSpec * pwSpec,const unsigned char * cr,const unsigned char * sr,PRBool isTLS,PRBool isExport)97 ssl3_KeyAndMacDeriveBypass(
98 ssl3CipherSpec * pwSpec,
99 const unsigned char * cr,
100 const unsigned char * sr,
101 PRBool isTLS,
102 PRBool isExport)
103 {
104 const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
105 unsigned char * key_block = pwSpec->key_block;
106 unsigned char * key_block2 = NULL;
107 unsigned int block_bytes = 0;
108 unsigned int block_needed = 0;
109 unsigned int i;
110 unsigned int keySize; /* actual size of cipher keys */
111 unsigned int effKeySize; /* effective size of cipher keys */
112 unsigned int macSize; /* size of MAC secret */
113 unsigned int IVSize; /* size of IV */
114 SECStatus rv = SECFailure;
115 SECStatus status = SECSuccess;
116 PRBool isFIPS = PR_FALSE;
117
118 SECItem srcr;
119 SECItem crsr;
120
121 unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2];
122 unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
123 PRUint64 md5buf[22];
124 PRUint64 shabuf[40];
125
126 #define md5Ctx ((MD5Context *)md5buf)
127 #define shaCtx ((SHA1Context *)shabuf)
128
129 static const SECItem zed = { siBuffer, NULL, 0 };
130
131 if (pwSpec->msItem.data == NULL ||
132 pwSpec->msItem.len != SSL3_MASTER_SECRET_LENGTH) {
133 PORT_SetError(SEC_ERROR_INVALID_ARGS);
134 return rv;
135 }
136
137 PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data,
138 pwSpec->msItem.len));
139
140 /* figure out how much is needed */
141 macSize = pwSpec->mac_size;
142 keySize = cipher_def->key_size;
143 effKeySize = cipher_def->secret_key_size;
144 IVSize = cipher_def->iv_size;
145 if (keySize == 0) {
146 effKeySize = IVSize = 0; /* only MACing */
147 }
148 block_needed = 2 * (macSize + effKeySize + ((!isExport) * IVSize));
149
150 /*
151 * clear out our returned keys so we can recover on failure
152 */
153 pwSpec->client.write_key_item = zed;
154 pwSpec->client.write_mac_key_item = zed;
155 pwSpec->server.write_key_item = zed;
156 pwSpec->server.write_mac_key_item = zed;
157
158 /* initialize the server random, client random block */
159 srcr.type = siBuffer;
160 srcr.data = srcrdata;
161 srcr.len = sizeof srcrdata;
162 PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH);
163 PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH);
164
165 /* initialize the client random, server random block */
166 crsr.type = siBuffer;
167 crsr.data = crsrdata;
168 crsr.len = sizeof crsrdata;
169 PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
170 PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
171 PRINT_BUF(100, (NULL, "Key & MAC CRSR", crsr.data, crsr.len));
172
173 /*
174 * generate the key material:
175 */
176 if (isTLS) {
177 SECItem keyblk;
178
179 keyblk.type = siBuffer;
180 keyblk.data = key_block;
181 keyblk.len = block_needed;
182
183 status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk,
184 isFIPS);
185 if (status != SECSuccess) {
186 goto key_and_mac_derive_fail;
187 }
188 block_bytes = keyblk.len;
189 } else {
190 /* key_block =
191 * MD5(master_secret + SHA('A' + master_secret +
192 * ServerHello.random + ClientHello.random)) +
193 * MD5(master_secret + SHA('BB' + master_secret +
194 * ServerHello.random + ClientHello.random)) +
195 * MD5(master_secret + SHA('CCC' + master_secret +
196 * ServerHello.random + ClientHello.random)) +
197 * [...];
198 */
199 unsigned int made = 0;
200 for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) {
201 unsigned int outLen;
202 unsigned char sha_out[SHA1_LENGTH];
203
204 SHA1_Begin(shaCtx);
205 SHA1_Update(shaCtx, (unsigned char*)(mixers[i]), i+1);
206 SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len);
207 SHA1_Update(shaCtx, srcr.data, srcr.len);
208 SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
209 PORT_Assert(outLen == SHA1_LENGTH);
210
211 MD5_Begin(md5Ctx);
212 MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len);
213 MD5_Update(md5Ctx, sha_out, outLen);
214 MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
215 PORT_Assert(outLen == MD5_LENGTH);
216 made += MD5_LENGTH;
217 }
218 block_bytes = made;
219 }
220 PORT_Assert(block_bytes >= block_needed);
221 PORT_Assert(block_bytes <= sizeof pwSpec->key_block);
222 PRINT_BUF(100, (NULL, "key block", key_block, block_bytes));
223
224 /*
225 * Put the key material where it goes.
226 */
227 key_block2 = key_block + block_bytes;
228 i = 0; /* now shows how much consumed */
229
230 /*
231 * The key_block is partitioned as follows:
232 * client_write_MAC_secret[CipherSpec.hash_size]
233 */
234 buildSSLKey(&key_block[i],macSize, &pwSpec->client.write_mac_key_item, \
235 "Client Write MAC Secret");
236 i += macSize;
237
238 /*
239 * server_write_MAC_secret[CipherSpec.hash_size]
240 */
241 buildSSLKey(&key_block[i],macSize, &pwSpec->server.write_mac_key_item, \
242 "Server Write MAC Secret");
243 i += macSize;
244
245 if (!keySize) {
246 /* only MACing */
247 buildSSLKey(NULL, 0, &pwSpec->client.write_key_item, \
248 "Client Write Key (MAC only)");
249 buildSSLKey(NULL, 0, &pwSpec->server.write_key_item, \
250 "Server Write Key (MAC only)");
251 buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item, \
252 "Client Write IV (MAC only)");
253 buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item, \
254 "Server Write IV (MAC only)");
255 } else if (!isExport) {
256 /*
257 ** Generate Domestic write keys and IVs.
258 ** client_write_key[CipherSpec.key_material]
259 */
260 buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item, \
261 "Domestic Client Write Key");
262 i += keySize;
263
264 /*
265 ** server_write_key[CipherSpec.key_material]
266 */
267 buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item, \
268 "Domestic Server Write Key");
269 i += keySize;
270
271 if (IVSize > 0) {
272 /*
273 ** client_write_IV[CipherSpec.IV_size]
274 */
275 buildSSLKey(&key_block[i], IVSize, &pwSpec->client.write_iv_item, \
276 "Domestic Client Write IV");
277 i += IVSize;
278
279 /*
280 ** server_write_IV[CipherSpec.IV_size]
281 */
282 buildSSLKey(&key_block[i], IVSize, &pwSpec->server.write_iv_item, \
283 "Domestic Server Write IV");
284 i += IVSize;
285 }
286 PORT_Assert(i <= block_bytes);
287
288 } else if (!isTLS) {
289 /*
290 ** Generate SSL3 Export write keys and IVs.
291 */
292 unsigned int outLen;
293
294 /*
295 ** client_write_key[CipherSpec.key_material]
296 ** final_client_write_key = MD5(client_write_key +
297 ** ClientHello.random + ServerHello.random);
298 */
299 MD5_Begin(md5Ctx);
300 MD5_Update(md5Ctx, &key_block[i], effKeySize);
301 MD5_Update(md5Ctx, crsr.data, crsr.len);
302 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
303 i += effKeySize;
304 buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \
305 "SSL3 Export Client Write Key");
306 key_block2 += keySize;
307
308 /*
309 ** server_write_key[CipherSpec.key_material]
310 ** final_server_write_key = MD5(server_write_key +
311 ** ServerHello.random + ClientHello.random);
312 */
313 MD5_Begin(md5Ctx);
314 MD5_Update(md5Ctx, &key_block[i], effKeySize);
315 MD5_Update(md5Ctx, srcr.data, srcr.len);
316 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
317 i += effKeySize;
318 buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \
319 "SSL3 Export Server Write Key");
320 key_block2 += keySize;
321 PORT_Assert(i <= block_bytes);
322
323 if (IVSize) {
324 /*
325 ** client_write_IV =
326 ** MD5(ClientHello.random + ServerHello.random);
327 */
328 MD5_Begin(md5Ctx);
329 MD5_Update(md5Ctx, crsr.data, crsr.len);
330 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
331 buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item, \
332 "SSL3 Export Client Write IV");
333 key_block2 += IVSize;
334
335 /*
336 ** server_write_IV =
337 ** MD5(ServerHello.random + ClientHello.random);
338 */
339 MD5_Begin(md5Ctx);
340 MD5_Update(md5Ctx, srcr.data, srcr.len);
341 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
342 buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item, \
343 "SSL3 Export Server Write IV");
344 key_block2 += IVSize;
345 }
346
347 PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
348 } else {
349 /*
350 ** Generate TLS Export write keys and IVs.
351 */
352 SECItem secret ;
353 SECItem keyblk ;
354
355 secret.type = siBuffer;
356 keyblk.type = siBuffer;
357 /*
358 ** client_write_key[CipherSpec.key_material]
359 ** final_client_write_key = PRF(client_write_key,
360 ** "client write key",
361 ** client_random + server_random);
362 */
363 secret.data = &key_block[i];
364 secret.len = effKeySize;
365 i += effKeySize;
366 keyblk.data = key_block2;
367 keyblk.len = keySize;
368 status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS);
369 if (status != SECSuccess) {
370 goto key_and_mac_derive_fail;
371 }
372 buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \
373 "TLS Export Client Write Key");
374 key_block2 += keySize;
375
376 /*
377 ** server_write_key[CipherSpec.key_material]
378 ** final_server_write_key = PRF(server_write_key,
379 ** "server write key",
380 ** client_random + server_random);
381 */
382 secret.data = &key_block[i];
383 secret.len = effKeySize;
384 i += effKeySize;
385 keyblk.data = key_block2;
386 keyblk.len = keySize;
387 status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS);
388 if (status != SECSuccess) {
389 goto key_and_mac_derive_fail;
390 }
391 buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \
392 "TLS Export Server Write Key");
393 key_block2 += keySize;
394
395 /*
396 ** iv_block = PRF("", "IV block", client_random + server_random);
397 ** client_write_IV[SecurityParameters.IV_size]
398 ** server_write_IV[SecurityParameters.IV_size]
399 */
400 if (IVSize) {
401 secret.data = NULL;
402 secret.len = 0;
403 keyblk.data = key_block2;
404 keyblk.len = 2 * IVSize;
405 status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS);
406 if (status != SECSuccess) {
407 goto key_and_mac_derive_fail;
408 }
409 buildSSLKey(key_block2, IVSize, \
410 &pwSpec->client.write_iv_item, \
411 "TLS Export Client Write IV");
412 buildSSLKey(key_block2 + IVSize, IVSize, \
413 &pwSpec->server.write_iv_item, \
414 "TLS Export Server Write IV");
415 key_block2 += 2 * IVSize;
416 }
417 PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
418 }
419 rv = SECSuccess;
420
421 key_and_mac_derive_fail:
422
423 MD5_DestroyContext(md5Ctx, PR_FALSE);
424 SHA1_DestroyContext(shaCtx, PR_FALSE);
425
426 if (rv != SECSuccess) {
427 PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
428 }
429
430 return rv;
431 }
432
433
434 /* derive the Master Secret from the PMS */
435 /* Presently, this is only done wtih RSA PMS, and only on the server side,
436 * so isRSA is always true.
437 */
438 SECStatus
ssl3_MasterKeyDeriveBypass(ssl3CipherSpec * pwSpec,const unsigned char * cr,const unsigned char * sr,const SECItem * pms,PRBool isTLS,PRBool isRSA)439 ssl3_MasterKeyDeriveBypass(
440 ssl3CipherSpec * pwSpec,
441 const unsigned char * cr,
442 const unsigned char * sr,
443 const SECItem * pms,
444 PRBool isTLS,
445 PRBool isRSA)
446 {
447 unsigned char * key_block = pwSpec->key_block;
448 SECStatus rv = SECSuccess;
449 PRBool isFIPS = PR_FALSE;
450
451 SECItem crsr;
452
453 unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
454 PRUint64 md5buf[22];
455 PRUint64 shabuf[40];
456
457 #define md5Ctx ((MD5Context *)md5buf)
458 #define shaCtx ((SHA1Context *)shabuf)
459
460 /* first do the consistancy checks */
461 if (isRSA) {
462 PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH);
463 if (pms->len != SSL3_RSA_PMS_LENGTH) {
464 PORT_SetError(SEC_ERROR_INVALID_ARGS);
465 return SECFailure;
466 }
467 /* caller must test PMS version for rollback */
468 }
469
470 /* initialize the client random, server random block */
471 crsr.type = siBuffer;
472 crsr.data = crsrdata;
473 crsr.len = sizeof crsrdata;
474 PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
475 PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
476 PRINT_BUF(100, (NULL, "Master Secret CRSR", crsr.data, crsr.len));
477
478 /* finally do the key gen */
479 if (isTLS) {
480 SECItem master = { siBuffer, NULL, 0 };
481
482 master.data = key_block;
483 master.len = SSL3_MASTER_SECRET_LENGTH;
484
485 rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS);
486 if (rv != SECSuccess) {
487 PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
488 }
489 } else {
490 int i;
491 unsigned int made = 0;
492 for (i = 0; i < 3; i++) {
493 unsigned int outLen;
494 unsigned char sha_out[SHA1_LENGTH];
495
496 SHA1_Begin(shaCtx);
497 SHA1_Update(shaCtx, (unsigned char*) mixers[i], i+1);
498 SHA1_Update(shaCtx, pms->data, pms->len);
499 SHA1_Update(shaCtx, crsr.data, crsr.len);
500 SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
501 PORT_Assert(outLen == SHA1_LENGTH);
502
503 MD5_Begin(md5Ctx);
504 MD5_Update(md5Ctx, pms->data, pms->len);
505 MD5_Update(md5Ctx, sha_out, outLen);
506 MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
507 PORT_Assert(outLen == MD5_LENGTH);
508 made += outLen;
509 }
510 }
511
512 /* store the results */
513 PORT_Memcpy(pwSpec->raw_master_secret, key_block,
514 SSL3_MASTER_SECRET_LENGTH);
515 pwSpec->msItem.data = pwSpec->raw_master_secret;
516 pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
517 PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data,
518 pwSpec->msItem.len));
519
520 return rv;
521 }
522
523 static SECStatus
ssl_canExtractMS(PK11SymKey * pms,PRBool isTLS,PRBool isDH,PRBool * pcbp)524 ssl_canExtractMS(PK11SymKey *pms, PRBool isTLS, PRBool isDH, PRBool *pcbp)
525 { SECStatus rv;
526 PK11SymKey * ms = NULL;
527 SECItem params = {siBuffer, NULL, 0};
528 CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
529 unsigned char rand[SSL3_RANDOM_LENGTH];
530 CK_VERSION pms_version;
531 CK_MECHANISM_TYPE master_derive;
532 CK_MECHANISM_TYPE key_derive;
533 CK_FLAGS keyFlags;
534
535 if (pms == NULL)
536 return(SECFailure);
537
538 PORT_Memset(rand, 0, SSL3_RANDOM_LENGTH);
539
540 if (isTLS) {
541 if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
542 else master_derive = CKM_TLS_MASTER_KEY_DERIVE;
543 key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
544 keyFlags = CKF_SIGN | CKF_VERIFY;
545 } else {
546 if (isDH) master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
547 else master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
548 key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
549 keyFlags = 0;
550 }
551
552 master_params.pVersion = &pms_version;
553 master_params.RandomInfo.pClientRandom = rand;
554 master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
555 master_params.RandomInfo.pServerRandom = rand;
556 master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
557
558 params.data = (unsigned char *) &master_params;
559 params.len = sizeof master_params;
560
561 ms = PK11_DeriveWithFlags(pms, master_derive, ¶ms, key_derive,
562 CKA_DERIVE, 0, keyFlags);
563 if (ms == NULL)
564 return(SECFailure);
565
566 rv = PK11_ExtractKeyValue(ms);
567 *pcbp = (rv == SECSuccess);
568 PK11_FreeSymKey(ms);
569
570 return(rv);
571
572 }
573
574 /* Check the key exchange algorithm for each cipher in the list to see if
575 * a master secret key can be extracted. If the KEA will use keys from the
576 * specified cert make sure the extract operation is attempted from the slot
577 * where the private key resides.
578 * If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and
579 * SECSuccess is returned. In all other cases but one (*pcanbypass) is
580 * set to FALSE and SECFailure is returned.
581 * In that last case Derive() has been called successfully but the MS is null,
582 * CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the
583 * arguments were all valid but the slot cannot be bypassed.
584 */
585
586 SECStatus
SSL_CanBypass(CERTCertificate * cert,SECKEYPrivateKey * srvPrivkey,PRUint32 protocolmask,PRUint16 * ciphersuites,int nsuites,PRBool * pcanbypass,void * pwArg)587 SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
588 PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites,
589 PRBool *pcanbypass, void *pwArg)
590 { SECStatus rv;
591 int i;
592 PRUint16 suite;
593 PK11SymKey * pms = NULL;
594 SECKEYPublicKey * srvPubkey = NULL;
595 KeyType privKeytype;
596 PK11SlotInfo * slot = NULL;
597 SECItem param;
598 CK_VERSION version;
599 CK_MECHANISM_TYPE mechanism_array[2];
600 SECItem enc_pms = {siBuffer, NULL, 0};
601 PRBool isTLS = PR_FALSE;
602 SSLCipherSuiteInfo csdef;
603 PRBool testrsa = PR_FALSE;
604 PRBool testrsa_export = PR_FALSE;
605 PRBool testecdh = PR_FALSE;
606 PRBool testecdhe = PR_FALSE;
607
608 if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) {
609 PORT_SetError(SEC_ERROR_INVALID_ARGS);
610 return SECFailure;
611 }
612
613 srvPubkey = CERT_ExtractPublicKey(cert);
614 if (!srvPubkey)
615 return SECFailure;
616
617 *pcanbypass = PR_TRUE;
618 rv = SECFailure;
619
620 /* determine which KEAs to test */
621 /* 0 (SSL_NULL_WITH_NULL_NULL) is used as a list terminator because
622 * SSL3 and TLS specs forbid negotiating that cipher suite number.
623 */
624 for (i=0; i < nsuites && (suite = *ciphersuites++) != 0; i++) {
625 /* skip SSL2 cipher suites and ones NSS doesn't support */
626 if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess
627 || SSL_IS_SSL2_CIPHER(suite) )
628 continue;
629 switch (csdef.keaType) {
630 case ssl_kea_rsa:
631 switch (csdef.cipherSuite) {
632 case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA:
633 case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA:
634 case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
635 case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
636 testrsa_export = PR_TRUE;
637 }
638 if (!testrsa_export)
639 testrsa = PR_TRUE;
640 break;
641 case ssl_kea_ecdh:
642 if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */
643 testecdhe = PR_TRUE;
644 else
645 testecdh = PR_TRUE;
646 break;
647 case ssl_kea_dh:
648 /* this is actually DHE */
649 default:
650 continue;
651 }
652 }
653
654 /* For each protocol try to derive and extract an MS.
655 * Failure of function any function except MS extract means
656 * continue with the next cipher test. Stop testing when the list is
657 * exhausted or when the first MS extract--not derive--fails.
658 */
659 privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey);
660 protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0;
661 while (protocolmask) {
662 if (protocolmask & SSL_CBP_SSL3) {
663 isTLS = PR_FALSE;
664 protocolmask ^= SSL_CBP_SSL3;
665 } else {
666 isTLS = PR_TRUE;
667 protocolmask ^= SSL_CBP_TLS1_0;
668 }
669
670 if (privKeytype == rsaKey && testrsa_export) {
671 if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) {
672 *pcanbypass = PR_FALSE;
673 rv = SECSuccess;
674 break;
675 } else
676 testrsa = PR_TRUE;
677 }
678 for (; privKeytype == rsaKey && testrsa; ) {
679 /* TLS_RSA */
680 unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
681 unsigned int outLen = 0;
682 CK_MECHANISM_TYPE target;
683 SECStatus irv;
684
685 mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
686 mechanism_array[1] = CKM_RSA_PKCS;
687
688 slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg);
689 if (slot == NULL) {
690 PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND);
691 break;
692 }
693
694 /* Generate the pre-master secret ... (client side) */
695 version.major = 3 /*MSB(clientHelloVersion)*/;
696 version.minor = 0 /*LSB(clientHelloVersion)*/;
697 param.data = (unsigned char *)&version;
698 param.len = sizeof version;
699 pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, ¶m, 0, pwArg);
700 PK11_FreeSlot(slot);
701 if (!pms)
702 break;
703 /* now wrap it */
704 enc_pms.len = SECKEY_PublicKeyStrength(srvPubkey);
705 enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len);
706 irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms);
707 if (irv != SECSuccess)
708 break;
709 PK11_FreeSymKey(pms);
710 /* now do the server side--check the triple bypass first */
711 rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen,
712 sizeof rsaPmsBuf,
713 (unsigned char *)enc_pms.data,
714 enc_pms.len);
715 /* if decrypt worked we're done with the RSA test */
716 if (rv == SECSuccess) {
717 *pcanbypass = PR_TRUE;
718 break;
719 }
720 /* check for fallback to double bypass */
721 target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE
722 : CKM_SSL3_MASTER_KEY_DERIVE;
723 pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms,
724 target, CKA_DERIVE, 0);
725 rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass);
726 if (rv == SECSuccess && *pcanbypass == PR_FALSE)
727 goto done;
728 break;
729 }
730 #ifdef NSS_ENABLE_ECC
731 for (; (privKeytype == ecKey && ( testecdh || testecdhe)) ||
732 (privKeytype == rsaKey && testecdhe); ) {
733 CK_MECHANISM_TYPE target;
734 SECKEYPublicKey *keapub = NULL;
735 SECKEYPrivateKey *keapriv;
736 SECKEYPublicKey *cpub = NULL; /* client's ephemeral ECDH keys */
737 SECKEYPrivateKey *cpriv = NULL;
738 SECKEYECParams ecParams = { siBuffer, NULL, 0 },
739 *pecParams;
740
741 if (privKeytype == ecKey && testecdhe) {
742 /* TLS_ECDHE_ECDSA */
743 pecParams = &srvPubkey->u.ec.DEREncodedParams;
744 } else if (privKeytype == rsaKey && testecdhe) {
745 /* TLS_ECDHE_RSA */
746 ECName ec_curve;
747 int serverKeyStrengthInBits;
748 int signatureKeyStrength;
749 int requiredECCbits;
750
751 /* find a curve of equivalent strength to the RSA key's */
752 requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey);
753 if (requiredECCbits < 0)
754 break;
755 requiredECCbits *= BPB;
756 serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len;
757 if (srvPubkey->u.rsa.modulus.data[0] == 0) {
758 serverKeyStrengthInBits--;
759 }
760 /* convert to strength in bits */
761 serverKeyStrengthInBits *= BPB;
762
763 signatureKeyStrength =
764 SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
765
766 if ( requiredECCbits > signatureKeyStrength )
767 requiredECCbits = signatureKeyStrength;
768
769 ec_curve =
770 ssl3_GetCurveWithECKeyStrength(SSL3_SUPPORTED_CURVES_MASK,
771 requiredECCbits);
772 rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams);
773 if (rv == SECFailure) {
774 break;
775 }
776 pecParams = &ecParams;
777 }
778
779 if (testecdhe) {
780 /* generate server's ephemeral keys */
781 keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL);
782 if (!keapriv || !keapub) {
783 if (keapriv)
784 SECKEY_DestroyPrivateKey(keapriv);
785 if (keapub)
786 SECKEY_DestroyPublicKey(keapub);
787 PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
788 rv = SECFailure;
789 break;
790 }
791 } else {
792 /* TLS_ECDH_ECDSA */
793 keapub = srvPubkey;
794 keapriv = srvPrivkey;
795 pecParams = &srvPubkey->u.ec.DEREncodedParams;
796 }
797
798 /* perform client side ops */
799 /* generate a pair of ephemeral keys using server's parms */
800 cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL);
801 if (!cpriv || !cpub) {
802 if (testecdhe) {
803 SECKEY_DestroyPrivateKey(keapriv);
804 SECKEY_DestroyPublicKey(keapub);
805 }
806 PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
807 rv = SECFailure;
808 break;
809 }
810 /* now do the server side */
811 /* determine the PMS using client's public value */
812 target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH
813 : CKM_SSL3_MASTER_KEY_DERIVE_DH;
814 pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL,
815 CKM_ECDH1_DERIVE,
816 target,
817 CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
818 rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass);
819 SECKEY_DestroyPrivateKey(cpriv);
820 SECKEY_DestroyPublicKey(cpub);
821 if (testecdhe) {
822 SECKEY_DestroyPrivateKey(keapriv);
823 SECKEY_DestroyPublicKey(keapub);
824 if (privKeytype == rsaKey)
825 PORT_Free(ecParams.data);
826 }
827 if (rv == SECSuccess && *pcanbypass == PR_FALSE)
828 goto done;
829 break;
830 }
831 #endif /* NSS_ENABLE_ECC */
832 if (pms)
833 PK11_FreeSymKey(pms);
834 }
835
836 /* *pcanbypass has been set */
837 rv = SECSuccess;
838
839 done:
840 if (pms)
841 PK11_FreeSymKey(pms);
842
843 SECITEM_FreeItem(&enc_pms, PR_FALSE);
844
845 if (srvPubkey) {
846 SECKEY_DestroyPublicKey(srvPubkey);
847 srvPubkey = NULL;
848 }
849
850
851 return rv;
852 }
853
854