/* ======================================================================== Routine Description: HMAC using SHA1 hash function Arguments: key Secret key key_len The length of the key in bytes message Message context message_len The length of message in bytes macLen Request the length of message authentication code Return Value: mac Message authentication code Note: None ======================================================================== */ VOID HMAC_SHA1 ( IN const UINT8 Key[], IN UINT KeyLen, IN const UINT8 Message[], IN UINT MessageLen, OUT UINT8 MAC[], IN UINT MACLen) { SHA1_CTX_STRUC sha_ctx1; SHA1_CTX_STRUC sha_ctx2; UINT8 K0[SHA1_BLOCK_SIZE]; UINT8 Digest[SHA1_DIGEST_SIZE]; UINT index; NdisZeroMemory(&sha_ctx1, sizeof(SHA1_CTX_STRUC)); NdisZeroMemory(&sha_ctx2, sizeof(SHA1_CTX_STRUC)); /* * If the length of K = B(Block size): K0 = K. * If the length of K > B: hash K to obtain an L byte string, * then append (B-L) zeros to create a B-byte string K0 (i.e., K0 = H(K) || 00...00). * If the length of K < B: append zeros to the end of K to create a B-byte string K0 */ NdisZeroMemory(K0, SHA1_BLOCK_SIZE); if (KeyLen <= SHA1_BLOCK_SIZE) NdisMoveMemory(K0, Key, KeyLen); else RT_SHA1(Key, KeyLen, K0); /* End of if */ /* Exclusive-Or K0 with ipad */ /* ipad: Inner pad; the byte x��36�� repeated B times. */ for (index = 0; index < SHA1_BLOCK_SIZE; index++) K0[index] ^= 0x36; /* End of for */ SHA1_Init(&sha_ctx1); /* H(K0^ipad) */ SHA1_Append(&sha_ctx1, K0, sizeof(K0)); /* H((K0^ipad)||text) */ SHA1_Append(&sha_ctx1, Message, MessageLen); SHA1_End(&sha_ctx1, Digest); /* Exclusive-Or K0 with opad and remove ipad */ /* opad: Outer pad; the byte x��5c�� repeated B times. */ for (index = 0; index < SHA1_BLOCK_SIZE; index++) K0[index] ^= 0x36^0x5c; /* End of for */ SHA1_Init(&sha_ctx2); /* H(K0^opad) */ SHA1_Append(&sha_ctx2, K0, sizeof(K0)); /* H( (K0^opad) || H((K0^ipad)||text) ) */ SHA1_Append(&sha_ctx2, Digest, SHA1_DIGEST_SIZE); SHA1_End(&sha_ctx2, Digest); if (MACLen > SHA1_DIGEST_SIZE) NdisMoveMemory(MAC, Digest, SHA1_DIGEST_SIZE); else NdisMoveMemory(MAC, Digest, MACLen); } /* End of HMAC_SHA1 */
SECStatus SHA1_HashBuf(unsigned char *dest, const unsigned char *src, uint32 src_length) { SHA1Context ctx; unsigned int outLen; SHA1_Begin(&ctx); SHA1_Update(&ctx, src, src_length); SHA1_End(&ctx, dest, &outLen, SHA1_LENGTH); return SECSuccess; }
static char * digest_end(DIGEST_CTX *c, char *buf) { switch (digesttype) { case DIGEST_MD5: return (MD5End(&(c->MD5), buf)); case DIGEST_RIPEMD160: return (RIPEMD160_End(&(c->RIPEMD160), buf)); case DIGEST_SHA1: return (SHA1_End(&(c->SHA1), buf)); case DIGEST_SHA256: return (SHA256_End(&(c->SHA256), buf)); case DIGEST_SHA512: return (SHA512_End(&(c->SHA512), buf)); default: return (NULL); } }
/* take string password and turn it into a key. The key is dependent * on a global salt entry acquired from the database. This salted * value will be based to a pkcs5 pbe function before it is used * in an actual encryption */ static SECStatus sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt, const char *pw, SECItem *key) { SHA1Context *cx = NULL; SECStatus rv = SECFailure; key->data = PORT_Alloc(SHA1_LENGTH); if (key->data == NULL) { goto loser; } key->len = SHA1_LENGTH; cx = SHA1_NewContext(); if (cx == NULL) { goto loser; } SHA1_Begin(cx); if (salt && salt->data) { SHA1_Update(cx, salt->data, salt->len); } SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw)); SHA1_End(cx, key->data, &key->len, key->len); rv = SECSuccess; loser: if (cx) { SHA1_DestroyContext(cx, PR_TRUE); } if (rv != SECSuccess) { if (key->data != NULL) { PORT_ZFree(key->data, key->len); } key->data = NULL; } return rv; }
SECStatus ssl3_KeyAndMacDeriveBypass( ssl3CipherSpec * pwSpec, const unsigned char * cr, const unsigned char * sr, PRBool isTLS, PRBool isExport) { const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; unsigned char * key_block = pwSpec->key_block; unsigned char * key_block2 = NULL; unsigned int block_bytes = 0; unsigned int block_needed = 0; unsigned int i; unsigned int keySize; /* actual size of cipher keys */ unsigned int effKeySize; /* effective size of cipher keys */ unsigned int macSize; /* size of MAC secret */ unsigned int IVSize; /* size of IV */ SECStatus rv = SECFailure; SECStatus status = SECSuccess; PRBool isFIPS = PR_FALSE; SECItem srcr; SECItem crsr; unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2]; unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; PRUint64 md5buf[22]; PRUint64 shabuf[40]; #define md5Ctx ((MD5Context *)md5buf) #define shaCtx ((SHA1Context *)shabuf) static const SECItem zed = { siBuffer, NULL, 0 }; if (pwSpec->msItem.data == NULL || pwSpec->msItem.len != SSL3_MASTER_SECRET_LENGTH) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return rv; } PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, pwSpec->msItem.len)); /* figure out how much is needed */ macSize = pwSpec->mac_size; keySize = cipher_def->key_size; effKeySize = cipher_def->secret_key_size; IVSize = cipher_def->iv_size; if (keySize == 0) { effKeySize = IVSize = 0; /* only MACing */ } block_needed = 2 * (macSize + effKeySize + ((!isExport) * IVSize)); /* * clear out our returned keys so we can recover on failure */ pwSpec->client.write_key_item = zed; pwSpec->client.write_mac_key_item = zed; pwSpec->server.write_key_item = zed; pwSpec->server.write_mac_key_item = zed; /* initialize the server random, client random block */ srcr.type = siBuffer; srcr.data = srcrdata; srcr.len = sizeof srcrdata; PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH); PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH); /* initialize the client random, server random block */ crsr.type = siBuffer; crsr.data = crsrdata; crsr.len = sizeof crsrdata; PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); PRINT_BUF(100, (NULL, "Key & MAC CRSR", crsr.data, crsr.len)); /* * generate the key material: */ if (isTLS) { SECItem keyblk; keyblk.type = siBuffer; keyblk.data = key_block; keyblk.len = block_needed; status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk, isFIPS); if (status != SECSuccess) { goto key_and_mac_derive_fail; } block_bytes = keyblk.len; } else { /* 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)) + * [...]; */ unsigned int made = 0; for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) { unsigned int outLen; unsigned char sha_out[SHA1_LENGTH]; SHA1_Begin(shaCtx); SHA1_Update(shaCtx, (unsigned char*)(mixers[i]), i+1); SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len); SHA1_Update(shaCtx, srcr.data, srcr.len); SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); PORT_Assert(outLen == SHA1_LENGTH); MD5_Begin(md5Ctx); MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len); MD5_Update(md5Ctx, sha_out, outLen); MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); PORT_Assert(outLen == MD5_LENGTH); made += MD5_LENGTH; } block_bytes = made; } PORT_Assert(block_bytes >= block_needed); PORT_Assert(block_bytes <= sizeof pwSpec->key_block); PRINT_BUF(100, (NULL, "key block", key_block, block_bytes)); /* * Put the key material where it goes. */ key_block2 = key_block + block_bytes; i = 0; /* now shows how much consumed */ /* * The key_block is partitioned as follows: * client_write_MAC_secret[CipherSpec.hash_size] */ buildSSLKey(&key_block[i],macSize, &pwSpec->client.write_mac_key_item, \ "Client Write MAC Secret"); i += macSize; /* * server_write_MAC_secret[CipherSpec.hash_size] */ buildSSLKey(&key_block[i],macSize, &pwSpec->server.write_mac_key_item, \ "Server Write MAC Secret"); i += macSize; if (!keySize) { /* only MACing */ buildSSLKey(NULL, 0, &pwSpec->client.write_key_item, \ "Client Write Key (MAC only)"); buildSSLKey(NULL, 0, &pwSpec->server.write_key_item, \ "Server Write Key (MAC only)"); buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item, \ "Client Write IV (MAC only)"); buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item, \ "Server Write IV (MAC only)"); } else if (!isExport) { /* ** Generate Domestic write keys and IVs. ** client_write_key[CipherSpec.key_material] */ buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item, \ "Domestic Client Write Key"); i += keySize; /* ** server_write_key[CipherSpec.key_material] */ buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item, \ "Domestic Server Write Key"); i += keySize; if (IVSize > 0) { /* ** client_write_IV[CipherSpec.IV_size] */ buildSSLKey(&key_block[i], IVSize, &pwSpec->client.write_iv_item, \ "Domestic Client Write IV"); i += IVSize; /* ** server_write_IV[CipherSpec.IV_size] */ buildSSLKey(&key_block[i], IVSize, &pwSpec->server.write_iv_item, \ "Domestic Server Write IV"); i += IVSize; } PORT_Assert(i <= block_bytes); } else if (!isTLS) { /* ** Generate SSL3 Export write keys and IVs. */ unsigned int outLen; /* ** client_write_key[CipherSpec.key_material] ** final_client_write_key = MD5(client_write_key + ** ClientHello.random + ServerHello.random); */ MD5_Begin(md5Ctx); MD5_Update(md5Ctx, &key_block[i], effKeySize); MD5_Update(md5Ctx, crsr.data, crsr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); i += effKeySize; buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \ "SSL3 Export Client Write Key"); key_block2 += keySize; /* ** server_write_key[CipherSpec.key_material] ** final_server_write_key = MD5(server_write_key + ** ServerHello.random + ClientHello.random); */ MD5_Begin(md5Ctx); MD5_Update(md5Ctx, &key_block[i], effKeySize); MD5_Update(md5Ctx, srcr.data, srcr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); i += effKeySize; buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \ "SSL3 Export Server Write Key"); key_block2 += keySize; PORT_Assert(i <= block_bytes); if (IVSize) { /* ** client_write_IV = ** MD5(ClientHello.random + ServerHello.random); */ MD5_Begin(md5Ctx); MD5_Update(md5Ctx, crsr.data, crsr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item, \ "SSL3 Export Client Write IV"); key_block2 += IVSize; /* ** server_write_IV = ** MD5(ServerHello.random + ClientHello.random); */ MD5_Begin(md5Ctx); MD5_Update(md5Ctx, srcr.data, srcr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item, \ "SSL3 Export Server Write IV"); key_block2 += IVSize; } PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); } else { /* ** Generate TLS Export write keys and IVs. */ SECItem secret ; SECItem keyblk ; secret.type = siBuffer; keyblk.type = siBuffer; /* ** 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]; secret.len = effKeySize; i += effKeySize; keyblk.data = key_block2; keyblk.len = keySize; status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS); if (status != SECSuccess) { goto key_and_mac_derive_fail; } buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \ "TLS Export Client Write Key"); key_block2 += keySize; /* ** server_write_key[CipherSpec.key_material] ** final_server_write_key = PRF(server_write_key, ** "server write key", ** client_random + server_random); */ secret.data = &key_block[i]; secret.len = effKeySize; i += effKeySize; keyblk.data = key_block2; keyblk.len = keySize; status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS); if (status != SECSuccess) { goto key_and_mac_derive_fail; } buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \ "TLS Export Server Write Key"); key_block2 += keySize; /* ** iv_block = PRF("", "IV block", client_random + server_random); ** client_write_IV[SecurityParameters.IV_size] ** server_write_IV[SecurityParameters.IV_size] */ if (IVSize) { secret.data = NULL; secret.len = 0; keyblk.data = key_block2; keyblk.len = 2 * IVSize; status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS); if (status != SECSuccess) { goto key_and_mac_derive_fail; } buildSSLKey(key_block2, IVSize, \ &pwSpec->client.write_iv_item, \ "TLS Export Client Write IV"); buildSSLKey(key_block2 + IVSize, IVSize, \ &pwSpec->server.write_iv_item, \ "TLS Export Server Write IV"); key_block2 += 2 * IVSize; } PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); } rv = SECSuccess; key_and_mac_derive_fail: MD5_DestroyContext(md5Ctx, PR_FALSE); SHA1_DestroyContext(shaCtx, PR_FALSE); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); } return rv; }
/* Presently, this is only done wtih RSA PMS, and only on the server side, * so isRSA is always true. */ SECStatus ssl3_MasterKeyDeriveBypass( ssl3CipherSpec * pwSpec, const unsigned char * cr, const unsigned char * sr, const SECItem * pms, PRBool isTLS, PRBool isRSA) { unsigned char * key_block = pwSpec->key_block; SECStatus rv = SECSuccess; PRBool isFIPS = PR_FALSE; SECItem crsr; unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; PRUint64 md5buf[22]; PRUint64 shabuf[40]; #define md5Ctx ((MD5Context *)md5buf) #define shaCtx ((SHA1Context *)shabuf) /* first do the consistancy checks */ if (isRSA) { PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH); if (pms->len != SSL3_RSA_PMS_LENGTH) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* caller must test PMS version for rollback */ } /* initialize the client random, server random block */ crsr.type = siBuffer; crsr.data = crsrdata; crsr.len = sizeof crsrdata; PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); PRINT_BUF(100, (NULL, "Master Secret CRSR", crsr.data, crsr.len)); /* finally do the key gen */ if (isTLS) { SECItem master = { siBuffer, NULL, 0 }; master.data = key_block; master.len = SSL3_MASTER_SECRET_LENGTH; rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); } } else { int i; unsigned int made = 0; for (i = 0; i < 3; i++) { unsigned int outLen; unsigned char sha_out[SHA1_LENGTH]; SHA1_Begin(shaCtx); SHA1_Update(shaCtx, (unsigned char*) mixers[i], i+1); SHA1_Update(shaCtx, pms->data, pms->len); SHA1_Update(shaCtx, crsr.data, crsr.len); SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); PORT_Assert(outLen == SHA1_LENGTH); MD5_Begin(md5Ctx); MD5_Update(md5Ctx, pms->data, pms->len); MD5_Update(md5Ctx, sha_out, outLen); MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); PORT_Assert(outLen == MD5_LENGTH); made += outLen; } } /* store the results */ PORT_Memcpy(pwSpec->raw_master_secret, key_block, SSL3_MASTER_SECRET_LENGTH); pwSpec->msItem.data = pwSpec->raw_master_secret; pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH; PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, pwSpec->msItem.len)); return rv; }
SECStatus ssl3_KeyAndMacDeriveBypass( ssl3CipherSpec * pwSpec, const unsigned char * cr, const unsigned char * sr, PRBool isTLS, PRBool isExport) { const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; unsigned char * key_block = pwSpec->key_block; unsigned char * key_block2 = NULL; unsigned int block_bytes = 0; unsigned int block_needed = 0; unsigned int i; unsigned int keySize; unsigned int effKeySize; unsigned int macSize; unsigned int IVSize; PRBool explicitIV = PR_FALSE; SECStatus rv = SECFailure; SECStatus status = SECSuccess; PRBool isFIPS = PR_FALSE; PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2; SECItem srcr; SECItem crsr; unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2]; unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; PRUint64 md5buf[22]; PRUint64 shabuf[40]; #define md5Ctx ((MD5Context *)md5buf) #define shaCtx ((SHA1Context *)shabuf) static const SECItem zed = { siBuffer, NULL, 0 }; if (pwSpec->msItem.data == NULL || pwSpec->msItem.len != SSL3_MASTER_SECRET_LENGTH) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return rv; } PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, pwSpec->msItem.len)); macSize = pwSpec->mac_size; keySize = cipher_def->key_size; effKeySize = cipher_def->secret_key_size; IVSize = cipher_def->iv_size; if (keySize == 0) { effKeySize = IVSize = 0; } if (cipher_def->type == type_block && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { explicitIV = PR_TRUE; } block_needed = 2 * (macSize + effKeySize + ((!isExport && !explicitIV) * IVSize)); pwSpec->client.write_key_item = zed; pwSpec->client.write_mac_key_item = zed; pwSpec->server.write_key_item = zed; pwSpec->server.write_mac_key_item = zed; srcr.type = siBuffer; srcr.data = srcrdata; srcr.len = sizeof srcrdata; PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH); PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH); crsr.type = siBuffer; crsr.data = crsrdata; crsr.len = sizeof crsrdata; PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); PRINT_BUF(100, (NULL, "Key & MAC CRSR", crsr.data, crsr.len)); if (isTLS) { SECItem keyblk; keyblk.type = siBuffer; keyblk.data = key_block; keyblk.len = block_needed; if (isTLS12) { status = TLS_P_hash(HASH_AlgSHA256, &pwSpec->msItem, "key expansion", &srcr, &keyblk, isFIPS); } else { status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk, isFIPS); } if (status != SECSuccess) { goto key_and_mac_derive_fail; } block_bytes = keyblk.len; } else { unsigned int made = 0; for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) { unsigned int outLen; unsigned char sha_out[SHA1_LENGTH]; SHA1_Begin(shaCtx); SHA1_Update(shaCtx, (unsigned char*)(mixers[i]), i+1); SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len); SHA1_Update(shaCtx, srcr.data, srcr.len); SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); PORT_Assert(outLen == SHA1_LENGTH); MD5_Begin(md5Ctx); MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len); MD5_Update(md5Ctx, sha_out, outLen); MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); PORT_Assert(outLen == MD5_LENGTH); made += MD5_LENGTH; } block_bytes = made; } PORT_Assert(block_bytes >= block_needed); PORT_Assert(block_bytes <= sizeof pwSpec->key_block); PRINT_BUF(100, (NULL, "key block", key_block, block_bytes)); key_block2 = key_block + block_bytes; i = 0; buildSSLKey(&key_block[i],macSize, &pwSpec->client.write_mac_key_item, \ "Client Write MAC Secret"); i += macSize; buildSSLKey(&key_block[i],macSize, &pwSpec->server.write_mac_key_item, \ "Server Write MAC Secret"); i += macSize; if (!keySize) { buildSSLKey(NULL, 0, &pwSpec->client.write_key_item, \ "Client Write Key (MAC only)"); buildSSLKey(NULL, 0, &pwSpec->server.write_key_item, \ "Server Write Key (MAC only)"); buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item, \ "Client Write IV (MAC only)"); buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item, \ "Server Write IV (MAC only)"); } else if (!isExport) { buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item, \ "Domestic Client Write Key"); i += keySize; buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item, \ "Domestic Server Write Key"); i += keySize; if (IVSize > 0) { if (explicitIV) { static unsigned char zero_block[32]; PORT_Assert(IVSize <= sizeof zero_block); buildSSLKey(&zero_block[0], IVSize, \ &pwSpec->client.write_iv_item, \ "Domestic Client Write IV"); buildSSLKey(&zero_block[0], IVSize, \ &pwSpec->server.write_iv_item, \ "Domestic Server Write IV"); } else { buildSSLKey(&key_block[i], IVSize, \ &pwSpec->client.write_iv_item, \ "Domestic Client Write IV"); i += IVSize; buildSSLKey(&key_block[i], IVSize, \ &pwSpec->server.write_iv_item, \ "Domestic Server Write IV"); i += IVSize; } } PORT_Assert(i <= block_bytes); } else if (!isTLS) { unsigned int outLen; MD5_Begin(md5Ctx); MD5_Update(md5Ctx, &key_block[i], effKeySize); MD5_Update(md5Ctx, crsr.data, crsr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); i += effKeySize; buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \ "SSL3 Export Client Write Key"); key_block2 += keySize; MD5_Begin(md5Ctx); MD5_Update(md5Ctx, &key_block[i], effKeySize); MD5_Update(md5Ctx, srcr.data, srcr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); i += effKeySize; buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \ "SSL3 Export Server Write Key"); key_block2 += keySize; PORT_Assert(i <= block_bytes); if (IVSize) { MD5_Begin(md5Ctx); MD5_Update(md5Ctx, crsr.data, crsr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item, \ "SSL3 Export Client Write IV"); key_block2 += IVSize; MD5_Begin(md5Ctx); MD5_Update(md5Ctx, srcr.data, srcr.len); MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item, \ "SSL3 Export Server Write IV"); key_block2 += IVSize; } PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); } else { SECItem secret ; SECItem keyblk ; secret.type = siBuffer; keyblk.type = siBuffer; secret.data = &key_block[i]; secret.len = effKeySize; i += effKeySize; keyblk.data = key_block2; keyblk.len = keySize; status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS); if (status != SECSuccess) { goto key_and_mac_derive_fail; } buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \ "TLS Export Client Write Key"); key_block2 += keySize; secret.data = &key_block[i]; secret.len = effKeySize; i += effKeySize; keyblk.data = key_block2; keyblk.len = keySize; status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS); if (status != SECSuccess) { goto key_and_mac_derive_fail; } buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \ "TLS Export Server Write Key"); key_block2 += keySize; if (IVSize) { secret.data = NULL; secret.len = 0; keyblk.data = key_block2; keyblk.len = 2 * IVSize; status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS); if (status != SECSuccess) { goto key_and_mac_derive_fail; } buildSSLKey(key_block2, IVSize, \ &pwSpec->client.write_iv_item, \ "TLS Export Client Write IV"); buildSSLKey(key_block2 + IVSize, IVSize, \ &pwSpec->server.write_iv_item, \ "TLS Export Server Write IV"); key_block2 += 2 * IVSize; } PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); } rv = SECSuccess; key_and_mac_derive_fail: MD5_DestroyContext(md5Ctx, PR_FALSE); SHA1_DestroyContext(shaCtx, PR_FALSE); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); } return rv; }
SECStatus ssl3_MasterKeyDeriveBypass( ssl3CipherSpec * pwSpec, const unsigned char * cr, const unsigned char * sr, const SECItem * pms, PRBool isTLS, PRBool isRSA) { unsigned char * key_block = pwSpec->key_block; SECStatus rv = SECSuccess; PRBool isFIPS = PR_FALSE; PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2; SECItem crsr; unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; PRUint64 md5buf[22]; PRUint64 shabuf[40]; #define md5Ctx ((MD5Context *)md5buf) #define shaCtx ((SHA1Context *)shabuf) if (isRSA) { PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH); if (pms->len != SSL3_RSA_PMS_LENGTH) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } } crsr.type = siBuffer; crsr.data = crsrdata; crsr.len = sizeof crsrdata; PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); PRINT_BUF(100, (NULL, "Master Secret CRSR", crsr.data, crsr.len)); if (isTLS) { SECItem master = { siBuffer, NULL, 0 }; master.data = key_block; master.len = SSL3_MASTER_SECRET_LENGTH; if (isTLS12) { rv = TLS_P_hash(HASH_AlgSHA256, pms, "master secret", &crsr, &master, isFIPS); } else { rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS); } if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); } } else { int i; unsigned int made = 0; for (i = 0; i < 3; i++) { unsigned int outLen; unsigned char sha_out[SHA1_LENGTH]; SHA1_Begin(shaCtx); SHA1_Update(shaCtx, (unsigned char*) mixers[i], i+1); SHA1_Update(shaCtx, pms->data, pms->len); SHA1_Update(shaCtx, crsr.data, crsr.len); SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); PORT_Assert(outLen == SHA1_LENGTH); MD5_Begin(md5Ctx); MD5_Update(md5Ctx, pms->data, pms->len); MD5_Update(md5Ctx, sha_out, outLen); MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); PORT_Assert(outLen == MD5_LENGTH); made += outLen; } } PORT_Memcpy(pwSpec->raw_master_secret, key_block, SSL3_MASTER_SECRET_LENGTH); pwSpec->msItem.data = pwSpec->raw_master_secret; pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH; PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, pwSpec->msItem.len)); return rv; }