• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params, 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, &param, 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