Example #1
0
int ssl_detect_server_hello_version( u_char* data, uint32_t len, uint16_t* ver )
{
	int rc = DSSL_RC_OK;

	_ASSERT( ver != NULL );
	_ASSERT( data != NULL );
	
	if( data[0] & 0x80 && len >= SSL20_SERVER_HELLO_MIN_LEN && data[2] == SSL2_MT_SERVER_HELLO )
	{
		*ver = MAKE_UINT16( data[5], data[6] );
	}
	else if( data[0] == SSL3_RT_HANDSHAKE && len > 11 && 
		data[1] == SSL3_VERSION_MAJOR && data[5] == SSL3_MT_SERVER_HELLO )
	{
		uint16_t sever_hello_ver = MAKE_UINT16( data[9], data[10] );
		*ver = MAKE_UINT16( data[1], data[2] );

		if( *ver > sever_hello_ver ) rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
	}
	else if( data[0] == SSL3_RT_ALERT && len == 7 && data[1] == SSL3_VERSION_MAJOR &&
			MAKE_UINT16( data[3], data[4] ) == 2 )
	{
		/* this is an SSL3 Alert message - the server didn't like this session */
		*ver = MAKE_UINT16( data[1], data[2] );
	}
	else
	{
		rc = NM_ERROR( DSSL_E_SSL_UNKNOWN_VERSION );
	}

	return rc;
}
Example #2
0
int ssl_detect_client_hello_version( u_char* data, uint32_t len, uint16_t* ver )
{
	int rc = DSSL_RC_OK;

	_ASSERT( ver != NULL );
	_ASSERT( data != NULL );

	/* SSL v2 header can be sent even by never clients */
	if( data[0] & 0x80 && len >= 3 && data[2] == SSL2_MT_CLIENT_HELLO )
	{
		*ver = MAKE_UINT16( data[3], data[4] );
	}
	else if ( data[0] == SSL3_RT_HANDSHAKE && len > 11 && 
		data[1] == SSL3_VERSION_MAJOR && data[5] == SSL3_MT_CLIENT_HELLO )
	{
		uint16_t client_hello_ver = MAKE_UINT16( data[9], data[10] );
		*ver = MAKE_UINT16( data[1], data[2] );

		if( *ver > client_hello_ver ) rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
	}
	else
	{
		rc = NM_ERROR( DSSL_E_SSL_UNKNOWN_VERSION );
	}

	return rc;
}
Example #3
0
int ssl3_alert_decoder( void* decoder_stack, NM_PacketDir dir,
		u_char* data, uint32_t len, uint32_t* processed )
{
	dssl_decoder_stack* stack = (dssl_decoder_stack*) decoder_stack;

	UNUSED_PARAM(dir);

	if( len != 2 ) return NM_ERROR( NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ) );

	if( data[0] == 2 )
	{
		stack->state = SS_FatalAlert;
	}

	/* Close notify? */
	if( data[1] == 0 )
	{
		stack->state = SS_SeenCloseNotify;
	}

#ifdef NM_TRACE_SSL_RECORD
	DEBUG_TRACE2( "\nAlert received: %s (%d)", 
			( (stack->state == SS_FatalAlert) ? "fatal alert" : 
			((stack->state == SS_SeenCloseNotify) ? "close_notify alert" : "unknown alert")), 
			(int) MAKE_UINT16( data[0], data[1] ) );
#endif

		(*processed) = len;
	return DSSL_RC_OK;
}
Example #4
0
static int ssl3_decode_new_session_ticket(DSSL_Session* sess, u_char* data, uint32_t len )
{
	uint16_t sz = 0;
	if(len < 6) return NM_ERROR(DSSL_E_SSL_INVALID_RECORD_LENGTH);

	sz = MAKE_UINT16(data[4], data[5]);

	if(len != sz + 6) return NM_ERROR(DSSL_E_SSL_PROTOCOL_ERROR);

	return ssls_store_new_ticket( sess, data + 6, sz );
}
Example #5
0
int ssl3_record_layer_decoder( void* decoder_stack, NM_PacketDir dir,
		u_char* data, uint32_t len, uint32_t* processed )
{
	int rc = DSSL_E_UNSPECIFIED_ERROR;
	uint32_t recLen = 0, totalRecLen = 0;
	uint8_t record_type = 0;
	dssl_decoder_stack* stack = (dssl_decoder_stack*) decoder_stack;
	dssl_decoder* next_decoder = NULL;
	int decrypt_buffer_aquired = 0;
	int decompress_buffer_aquired = 0;

	_ASSERT( stack );
	_ASSERT( processed );
	_ASSERT( stack->sess );

	if( stack->state > SS_Established )
	{
#ifdef NM_TRACE_SSL_RECORD
		DEBUG_TRACE1( "[!]Unexpected SSL record after %s", 
			( (stack->state == SS_FatalAlert) ? "fatal alert" : "close_notify alert") );
#endif
		return NM_ERROR( DSSL_E_SSL_UNEXPECTED_TRANSMISSION );
	}

	/* special case for a first client hello */
	if( stack->sess->version == 0 )
	{
		_ASSERT( dir == ePacketDirFromClient );
		rc = ssl_decode_first_client_hello( stack->sess, data, len, processed );
		return rc;
	}

	if( len < SSL3_HEADER_LEN ) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	if( data[1] != 3) return NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );

	/* Decode record type */
	record_type = data[0];
	totalRecLen = recLen = MAKE_UINT16( data[3], data[4] );

	data += SSL3_HEADER_LEN;
	len -= SSL3_HEADER_LEN;

#ifdef NM_TRACE_SSL_RECORD
	DEBUG_TRACE3( "\n==>Decoding SSL v3 Record from %s, type: %d, len: %d\n{\n", ((dir == ePacketDirFromClient)?"client":"server"), (int) record_type, (int) recLen );
#endif

	rc = DSSL_RC_OK;
	if( len < recLen ) { rc = DSSL_RC_WOULD_BLOCK; }

	if( rc == DSSL_RC_OK && stack->cipher )
	{
		rc = ssl_decrypt_record( stack, data, recLen, &data, &recLen, &decrypt_buffer_aquired );
	}

	/* check if the record length is still within bounds (failed decryption, etc) */
	if( rc == DSSL_RC_OK && (recLen > RFC_2246_MAX_COMPRESSED_LENGTH || 
		recLen > len || (stack->sess->version < TLS1_2_VERSION && stack->md && recLen < EVP_MD_size(stack->md))) )
	{
		rc = NM_ERROR(DSSL_E_SSL_INVALID_RECORD_LENGTH);
	}

	if( rc == DSSL_RC_OK && stack->md )
	{
		u_char mac[EVP_MAX_MD_SIZE*2];
		u_char* rec_mac = NULL;
		int l = EVP_MD_size( stack->md );
		int ivl = EVP_CIPHER_iv_length( stack->cipher->cipher );

		if ( EVP_CIPH_CBC_MODE == stack->sess->cipher_mode || EVP_CIPH_STREAM_CIPHER == stack->sess->cipher_mode )
			recLen -= l;
		rec_mac = data+recLen;

		memset(mac, 0, sizeof(mac) );
		
		/* TLS 1.1 and later: remove explicit IV for non-stream ciphers */
		if ( EVP_CIPH_CBC_MODE == stack->sess->cipher_mode )
		{
			if (stack->sess->version >= TLS1_1_VERSION )
			{
				if (ivl <= recLen) {
					recLen -= ivl;
					data += ivl;
				}
			}
		}

		/* AEAD ciphers have no mac */
		if ( EVP_CIPH_CBC_MODE == stack->sess->cipher_mode || EVP_CIPH_STREAM_CIPHER == stack->sess->cipher_mode )
		{
			rc = stack->sess->caclulate_mac_proc( stack, record_type, data, recLen, mac );

			if( rc == DSSL_RC_OK )
			{
				rc = memcmp( mac, rec_mac, l ) == 0 ? DSSL_RC_OK : NM_ERROR( DSSL_E_SSL_INVALID_MAC );
			}
		}
	}

	if( rc == DSSL_RC_OK && stack->compression_method != 0 )
	{
		rc = ssl_decompress_record( stack, data, recLen, &data, &recLen, &decompress_buffer_aquired );
	}
	
	DEBUG_TRACE_BUF("decompressed", data, recLen);

	if( rc == DSSL_RC_OK )
	{
		switch( record_type )
		{
			case SSL3_RT_HANDSHAKE:
				next_decoder = &stack->dhandshake;
				break;

			case SSL3_RT_CHANGE_CIPHER_SPEC:
				next_decoder = &stack->dcss;
				break;

			case SSL3_RT_APPLICATION_DATA:
				next_decoder = &stack->dappdata;
				break;
			case SSL3_RT_ALERT:
				next_decoder = &stack->dalert;
				break;

			default:
				rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
		}
	}

	if( rc == DSSL_RC_OK )
	{
		_ASSERT( next_decoder != NULL );
		rc = dssl_decoder_process( next_decoder, dir, data, recLen );
	}

	if( rc == DSSL_RC_OK )
	{
		*processed = totalRecLen + SSL3_HEADER_LEN;
	}

	if( decrypt_buffer_aquired )
	{
		ssls_release_decrypt_buffer( stack->sess );
	}

	if( decompress_buffer_aquired )
	{
		ssls_release_decompress_buffer( stack->sess );
	}

#ifdef NM_TRACE_SSL_RECORD
	DEBUG_TRACE1( "\n} rc: %d\n", (int) rc);
#endif

	if( stack->state == SS_SeenCloseNotify )
	{
		stack->sess->flags |= SSF_CLOSE_NOTIFY_RECEIVED;
	} else if ( stack->state == SS_FatalAlert )
	{
		stack->sess->flags |= SSF_FATAL_ALERT_RECEIVED;
	}

	return rc;
}
Example #6
0
int ssl3_record_layer_decoder( void* decoder_stack, NM_PacketDir dir,
		u_char* data, uint32_t len, uint32_t* processed )
{
	int rc = DSSL_E_UNSPECIFIED_ERROR;
	uint32_t recLen = 0, totalRecLen = 0;
	uint8_t record_type = 0;
	dssl_decoder_stack* stack = (dssl_decoder_stack*) decoder_stack;
	dssl_decoder* next_decoder = NULL;
	int decrypt_buffer_aquired = 0;
	int decompress_buffer_aquired = 0;
	int i = 0;
	char * data2 = NULL;
	uint32_t recLen2 = 0;
	int block_size = 0;


	DEBUG_TRACE1("ssl_record_layer_decoder - start. len: %d\n", len);

	_ASSERT( stack );
	_ASSERT( processed );
	_ASSERT( stack->sess );

	/*
	for (i=0; i < len; i++)
	{
		printf("0x%02X ", data[i]);
	}
	*/

	if( stack->state > SS_Established )
	{
#ifdef NM_TRACE_SSL_RECORD
		DEBUG_TRACE1( "[!]Unexpected SSL record after %s", 
			( (stack->state == SS_FatalAlert) ? "fatal alert" : "close_notify alert") );
#endif
		return NM_ERROR( DSSL_E_SSL_UNEXPECTED_TRANSMISSION );
	}

	/* special case for a first client hello */
	DEBUG_TRACE1("ssl_record_layer_decoder - version: 0x%02X\n", stack->sess->version);
	if( stack->sess->version == 0 )
	{
		_ASSERT( dir == ePacketDirFromClient );
		rc = ssl_decode_first_client_hello( stack->sess, data, len, processed );
		return rc;
	}

	if( len < SSL3_HEADER_LEN ) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	if( data[1] != 3) return NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );

	/* Decode record type */
	record_type = data[0];
	totalRecLen = recLen = MAKE_UINT16( data[3], data[4] );
	DEBUG_TRACE1("ssl_record_layer_decoder - record_type: %d\n", record_type);
	DEBUG_TRACE1("ssl_record_layer_decoder - recLen: %d\n", recLen);

	/*
	for (i = 0; i < 128; i++)
	{
		printf("ssl_tls_record_layer_decoder - data before skip header size [%d]: %d\n", i, data[i]);
	}
	*/

	data += SSL3_HEADER_LEN;
	len -= SSL3_HEADER_LEN;

	DEBUG_TRACE1("ssl_record_layer_decoder - len after header adjustments: %d\n", len);
	/*
	for (i=0; i < len; i++)
	{
		printf("0x%02X ", data[i]);
	}
	*/

#ifdef NM_TRACE_SSL_RECORD
	DEBUG_TRACE2( "\n==>Decoding SSL v3 Record, type: %d, len: %d\n{\n", (int) record_type, (int) recLen );
#endif

	rc = DSSL_RC_OK;
	if( len < recLen ) 
	{ 
		rc = DSSL_RC_WOULD_BLOCK; 
		DEBUG_TRACE0("ssl_tls_record_layer_decoder - rc is DSSL_RC_WOULD_BLOCK\n");
	}

	if( rc == DSSL_RC_OK && stack->cipher )
	{
		rc = ssl_decrypt_record( stack, data, recLen, &data, &recLen, &decrypt_buffer_aquired,&block_size );

		DEBUG_TRACE1("ssl_record_layer_decoder - ssl_decrypt_record ret: %d\n", rc);
	}

	/* check if the record length is still within bounds (failed decryption, etc) */
	if( rc == DSSL_RC_OK && (recLen > RFC_2246_MAX_COMPRESSED_LENGTH || 
		recLen > len || (stack->md && recLen < EVP_MD_size(stack->md))) )
	{
		rc = NM_ERROR(DSSL_E_SSL_INVALID_RECORD_LENGTH);
	}

	if( rc == DSSL_RC_OK && stack->md )
	{
		u_char mac[EVP_MAX_MD_SIZE];
		u_char* rec_mac = NULL;
		
		DEBUG_TRACE1("ssl_record_layer_decoder - data using len: %d\n", len);
		/*
		for (i=0; i < len; i++)
		{
			printf("0x%02X ", data[i]);
		}
		*/

		recLen -= EVP_MD_size( stack->md );
		rec_mac = data+recLen;

		memset(mac, 0, sizeof(mac) );
		
		// Fix - skip iv for TLS 1.1
		DEBUG_TRACE1("ssl_record_layer_decoder - stack->version: 0x%02X\n", stack->version);
		DEBUG_TRACE1("ssl_record_layer_decoder - block_size: %d\n", block_size);

		if (stack->version > TLS1_VERSION && block_size > 1)
		{
			DEBUG_TRACE0("ssl_record_layer_decoder - activated fix for TLS 1.1 (skip 16 bytes)\n");

			data2 = data + block_size;
			recLen2 = recLen - block_size;
			rc = stack->sess->caclulate_mac_proc( stack, record_type, data2, recLen2, mac );
		}
		else
		{
			rc = stack->sess->caclulate_mac_proc( stack, record_type, data, recLen, mac );
		}

		DEBUG_TRACE1("ssl_record_layer_decoder - caclulate_mac_proc result: %d\n", rc);
		
		if( rc == DSSL_RC_OK )
		{
			DEBUG_TRACE1("ssl_record_layer_decoder - caclulate_mac_proc memcmp size(i.e. EVP_MD_size(stack->md)): %d\n", EVP_MD_size(stack->md));
			DEBUG_TRACE0("ssl_record_layer_decoder - mac vs. rec_mac:\n");
			if (IsDebugEnabled())
			{
				for (i=0; i < EVP_MD_size(stack->md); i++)
				{
					DEBUG_TRACE2("0x%02X vs. 0x%02X\n", mac[i], rec_mac[i]);
				}
			}
			rc = memcmp( mac, rec_mac, EVP_MD_size(stack->md) ) == 0 ? DSSL_RC_OK : NM_ERROR( DSSL_E_SSL_INVALID_MAC );
		}
	}

	if( rc == DSSL_RC_OK && stack->compression_method != 0 )
	{
		rc = ssl_decompress_record( stack, data, recLen, &data, &recLen, &decompress_buffer_aquired );

		DEBUG_TRACE1("ssl_record_layer_decoder - ssl_decompress_record call ended. rc: %d\n", rc);
	}

	if( rc == DSSL_RC_OK )
	{
		DEBUG_TRACE1("ssl_record_layer_decoder - record_type: %d\n", record_type);
		switch( record_type )
		{
			case SSL3_RT_HANDSHAKE:
				DEBUG_TRACE0("ssl_record_layer_decoder - SSL3_RT_HANDSHAKE\n");
				next_decoder = &stack->dhandshake;
				break;

			case SSL3_RT_CHANGE_CIPHER_SPEC:
				DEBUG_TRACE0("ssl_record_layer_decoder - SSL3_RT_CHANGE_CIPHER_SPEC\n");
				next_decoder = &stack->dcss;
				break;

			case SSL3_RT_APPLICATION_DATA:
				DEBUG_TRACE0("ssl_record_layer_decoder - SSL3_RT_APPLICATION_DATA\n");
				next_decoder = &stack->dappdata;
				break;

			case SSL3_RT_ALERT:
				DEBUG_TRACE0("ssl_record_layer_decoder - SSL3_RT_ALERT\n");
				next_decoder = &stack->dalert;
				break;

			default:
				DEBUG_TRACE0("ssl_record_layer_decoder - record_type not found\n");
				rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
		}
	}

	if( rc == DSSL_RC_OK )
	{
		_ASSERT( next_decoder != NULL );
		
		DEBUG_TRACE1("ssl_record_layer_decoder - calling dssl_decoder_process. handler is: %x\n", next_decoder->handler);
		
		// Fix - for TLS 1.1 continue
		if (data2 == NULL)
			rc = dssl_decoder_process( next_decoder, dir, data, recLen );
		else
			rc = dssl_decoder_process( next_decoder, dir, data2, recLen2 );

		DEBUG_TRACE1("ssl_record_layer_decoder - dssl_decoder_process ret: %d\n", rc);
	}

	if( rc == DSSL_RC_OK )
	{
		*processed = totalRecLen + SSL3_HEADER_LEN;
	}

	if( decrypt_buffer_aquired )
	{
		ssls_release_decrypt_buffer( stack->sess );
	}

	if( decompress_buffer_aquired )
	{
		ssls_release_decompress_buffer( stack->sess );
	}

#ifdef NM_TRACE_SSL_RECORD
	DEBUG_TRACE1( "\n} rc: %d\n", (int) rc);
#endif

	if( stack->state == SS_SeenCloseNotify )
	{
		stack->sess->flags |= SSF_CLOSE_NOTIFY_RECEIVED;
	} else if ( stack->state == SS_FatalAlert )
	{
		stack->sess->flags |= SSF_FATAL_ALERT_RECEIVED;
	}

	DEBUG_TRACE1("ssl_record_layer_decoder - end. rc = %d\n", rc);

	return rc;
}
Example #7
0
static int ssl3_decode_client_hello( DSSL_Session* sess, u_char* data, uint32_t len )
{
	u_char* org_data = data;
	int t_len = 0;

	/* record the handshake start time */
	sess->handshake_start = sess->last_packet->pcap_header.ts;

	if( data[0] != 3 || data[1] > 3) return NM_ERROR( DSSL_E_SSL_UNKNOWN_VERSION );

	/* 2 bytes client version */
	sess->client_version = MAKE_UINT16( data[0], data[1] );
	ssls_set_session_version( sess, MAKE_UINT16( data[0], data[1] ) );

	data+= 2;

	/* make sure */
	if( data + 32 > org_data + len ) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );

	/* 32 bytes ClientRandom */
	memcpy( sess->client_random, data, 32 );
	data+= 32;
	DEBUG_TRACE_BUF("client_random", sess->client_random, 32);

	/* check session ID length */
	if( data[0] > 32 ) return NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );

	if( data[0] > 0 )
	{
		/* Session ID set */
		if( data + data[0] > org_data + len ) 
			return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );

		memcpy( sess->session_id, data+1, data[0] );
		sess->flags |= SSF_CLIENT_SESSION_ID_SET;

		data += data[0] + 1;
	}
	else
	{
		/* no Session ID */
		sess->flags &= ~SSF_CLIENT_SESSION_ID_SET;
		++data;
	}

	/* Cypher Suites */
	if(data + 1 >= org_data + len) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	t_len = MAKE_UINT16(data[0], data[1]) + 2; /* cypher suites + cypher sute length size */

	data += t_len; /* skip cypher suites */

	/* Compression Method */
	if(data >= org_data + len) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	if(data + data[0] + 1 > org_data + len) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	t_len = data[0] + 1;

	data += t_len; /* skip compression methods */

	/* Extensions */

	/* clear all previous extension fields */
	ssls_free_extension_data(sess);

	if(data >= org_data + len) return DSSL_RC_OK;

	if(data + 2 > org_data + len) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	t_len = MAKE_UINT16(data[0], data[1]);

	data += 2; /* positon at the beginning of the first extension record, if any*/

	while(t_len >= 4)
	{
		int ext_type = MAKE_UINT16(data[0], data[1]); /* extension type */
		int ext_len = MAKE_UINT16(data[2], data[3]);
		#ifdef NM_TRACE_SSL_HANDSHAKE
			DEBUG_TRACE2( "\nSSL extension: %s len: %d", SSL3_ExtensionTypeToString( ext_type ), ext_len );
		#endif

		/* TLS Session Ticket */
		if( ext_type == 0x0023)
		{
			/* non empty ticket passed, store it */
			if(ext_len > 0)
			{
				sess->flags |= SSF_TLS_SESSION_TICKET_SET;
				sess->session_ticket = (u_char*) malloc(ext_len);
				if(sess->session_ticket == NULL) return NM_ERROR(DSSL_E_OUT_OF_MEMORY);
				memcpy(sess->session_ticket, data+4, ext_len);
				sess->session_ticket_len = ext_len;
			}
		}

		data += ext_len + 4;
		if(data > org_data + len) return NM_ERROR(DSSL_E_SSL_INVALID_RECORD_LENGTH);
		t_len -= ext_len + 4;
	}

	return DSSL_RC_OK;
}
Example #8
0
/* ========= ClientKeyExchange ========= */
int ssl3_decode_client_key_exchange( DSSL_Session* sess, u_char* data, uint32_t len )
{
	EVP_PKEY *pk = NULL;
	u_char* org_data = data;
	uint32_t org_len = len;
	int pms_len = 0;
	int rc = DSSL_RC_OK;

	if( sess->version < SSL3_VERSION || sess->version > TLS1_2_VERSION )
	{
		return NM_ERROR( DSSL_E_SSL_UNKNOWN_VERSION );
	}

	/* 
	TLS is different as it sends the record length, while SSL3 implementaions don't
	(due to a bug in Netscape implementation)
	*/
	if( sess->version > SSL3_VERSION )
	{
		uint16_t recLen = 0;
		if( !IS_ENOUGH_LENGTH( org_data, org_len, data, 2 ) ) 
		{
			return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
		}

		recLen = MAKE_UINT16( data[0], data[1] );
		if( len != (uint32_t)recLen + 2 )
		{
			/*TODO: set an option to tolerate this bug?*/
			return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
		}

		/* advance */
		data += len - recLen;
		len = recLen;
	}

	if( !IS_ENOUGH_LENGTH( org_data, org_len, data, SSL_MAX_MASTER_KEY_LENGTH ) )
	{
		return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	}

	pk = ssls_get_session_private_key( sess );

	/* if SSL server key is not found, try to find a matching one from the key pool */
	if(pk == NULL) 
	{
		_ASSERT( sess->last_packet);
		pk = ssls_try_ssl_keys( sess, data, len );

		/* if a matching key found, register it with the server IP:port */
		if(pk != NULL)
		{
			if( ssls_register_ssl_key( sess, pk ) == DSSL_RC_OK)
			{
				/* ssls_register_ssl_key clones the key, query the key back */
				pk = ssls_get_session_private_key( sess );
			}
			else
			{
				pk = NULL;
			}
		}
	}

	if(!pk) 
	{
		ssls_register_missing_key_server( sess );
		return NM_ERROR( DSSL_E_SSL_SERVER_KEY_UNKNOWN );
	}

	if(pk->type != EVP_PKEY_RSA) return NM_ERROR( DSSL_E_SSL_CANNOT_DECRYPT_NON_RSA );

	pms_len = RSA_private_decrypt( len, data, sess->PMS, pk->pkey.rsa, RSA_PKCS1_PADDING );

	if( pms_len != SSL_MAX_MASTER_KEY_LENGTH )
	{
		return NM_ERROR( DSSL_E_SSL_CORRUPTED_PMS );
	}

	if( MAKE_UINT16( sess->PMS[0], sess->PMS[1] ) != sess->client_version )
	{
		return NM_ERROR( DSSL_E_SSL_PMS_VERSION_ROLLBACK );
	}

	rc = ssls_decode_master_secret( sess );
	OPENSSL_cleanse(sess->PMS, sizeof(sess->PMS) );

	if( rc != DSSL_RC_OK ) return rc;

	rc = ssls_generate_keys( sess );
	if( rc == DSSL_RC_OK )
	{
		ssls_store_session( sess );
	}
	return rc;
}
Example #9
0
static int ssl3_decode_server_hello( DSSL_Session* sess, u_char* data, uint32_t len )
{
	uint16_t server_version = 0;
	u_char* org_data = data;
	uint16_t session_id_len = 0;
	int session_id_match = 0;

	if( data[0] != 3 || data[1] > 3) return NM_ERROR( DSSL_E_SSL_UNKNOWN_VERSION );
	if( len < SSL3_SERVER_HELLO_MIN_LEN ) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );

	/* Server Version */
	server_version = MAKE_UINT16( data[0], data[1] );
	if( sess->version == 0 || server_version < sess->version )
	{
		ssls_set_session_version( sess, server_version );
	}
	data+= 2;

	/* ServerRandom */
	_ASSERT_STATIC( sizeof(sess->server_random) == 32 );

	memcpy( sess->server_random, data, sizeof( sess->server_random ) );
	data+= 32;
	DEBUG_TRACE_BUF("server_random", sess->server_random, 32);


	/* session ID */
	_ASSERT_STATIC( sizeof(sess->session_id) == 32 );
	session_id_len = data[0];
	data++;

	if( session_id_len > 0 )
	{
		if ( session_id_len > 32 ) return NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );

		if( !IS_ENOUGH_LENGTH( org_data, len, data, session_id_len ) ) 
		{
			return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
		}

		if( sess->flags & SSF_CLIENT_SESSION_ID_SET 
			&& memcmp( sess->session_id, data, session_id_len ) == 0 )
		{
			session_id_match = 1;
		}
		else
		{
			sess->flags &= ~SSF_CLIENT_SESSION_ID_SET;
			memcpy( sess->session_id, data, session_id_len );
		}

		data += session_id_len;
	}

	/* Cipher Suite and Compression */
	if( !IS_ENOUGH_LENGTH( org_data, len, data, 3 ) ) 
	{
		return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
	}

	sess->cipher_suite = MAKE_UINT16( data[0], data[1] );
	sess->compression_method = data[2];

	data += 3;
	sess->flags &= ~SSF_TLS_SERVER_SESSION_TICKET; /* clear server side TLS Session Ticket flag */
	/* Process SSL Extensions, if present */
	if(IS_ENOUGH_LENGTH( org_data, len, data, 2 )) 
	{
		int t_len = MAKE_UINT16(data[0], data[1]);
		data += 2;
		if(!IS_ENOUGH_LENGTH( org_data, len, data, t_len)) 
			return NM_ERROR(DSSL_E_SSL_INVALID_RECORD_LENGTH);

		/* cycle through extension records */
		while(t_len >= 4)
		{
			int ext_type = MAKE_UINT16(data[0], data[1]); /* extension type */
			int ext_len = MAKE_UINT16(data[2], data[3]);
			#ifdef NM_TRACE_SSL_HANDSHAKE
				DEBUG_TRACE2( "\nSSL extension: %s len: %d", SSL3_ExtensionTypeToString( ext_type ), ext_len );
			#endif

			/* TLS Session Ticket extension found, set the flag */
			if( ext_type == 0x0023)
			{
				sess->flags |= SSF_TLS_SERVER_SESSION_TICKET;
			}

			data += ext_len + 4;
			if(data > org_data + len) return NM_ERROR(DSSL_E_SSL_INVALID_RECORD_LENGTH);
			t_len -= ext_len + 4;
		}
	}

	if( session_id_match )
	{
		if( sess->flags & SSF_TLS_SESSION_TICKET_SET)
		{
			int rc = ssls_init_from_tls_ticket( sess );
			if( NM_IS_FAILED( rc ) ) 
				return rc;
		}
		else
		{
			/* lookup session from the cache for stateful SSL renegotiation */
			int rc = ssls_lookup_session( sess );
			if( NM_IS_FAILED( rc ) ) 
				return rc;
		}
	}

	if( sess->flags & SSF_CLIENT_SESSION_ID_SET )
	{
		int rc = ssls_generate_keys( sess );
		if( NM_IS_FAILED( rc ) ) return rc;
	}

	return DSSL_RC_OK;
}
Example #10
0
/* ========== CLIENT-HELLO ========== */
static int ssl2_decode_client_hello( DSSL_Session* sess, u_char* data, uint32_t len, uint32_t* processed )
{
	int rc = DSSL_RC_OK;
	uint32_t sessionIdLen = 0, challengeLen = 0, cipherSpecLen = 0;

	_ASSERT( processed && data && sess );

	/* record the handshake start time */
	sess->handshake_start = sess->last_packet->pcap_header.ts;

	if( len < SSL20_CLIENT_HELLO_MIN_LEN ) return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); 

	if( data[0] == 0 && data[1] == 2 )
	{
		sess->client_version = SSL2_VERSION;
		rc = ssls_set_session_version( sess, SSL2_VERSION );
	}
	else if( data[0] == 3 ) 
	{
		/* SSLv3 or TLS1 in a v2 header */
		sess->client_version = MAKE_UINT16(data[0], data[1]);
		rc = ssls_set_session_version( sess, MAKE_UINT16(data[0], data[1]) );
	}
	else
	{
		rc = NM_ERROR( DSSL_E_SSL_UNKNOWN_VERSION );
	}

	/*	validate the record format */
	if( rc == DSSL_RC_OK )
	{
		/* CIPHER-SPECS-LENGTH */
		cipherSpecLen = MAKE_UINT16( data[2], data[3] );
		/* SESSION-ID-LENGTH */
		sessionIdLen = MAKE_UINT16( data[4], data[5] ); 
		/* CHALLENGE-LENGTH */
		challengeLen = MAKE_UINT16( data[6], data[7] ); 

		if( challengeLen + sessionIdLen + cipherSpecLen + SSL20_CLIENT_HELLO_MIN_LEN != len ) 
		{
			rc = NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
		}
	}

	/* validate and set the session ID */
	
	if( rc == DSSL_RC_OK )
	{
		if( sessionIdLen == 16 )
		{
			u_char* sessionId = data + SSL20_CLIENT_HELLO_MIN_LEN + cipherSpecLen;

			_ASSERT( sessionIdLen <= sizeof( sess->session_id ) );
			memset( sess->session_id, 0, sizeof( sess->session_id ) );
			memcpy( sess->session_id, sessionId, sessionIdLen );
			sess->flags |= SSF_CLIENT_SESSION_ID_SET;

		}
		else
		{
			sess->flags &= ~SSF_CLIENT_SESSION_ID_SET;
			if (sessionIdLen != 0 )
			{
				/* session ID length must be either 16 or 0 for SSL v2 */
				rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
			}
		}
	}

	/* validate and set the client random aka Challenge */
	if( rc == DSSL_RC_OK )
	{
		if( challengeLen < 16 || challengeLen > 32 )
		{
			rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
		}
		else
		{
			u_char* challenge = data + SSL20_CLIENT_HELLO_MIN_LEN + cipherSpecLen + sessionIdLen;
			_ASSERT( challengeLen <= sizeof( sess->client_random ) );
			memset( sess->client_random, 0, sizeof( sess->client_random ) );
			memcpy( sess->client_random,  challenge, challengeLen );
			sess->client_challenge_len = challengeLen;
			/* may need this flag later to convert CHALLENGE to SSL v3 CLIENT_RANDOM */
			sess->flags |= SSF_SSLV2_CHALLENGE;
		}
	}

	if( rc == DSSL_RC_OK ) { *processed = len; }

	return rc;
}
Example #11
0
/* ========== CLIENT-MASTER-KEY ========== */
static int ssl2_decode_client_master_key(  DSSL_Session* sess, u_char* data, uint32_t len, uint32_t* processed )
{
	int rc = DSSL_RC_OK;
	uint16_t clearKeyLen = 0;
	uint16_t encKeyLen = 0;
	uint16_t keyArgLen = 0;
	u_char* pClearKey = NULL;
	u_char* pEncKey = NULL;
	u_char* pKeyArg = NULL;

	_ASSERT( processed && data && sess );
	if( len < SSL20_CLIENT_MASTER_KEY_MIN_LEN ) { return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); }

	/* CIPHER-KIND - convert to 2 byte DSSL_Session::cipher_suite */
	rc = DSSL_ConvertSSL2CipherSuite( data, &sess->cipher_suite );

	/* CLEAR-KEY-LENGTH, ENCRYPTED-KEY-LENGTH, KEY-ARG-LENGTH */
	if( rc == DSSL_RC_OK )
	{
		clearKeyLen = MAKE_UINT16( data[3], data[4] );
		encKeyLen = MAKE_UINT16( data[5], data[6] );
		keyArgLen = MAKE_UINT16( data[7], data[8] );

		if( len != (uint32_t)clearKeyLen + encKeyLen + keyArgLen + SSL20_CLIENT_MASTER_KEY_MIN_LEN )
		{
			rc = NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
		}

		*processed = len;

	}
	
	/* reconstitute the master secret */
	if( rc == DSSL_RC_OK )
	{
		EVP_PKEY *pk = NULL;

		pClearKey = data + SSL20_CLIENT_MASTER_KEY_MIN_LEN;
		pEncKey = pClearKey + clearKeyLen;
		pKeyArg = pEncKey + encKeyLen;

		if( clearKeyLen ) { memcpy( sess->master_secret, pClearKey, clearKeyLen ); }

		pk = ssls_get_session_private_key( sess );
		
		/* if SSL server key is not found, try to find a matching one from the key pool */
		if(pk == NULL) 
		{
			u_char buff[1024];
			_ASSERT( sess->last_packet);

			memcpy(buff, pEncKey, encKeyLen);
			pk = ssls_try_ssl_keys( sess, pEncKey, encKeyLen );

			/* if a matching key found, register it with the server IP:port */
			if(pk != NULL)
			{
				if( ssls_register_ssl_key( sess, pk ) == DSSL_RC_OK)
				{
					/* ssls_register_ssl_key clones the key, query the key back */
					//pk = ssls_get_session_private_key( sess );
				}
				else
				{
					pk = NULL;
				}
			}
		}

		if( pk )
		{
			uint32_t encLen2 = RSA_private_decrypt( encKeyLen, pEncKey, 
					sess->master_secret + clearKeyLen, pk->pkey.rsa, RSA_PKCS1_PADDING );

			if( clearKeyLen + encLen2 >= sizeof( sess->master_secret ) )
			{
				rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
			}

			sess->master_key_len = clearKeyLen + encLen2;
		}
		else
		{
			rc = NM_ERROR( DSSL_E_SSL_SERVER_KEY_UNKNOWN );
			ssls_register_missing_key_server( sess );
		}
	}

	/* generate session keys */
	if( rc == DSSL_RC_OK )
	{
		rc = ssls2_generate_keys( sess, pKeyArg, keyArgLen );
	}

	/* turn on new ciphers */
	if( rc == DSSL_RC_OK ) 
	{
		rc = dssl_decoder_stack_flip_cipher( &sess->c_dec );
		if (rc == DSSL_RC_OK ) { rc = dssl_decoder_stack_flip_cipher( &sess->s_dec ); }
	}

	return rc;
}
Example #12
0
/* ========== SERVER-HELLO ========== */
static int ssl2_decode_server_hello( DSSL_Session* sess, u_char* data, uint32_t len, uint32_t* processed )
{
	int rc = DSSL_RC_OK;
	uint16_t certLen = 0;
	uint16_t cipherSpecLen = 0;
	uint16_t connectionIdLen = 0;
	int session_id_hit = 0;

	_ASSERT( processed && data && sess );

	if( len < SSL20_SERVER_HELLO_MIN_LEN ) { return NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH ); }

	/* check SESSION-ID-HIT */
	session_id_hit = data[0];

	/* decode CERTIFICATE-TYPE */
	if( rc == DSSL_RC_OK && (data[1] && data[1] != SSL2_CT_X509_CERTIFICATE) ) 
	{
		rc = NM_ERROR( DSSL_E_SSL2_INVALID_CERTIFICATE_TYPE ); 
	}

	/* SERVER-VERSION*/	 /* TODO: add server version check */

	/* CERTIFICATE-LENGTH, CIPHER-SPECS-LENGTH, CONNECTION-ID-LENGTH */
	if( rc == DSSL_RC_OK )
	{
		certLen = MAKE_UINT16( data[4], data[5] );
		cipherSpecLen = MAKE_UINT16( data[6], data[7] );
		connectionIdLen = MAKE_UINT16( data[8], data[9] );

		if( (uint32_t)certLen + cipherSpecLen + connectionIdLen + SSL20_SERVER_HELLO_MIN_LEN != len )
		{
			rc = NM_ERROR( DSSL_E_SSL_INVALID_RECORD_LENGTH );
		}
		else if( connectionIdLen < 16 || connectionIdLen > 32 )
		{
			rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
		}

		if( rc == DSSL_RC_OK ) 
		{
			u_char* connIdData = data + SSL20_SERVER_HELLO_MIN_LEN + certLen + cipherSpecLen;
			sess->server_connection_id_len = connectionIdLen; 
			memset( sess->server_random, 0, sizeof(sess->server_random) );
			memcpy( sess->server_random, connIdData, connectionIdLen );
		}
	}

	/* TODO: Check the certificate to match what DSSL has been initialized with */
	if( rc == DSSL_RC_OK )
	{
	}

	if( session_id_hit )
	{
		if( sess->flags & SSF_CLIENT_SESSION_ID_SET )
		{
			rc = ssls_lookup_session( sess );
			/* re-generate the session keys and turn on ciphers right away */
			if( rc == DSSL_RC_OK)
			{
				rc = ssls2_generate_keys( sess, sess->ssl2_key_arg, sess->ssl2_key_arg_len );
			}
			/* turn on new ciphers */
			if( rc == DSSL_RC_OK ) 
			{
				rc = dssl_decoder_stack_flip_cipher( &sess->c_dec );
				if (rc == DSSL_RC_OK ) { rc = dssl_decoder_stack_flip_cipher( &sess->s_dec ); }
			}
		}
		else
		{
			/* client didn't send the session id */
			rc = NM_ERROR( DSSL_E_SSL_PROTOCOL_ERROR );
		}
	}


	if( rc == DSSL_RC_OK )
	{
		*processed = certLen + cipherSpecLen + connectionIdLen + SSL20_SERVER_HELLO_MIN_LEN;
	}

	return rc;
}