Beispiel #1
0
int DSSL_SessionProcessData( DSSL_Session* sess, NM_PacketDir dir, u_char* data, uint32_t len )
{
	int rc = DSSL_RC_OK;
	dssl_decoder_stack* dec = NULL;

	if( dir == ePacketDirInvalid ) return NM_ERROR( DSSL_E_INVALID_PARAMETER );

	dec = (dir == ePacketDirFromClient) ? &sess->c_dec : &sess->s_dec;

	if( !sslc_is_decoder_stack_set( dec ) )
	{
		uint16_t ver = 0;
		int is_client = (dir == ePacketDirFromClient);
		if( is_client )
		{
			rc = ssl_detect_client_hello_version( data, len, &ver );
		}
		else
		{
			rc = ssl_detect_server_hello_version( data, len, &ver );
			/* update the client decoder after the server have declared the actual version 
			of the session */
			DEBUG_TRACE2("DSSL_SessionProcessData - sess->version: 0x%02X, ver is: 0x%02X\n", sess->version, ver);
			if( rc == DSSL_RC_OK && sess->version != ver )
			{
				sess->c_dec.version = ver;
				rc = dssl_decoder_stack_set( &sess->c_dec, sess, ver, 1 );
			}
			ssls_set_session_version( sess, ver );
		}

		if( rc == DSSL_RC_OK ) 
		{
			dec->version = ver;
			rc = dssl_decoder_stack_set( dec, sess, ver, is_client );
		}
	}

	if( rc == DSSL_RC_OK ) rc = dssl_decoder_stack_process( dec, dir, data, len );

	/* check if a session with a first-time automapped key failed */
	if( NM_IS_FAILED( rc ) && sess->flags & SSF_TEST_SSL_KEY )
	{
		if(sess->event_callback)
		{
			(*sess->event_callback)( sess->user_data, eSslMappedKeyFailed, sess->ssl_si );
		}
		DSSL_MoveServerToMissingKeyList( sess->env, sess->ssl_si );
		sess->ssl_si = NULL;
	}

	if( NM_IS_FAILED( rc ) && sess->error_callback && rc != DSSL_E_SSL_SERVER_KEY_UNKNOWN )
	{
		sess->error_callback( sess->user_data, rc );
	}

	return rc;
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}