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