/* ========== Finished, handshake digest routines ========== */ void ssl3_init_handshake_digests( DSSL_Session* sess ) { EVP_DigestInit_ex( &sess->handshake_digest_md5, EVP_md5(), NULL ); EVP_DigestInit_ex( &sess->handshake_digest_sha, EVP_sha1(), NULL ); if ( sess->version >= TLS1_2_VERSION ) { EVP_MD* digest = NULL; DSSL_CipherSuite* suite = sess->dssl_cipher_suite; if ( !suite ) suite = DSSL_GetSSL3CipherSuite( sess->cipher_suite ); digest = EVP_get_digestbyname( suite->digest ); /* 'sha256' is the default for TLS 1.2 */ if ( !digest ) digest = EVP_sha256(); if ( digest ) EVP_DigestInit_ex( &sess->handshake_digest, digest, NULL ); } }
int ssls_generate_keys( DSSL_Session* sess ) { DSSL_CipherSuite* suite = NULL; const EVP_CIPHER* c = NULL; const EVP_MD* digest = NULL; u_char* c_mac = NULL; u_char* c_wk = NULL; u_char* c_iv = NULL; u_char* s_mac = NULL; u_char* s_wk = NULL; u_char* s_iv = NULL; u_char export_iv_block[EVP_MAX_IV_LENGTH*2]; u_char export_c_wk[EVP_MAX_KEY_LENGTH]; u_char export_s_wk[EVP_MAX_KEY_LENGTH]; u_char keyblock[ TLS_MAX_KEYBLOCK_LEN ]; uint32_t keyblock_len = 0; uint32_t iv_len = 0; uint32_t wk_len = 0; uint32_t digest_len = 0; EVP_CIPHER_CTX* c_cipher = NULL; EVP_CIPHER_CTX* s_cipher = NULL; int rc = DSSL_RC_OK; _ASSERT( sess->c_dec.compression_data_new == NULL ); _ASSERT( sess->s_dec.compression_data_new == NULL ); _ASSERT( sess->c_dec.compression_method_new == 0 ); _ASSERT( sess->s_dec.compression_method_new == 0 ); /* set new compression algorithm */ if( sess->compression_method != 0 ) { sess->s_dec.compression_method_new = sess->compression_method; sess->c_dec.compression_method_new = sess->compression_method; dssl_compr_init( sess->s_dec.compression_method_new, &sess->s_dec.compression_data_new ); dssl_compr_init( sess->c_dec.compression_method_new, &sess->c_dec.compression_data_new ); } if( sess->c_dec.cipher_new != NULL ) { // _ASSERT( FALSE ); EVP_CIPHER_CTX_cleanup( sess->c_dec.cipher_new ); free( sess->c_dec.cipher_new ); sess->c_dec.cipher_new = NULL; } if( sess->s_dec.cipher_new != NULL ) { // _ASSERT( FALSE ); EVP_CIPHER_CTX_cleanup( sess->s_dec.cipher_new ); free( sess->s_dec.cipher_new ); sess->s_dec.cipher_new = NULL; } suite = DSSL_GetSSL3CipherSuite( sess->cipher_suite ); if( !suite ) { DEBUG_TRACE0("ssls_generate_keys - failed to find cipher suite\n"); return NM_ERROR( DSSL_E_SSL_CANNOT_DECRYPT ); } if (suite->enc != NULL && strlen(suite->enc) < 32) strcpy(sess->cipher_encoding, suite->enc); if (suite->digest != NULL && strlen(suite->digest) < 32) strcpy(sess->cipher_digest, suite->digest); c = EVP_get_cipherbyname( suite->enc ); digest = EVP_get_digestbyname( suite->digest ); /* calculate key length and IV length */ if( c != NULL ) { if( DSSL_CipherSuiteExportable( suite ) ) { wk_len = suite->export_key_bits / 8; } else { wk_len = EVP_CIPHER_key_length( c ); } iv_len = EVP_CIPHER_iv_length( c ); } if( digest != NULL ) digest_len = EVP_MD_size( digest ); /* calculate total keyblock length */ keyblock_len = (wk_len + digest_len + iv_len)*2; if( !keyblock_len ) return DSSL_RC_OK; if( sess->version == TLS1_VERSION || sess->version == TLS1_1_VERSION) { DEBUG_TRACE0("ssls_generate_keys - calling tls1_PRF\n"); rc = tls1_PRF( sess->master_secret, sizeof( sess->master_secret ), "key expansion", sess->server_random, SSL3_RANDOM_SIZE, sess->client_random, SSL3_RANDOM_SIZE, keyblock, keyblock_len ); } else if( sess->version == TLS1_2_VERSION) { DEBUG_TRACE0("ssls_generate_keys - calling tls12_PRF\n"); rc = tls12_PRF( "SHA256"/*sess->cipher_digest*/, sess->master_secret, sizeof( sess->master_secret ), "key expansion", sess->server_random, SSL3_RANDOM_SIZE, sess->client_random, SSL3_RANDOM_SIZE, keyblock, keyblock_len ); } else { DEBUG_TRACE0("ssls_generate_keys - calling ssl3_PRF\n"); rc = ssl3_PRF( sess->master_secret, sizeof( sess->master_secret ), sess->server_random, SSL3_RANDOM_SIZE, sess->client_random, SSL3_RANDOM_SIZE, keyblock, keyblock_len ); } /* init keying material pointers */ if( rc == DSSL_RC_OK ) { u_char* p = keyblock; if( digest_len ) { c_mac = p; p+= digest_len; s_mac = p; p+= digest_len; } if( c != NULL ) { c_wk = p; p+= wk_len; s_wk = p; p+= wk_len; /* generate final server and client write keys for exportable ciphers */ if( DSSL_CipherSuiteExportable( suite ) ) { int final_wk_len = EVP_CIPHER_key_length( c ); if( sess->version == TLS1_VERSION || sess->version == TLS1_1_VERSION ) { DEBUG_TRACE0("ssls_generate_keys - calling tls1_PRF (2)\n"); tls1_PRF( c_wk, wk_len, "client write key", sess->client_random, SSL3_RANDOM_SIZE, sess->server_random, SSL3_RANDOM_SIZE, export_c_wk, final_wk_len ); tls1_PRF( s_wk, wk_len, "server write key", sess->client_random, SSL3_RANDOM_SIZE, sess->server_random, SSL3_RANDOM_SIZE, export_s_wk, final_wk_len ); } else if( sess->version == TLS1_2_VERSION) { DEBUG_TRACE1("ssls_generate_keys - calling tls12_PRF (2) - sess->cipher_digest: %s\n", sess->cipher_digest); tls12_PRF( "SHA256"/*sess->cipher_digest*/,c_wk, wk_len, "client write key", sess->client_random, SSL3_RANDOM_SIZE, sess->server_random, SSL3_RANDOM_SIZE, export_c_wk, final_wk_len ); tls12_PRF( "SHA256"/*sess->cipher_digest*/,s_wk, wk_len, "server write key", sess->client_random, SSL3_RANDOM_SIZE, sess->server_random, SSL3_RANDOM_SIZE, export_s_wk, final_wk_len ); } else { MD5_CTX md5; DEBUG_TRACE0("ssls_generate_keys - MD5_CTX handling\n"); _ASSERT( sess->version == SSL3_VERSION ); MD5_Init( &md5 ); MD5_Update( &md5, c_wk, wk_len ); MD5_Update( &md5, sess->client_random, SSL3_RANDOM_SIZE ); MD5_Update( &md5, sess->server_random, SSL3_RANDOM_SIZE ); MD5_Final( export_c_wk, &md5 ); MD5_Init( &md5 ); MD5_Update( &md5, s_wk, wk_len ); MD5_Update( &md5, sess->server_random, SSL3_RANDOM_SIZE ); MD5_Update( &md5, sess->client_random, SSL3_RANDOM_SIZE ); MD5_Final( export_s_wk, &md5 ); } c_wk = export_c_wk; s_wk = export_s_wk; wk_len = final_wk_len; } } if( iv_len ) { if( DSSL_CipherSuiteExportable( suite ) ) { if( sess->version == TLS1_VERSION || sess->version == TLS1_1_VERSION ) { DEBUG_TRACE0("ssls_generate_keys - calling tls1_PRF (3)\n"); tls1_PRF( NULL, 0, "IV block", sess->client_random, SSL3_RANDOM_SIZE, sess->server_random, SSL3_RANDOM_SIZE, export_iv_block, iv_len*2 ); } else if( sess->version == TLS1_2_VERSION) { DEBUG_TRACE1("ssls_generate_keys - calling tls12_PRF (3) - sess->cipher_digest: %s\n", sess->cipher_digest); tls12_PRF( "SHA256"/*sess->cipher_digest*/, NULL, 0, "IV block", sess->client_random, SSL3_RANDOM_SIZE, sess->server_random, SSL3_RANDOM_SIZE, export_iv_block, iv_len*2 ); } else { MD5_CTX md5; DEBUG_TRACE0("ssls_generate_keys - MD5_CTX handling (2)\n"); _ASSERT( sess->version == SSL3_VERSION ); MD5_Init( &md5 ); MD5_Update( &md5, sess->client_random, SSL3_RANDOM_SIZE ); MD5_Update( &md5, sess->server_random, SSL3_RANDOM_SIZE ); MD5_Final( export_iv_block, &md5 ); MD5_Init( &md5 ); MD5_Update( &md5, sess->server_random, SSL3_RANDOM_SIZE ); MD5_Update( &md5, sess->client_random, SSL3_RANDOM_SIZE ); MD5_Final( export_iv_block + iv_len, &md5 ); } c_iv = export_iv_block; s_iv = export_iv_block + iv_len; } else { c_iv = p; p+= iv_len; s_iv = p; p+= iv_len; } } else { c_iv = s_iv = NULL; } } /* create ciphers */ if( c != NULL && rc == DSSL_RC_OK ) { c_cipher = (EVP_CIPHER_CTX*) malloc( sizeof(EVP_CIPHER_CTX) ); s_cipher = (EVP_CIPHER_CTX*) malloc( sizeof(EVP_CIPHER_CTX) ); if( !c_cipher || !s_cipher ) { rc = NM_ERROR( DSSL_E_OUT_OF_MEMORY ); } } /* init ciphers */ if( c != NULL && rc == DSSL_RC_OK ) { DEBUG_TRACE0("ssls_generate_keys - EVP_CIPHER_CTX_init\n"); EVP_CIPHER_CTX_init( c_cipher ); EVP_CipherInit( c_cipher, c, c_wk, c_iv, 0 ); EVP_CIPHER_CTX_init( s_cipher ); EVP_CipherInit( s_cipher, c, s_wk, s_iv, 0 ); } else { DEBUG_TRACE0("ssls_generate_keys - not calling EVP_CIPHER_CTX_init\n"); } /* set session data */ if( rc == DSSL_RC_OK ) { _ASSERT( sess->c_dec.cipher_new == NULL ); _ASSERT( sess->s_dec.cipher_new == NULL ); sess->c_dec.cipher_new = c_cipher; c_cipher = NULL; sess->s_dec.cipher_new = s_cipher; s_cipher = NULL; if( digest ) { DEBUG_TRACE1("ssls_generate_keys - identified digest. len: %d\n", digest_len); _ASSERT( EVP_MD_size( digest ) == (int)digest_len ); sess->c_dec.md_new = digest; sess->s_dec.md_new = digest; memcpy( sess->c_dec.mac_key_new, c_mac, digest_len ); memcpy( sess->s_dec.mac_key_new, s_mac, digest_len ); } } /* cleanup */ OPENSSL_cleanse( keyblock, keyblock_len ); if( c_cipher ) { free( c_cipher ); c_cipher = NULL; } if( s_cipher ) { free( c_cipher ); c_cipher = NULL; } return rc; }
void ssl3_update_handshake_digests( DSSL_Session* sess, u_char* data, uint32_t len ) { DSSL_handshake_buffer *q = NULL, *next; /* sanity check in case client hello is not received */ if( sess->handshake_digest_md5.digest == NULL || sess->handshake_digest_sha.digest == NULL) { ssl3_init_handshake_digests( sess ); } EVP_DigestUpdate( &sess->handshake_digest_md5, data, len ); EVP_DigestUpdate( &sess->handshake_digest_sha, data, len ); if ( sess->version >= TLS1_2_VERSION ) { /* if digest is still unknown, then queue the packets. * we'll calculate the handshake hash once we determine which digest we should use. */ EVP_MD* digest = NULL; DSSL_CipherSuite* suite = sess->dssl_cipher_suite; if ( !suite ) suite = DSSL_GetSSL3CipherSuite( sess->cipher_suite ); digest = EVP_get_digestbyname( suite->digest ); /* 'sha256' is the default for TLS 1.2, and can be replaced with a different (but stronger) hash */ if ( !digest ) { q = (DSSL_handshake_buffer*) malloc( sizeof(DSSL_handshake_buffer) ); q->next = NULL; q->data = (u_char*) malloc( len ); memcpy(q->data, data, len); q->len = len; if (NULL == sess->handshake_queue) sess->handshake_queue = q; else sess->handshake_queue->next = q; DEBUG_TRACE3( "Queue handshake packet %p (%u @ %p)", q, q->len, q->data ); } else if ( digest != sess->handshake_digest.digest && EVP_MD_size( digest ) >= EVP_MD_size( sess->handshake_digest.digest ) ) { /* specified digest is different than the default. * re-init and re-hash all queued packets. */ EVP_MD_CTX_cleanup( &sess->handshake_digest ); EVP_DigestInit_ex( &sess->handshake_digest, digest, NULL ); for (q = sess->handshake_queue; q != NULL; q = next) { DEBUG_TRACE3( "Re-hash handshake packet %p (%u @ %p)", q, q->len, q->data ); EVP_DigestUpdate( &sess->handshake_digest, q->data, q->len ); next = q->next; free ( q->data ); free ( q ); } sess->handshake_queue = NULL; } else { /* specified digest is identical to the default. * throw away all the queued packets. */ for (q = sess->handshake_queue; q != NULL; q = next) { DEBUG_TRACE3( "discard handshake packet %p (%u @ %p)", q, q->len, q->data ); next = q->next; free ( q->data ); free ( q ); } sess->handshake_queue = NULL; } if ( sess->handshake_digest.digest ) EVP_DigestUpdate( &sess->handshake_digest, data, len ); } }