Don't compute excessive key material for SSL3/TLS. Bug 274512. NSS_3_11_BRANCH
authornelson%bolyard.com
Tue, 25 Apr 2006 06:33:04 +0000
branchNSS_3_11_BRANCH
changeset 6944 4408b7e3294d94811687b1915affc3fd423b98ec
parent 6939 5cb5ea55e4a6b9ece8a311a1a3df389fe2325b8d
child 6945 14eb8abb4638a8ae027d655d2ca8a02536fc6c56
child 6946 fb0f4d38b4ceb05093e07bd6cf5ac0fc6ea9d9d1
push idunknown
push userunknown
push dateunknown
bugs274512
Don't compute excessive key material for SSL3/TLS. Bug 274512. r=julien.pierre, wtchang
security/nss/lib/softoken/pkcs11c.c
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -4717,17 +4717,19 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
     case CKM_TLS_MASTER_KEY_DERIVE:
     case CKM_TLS_MASTER_KEY_DERIVE_DH:
 	isTLS = PR_TRUE;
 	/* fall thru */
     case CKM_SSL3_MASTER_KEY_DERIVE:
     case CKM_SSL3_MASTER_KEY_DERIVE_DH:
       {
 	CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master;
-	SSL3RSAPreMasterSecret *rsa_pms;
+	SSL3RSAPreMasterSecret *          rsa_pms;
+	unsigned char                     crsrdata[SSL3_RANDOM_LENGTH * 2];
+
         if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) ||
             (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH))
 		isDH = PR_TRUE;
 
 	/* first do the consistancy checks */
 	if (!isDH && (att->attrib.ulValueLen != SSL3_PMS_LENGTH)) {
 	    crv = CKR_KEY_TYPE_INCONSISTENT;
 	    break;
@@ -4744,20 +4746,25 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
 	    break;
 	}
 	if ((keySize != 0) && (keySize != SSL3_MASTER_SECRET_LENGTH)) {
 	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
 	    break;
 	}
 
-
 	/* finally do the key gen */
 	ssl3_master = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)
 					pMechanism->pParameter;
+
+	PORT_Memcpy(crsrdata, 
+	            ssl3_master->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
+	PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
+	            ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
+
 	if (ssl3_master->pVersion) {
 	    SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
 	    rsa_pms = (SSL3RSAPreMasterSecret *) att->attrib.pValue;
 	    /* don't leak more key material then necessary for SSL to work */
 	    if ((sessKey == NULL) || sessKey->wasDerived) {
 		ssl3_master->pVersion->major = 0xff;
 		ssl3_master->pVersion->minor = 0xff;
 	    } else {
@@ -4770,33 +4777,26 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 	   break;
 	}
 	if (ssl3_master->RandomInfo.ulServerRandomLen != SSL3_RANDOM_LENGTH) {
 	   crv = CKR_MECHANISM_PARAM_INVALID;
 	   break;
 	}
 
         if (isTLS) {
-	    unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
-	    SECItem crsr = { siBuffer, NULL, 0 };
-	    SECItem master = { siBuffer, NULL, 0 };
-	    SECItem pms = { siBuffer, NULL, 0 };
 	    SECStatus status;
-
-	    pms.data = (unsigned char*)att->attrib.pValue;
-	    pms.len = att->attrib.ulValueLen;
-	    master.data = key_block;
-	    master.len = SSL3_MASTER_SECRET_LENGTH;
-	    crsr.data = crsrdata;
-	    crsr.len = sizeof(crsrdata);
-
-	    PORT_Memcpy(crsrdata, ssl3_master->RandomInfo.pClientRandom,
-							 SSL3_RANDOM_LENGTH);
-	    PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
-		ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
+ 	    SECItem crsr   = { siBuffer, crsrdata, sizeof crsrdata };
+ 	    SECItem master = { siBuffer, key_block, SSL3_MASTER_SECRET_LENGTH};
+ 	    SECItem pms    = { siBuffer };
+
+	    /* HPUX won't let a structure member be initialized with the 
+	     * value of a variable, but the address of a local variable. :-/
+	     */
+ 	    pms.data = (unsigned char*)att->attrib.pValue;
+	    pms.len  =                 att->attrib.ulValueLen;
 
 	    status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
 	    if (status != SECSuccess) {
 	    	crv = CKR_FUNCTION_FAILED;
 		break;
 	    }
 	} else {
 	    /* now allocate the hash contexts */
@@ -4811,22 +4811,20 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 		crv = CKR_HOST_MEMORY;
 		break;
 	    }
             for (i = 0; i < 3; i++) {
               SHA1_Begin(sha);
               SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
               SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
 			  att->attrib.ulValueLen);
-              SHA1_Update(sha, ssl3_master->RandomInfo.pClientRandom,
-				ssl3_master->RandomInfo.ulClientRandomLen);
-              SHA1_Update(sha, ssl3_master->RandomInfo.pServerRandom, 
-				ssl3_master->RandomInfo.ulServerRandomLen);
+              SHA1_Update(sha, crsrdata, sizeof crsrdata);
               SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
               PORT_Assert(outLen == SHA1_LENGTH);
+
               MD5_Begin(md5);
               MD5_Update(md5, (const unsigned char*)att->attrib.pValue, 
 			 att->attrib.ulValueLen);
               MD5_Update(md5, sha_out, outLen);
               MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
               PORT_Assert(outLen == MD5_LENGTH);
             }
 	    PORT_Free(md5);
@@ -4857,16 +4855,19 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
     case CKM_TLS_KEY_AND_MAC_DERIVE:
 	isTLS = PR_TRUE;
 	/* fall thru */
     case CKM_SSL3_KEY_AND_MAC_DERIVE:
       {
 	CK_SSL3_KEY_MAT_PARAMS *ssl3_keys;
 	CK_SSL3_KEY_MAT_OUT *   ssl3_keys_out;
 	CK_ULONG                effKeySize;
+	unsigned int            block_needed;
+	unsigned char           srcrdata[SSL3_RANDOM_LENGTH * 2];
+	unsigned char           crsrdata[SSL3_RANDOM_LENGTH * 2];
 
 	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
 	if (crv != CKR_OK) break;
 
 	if (att->attrib.ulValueLen != SSL3_MASTER_SECRET_LENGTH) {
 	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
 	    break;
 	}
@@ -4885,95 +4886,103 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 	}
 	sha = SHA1_NewContext();
 	if (sha == NULL) { 
 	    PORT_Free(md5);
 	    crv = CKR_HOST_MEMORY;
 	    break;
 	}
 	ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter;
+
+	PORT_Memcpy(srcrdata, 
+	            ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
+	PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, 
+		    ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
+
+	PORT_Memcpy(crsrdata, 
+		    ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
+	PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
+		    ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
+
 	/*
 	 * clear out our returned keys so we can recover on failure
 	 */
 	ssl3_keys_out = ssl3_keys->pReturnedKeyMaterial;
 	ssl3_keys_out->hClientMacSecret = CK_INVALID_HANDLE;
 	ssl3_keys_out->hServerMacSecret = CK_INVALID_HANDLE;
 	ssl3_keys_out->hClientKey       = CK_INVALID_HANDLE;
 	ssl3_keys_out->hServerKey       = CK_INVALID_HANDLE;
 
 	/*
+	 * How much key material do we need?
+	 */
+	macSize    = ssl3_keys->ulMacSizeInBits/8;
+	effKeySize = ssl3_keys->ulKeySizeInBits/8;
+	IVSize     = ssl3_keys->ulIVSizeInBits/8;
+	if (keySize == 0) {
+	    effKeySize = keySize;
+	}
+	block_needed = 2 * (macSize + effKeySize + 
+	                    ((!ssl3_keys->bIsExport) * IVSize));
+	PORT_Assert(block_needed <= sizeof key_block);
+	if (block_needed > sizeof key_block)
+	    block_needed = sizeof key_block;
+
+	/*
 	 * generate the key material: This looks amazingly similar to the
 	 * PMS code, and is clearly crying out for a function to provide it.
 	 */
 	if (isTLS) {
 	    SECStatus     status;
-	    SECItem       master = { siBuffer, NULL, 0 };
-	    SECItem       srcr   = { siBuffer, NULL, 0 };
-	    SECItem       keyblk = { siBuffer, NULL, 0 };
-	    unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2];
-
+	    SECItem       srcr   = { siBuffer, srcrdata, sizeof srcrdata };
+	    SECItem       keyblk = { siBuffer, key_block };
+	    SECItem       master = { siBuffer }; 
+
+	    keyblk.len  = block_needed;
 	    master.data = (unsigned char*)att->attrib.pValue;
-	    master.len  = att->attrib.ulValueLen;
-	    srcr.data   = srcrdata;
-	    srcr.len    = sizeof srcrdata;
-	    keyblk.data = key_block;
-	    keyblk.len  = sizeof key_block;
-
-	    PORT_Memcpy(srcrdata, 
-	                ssl3_keys->RandomInfo.pServerRandom,
-			SSL3_RANDOM_LENGTH);
-	    PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, 
-		        ssl3_keys->RandomInfo.pClientRandom, 
-			SSL3_RANDOM_LENGTH);
+	    master.len  =                 att->attrib.ulValueLen;
 
 	    status = TLS_PRF(&master, "key expansion", &srcr, &keyblk,
 			      isFIPS);
 	    if (status != SECSuccess) {
 		goto key_and_mac_derive_fail;
 	    }
 	} else {
+	    unsigned int block_bytes = 0;
 	    /* key_block = 
 	     *     MD5(master_secret + SHA('A' + master_secret + 
 	     *                      ServerHello.random + ClientHello.random)) +
 	     *     MD5(master_secret + SHA('BB' + master_secret + 
 	     *                      ServerHello.random + ClientHello.random)) +
 	     *     MD5(master_secret + SHA('CCC' + master_secret + 
 	     *                      ServerHello.random + ClientHello.random)) +
 	     *     [...];
 	     */
-	    for (i = 0; i < NUM_MIXERS; i++) {
+	    for (i = 0; i < NUM_MIXERS && block_bytes < block_needed; i++) {
 	      SHA1_Begin(sha);
 	      SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
 	      SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
 			  att->attrib.ulValueLen);
-              SHA1_Update(sha, ssl3_keys->RandomInfo.pServerRandom, 
-				ssl3_keys->RandomInfo.ulServerRandomLen);
-              SHA1_Update(sha, ssl3_keys->RandomInfo.pClientRandom,
-				ssl3_keys->RandomInfo.ulClientRandomLen);
+	      SHA1_Update(sha, srcrdata, sizeof srcrdata);
 	      SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
 	      PORT_Assert(outLen == SHA1_LENGTH);
 	      MD5_Begin(md5);
 	      MD5_Update(md5, (const unsigned char*)att->attrib.pValue,
 			 att->attrib.ulValueLen);
 	      MD5_Update(md5, sha_out, outLen);
 	      MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
 	      PORT_Assert(outLen == MD5_LENGTH);
+	      block_bytes += outLen;
 	    }
 	}
 
 	/*
 	 * Put the key material where it goes.
 	 */
 	i = 0;			/* now shows how much consumed */
-	macSize    = ssl3_keys->ulMacSizeInBits/8;
-	effKeySize = ssl3_keys->ulKeySizeInBits/8;
-	IVSize     = ssl3_keys->ulIVSizeInBits/8;
-	if (keySize == 0) {
-	    effKeySize = keySize;
-	}
 
 	/* 
 	 * The key_block is partitioned as follows:
 	 * client_write_MAC_secret[CipherSpec.hash_size]
 	 */
 	crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
 					 &ssl3_keys_out->hClientMacSecret);
 	if (crv != CKR_OK)
@@ -5038,92 +5047,68 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 		/*
 		** Generate SSL3 Export write keys and IVs.
 		** client_write_key[CipherSpec.key_material]
 		** final_client_write_key = MD5(client_write_key +
 		**                   ClientHello.random + ServerHello.random);
 		*/
 		MD5_Begin(md5);
 		MD5_Update(md5, &key_block[i], effKeySize);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom,
-				ssl3_keys->RandomInfo.ulClientRandomLen);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, 
-				ssl3_keys->RandomInfo.ulServerRandomLen);
+            	MD5_Update(md5, crsrdata, sizeof crsrdata);
 		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
 		i += effKeySize;
 		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
 				 	keySize,&ssl3_keys_out->hClientKey);
 		if (crv != CKR_OK) {
 		    goto key_and_mac_derive_fail;
 		}
 
 		/*
 		** server_write_key[CipherSpec.key_material]
 		** final_server_write_key = MD5(server_write_key +
 		**                    ServerHello.random + ClientHello.random);
 		*/
 		MD5_Begin(md5);
 		MD5_Update(md5, &key_block[i], effKeySize);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, 
-				ssl3_keys->RandomInfo.ulServerRandomLen);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom,
-				ssl3_keys->RandomInfo.ulClientRandomLen);
+            	MD5_Update(md5, srcrdata, sizeof srcrdata);
 		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
 		i += effKeySize;
 		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
 					 keySize,&ssl3_keys_out->hServerKey);
 		if (crv != CKR_OK) {
 		    goto key_and_mac_derive_fail;
 		}
 
 		/*
 		** client_write_IV = 
 		**	MD5(ClientHello.random + ServerHello.random);
 		*/
 		MD5_Begin(md5);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom,
-				ssl3_keys->RandomInfo.ulClientRandomLen);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, 
-				ssl3_keys->RandomInfo.ulServerRandomLen);
+            	MD5_Update(md5, crsrdata, sizeof crsrdata);
 		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
 		PORT_Memcpy(ssl3_keys_out->pIVClient, key_block2, IVSize);
 
 		/*
 		** server_write_IV = 
 		**	MD5(ServerHello.random + ClientHello.random);
 		*/
 		MD5_Begin(md5);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, 
-				ssl3_keys->RandomInfo.ulServerRandomLen);
-            	MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom,
-				ssl3_keys->RandomInfo.ulClientRandomLen);
+            	MD5_Update(md5, srcrdata, sizeof srcrdata);
 		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
 		PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize);
 
 	    } else {
 
 		/*
 		** Generate TLS Export write keys and IVs.
 		*/
 		SECStatus     status;
 		SECItem       secret = { siBuffer, NULL, 0 };
-		SECItem       crsr   = { siBuffer, NULL, 0 };
+		SECItem       crsr   = { siBuffer, crsrdata, sizeof crsrdata };
 		SECItem       keyblk = { siBuffer, NULL, 0 };
-		unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
-
-		crsr.data   = crsrdata;
-		crsr.len    = sizeof crsrdata;
-
-		PORT_Memcpy(crsrdata, 
-		            ssl3_keys->RandomInfo.pClientRandom, 
-			    SSL3_RANDOM_LENGTH);
-		PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
-			    ssl3_keys->RandomInfo.pServerRandom,
-			    SSL3_RANDOM_LENGTH);
-
 
 		/*
 		** client_write_key[CipherSpec.key_material]
 		** final_client_write_key = PRF(client_write_key, 
 		**                              "client write key",
 		**                              client_random + server_random);
 		*/
 		secret.data = &key_block[i];