eapol/eapol_framework/eapol_common/type/tls_peap/tls/src/tls_handshake_message.cpp
changeset 0 c8830336c852
child 2 1c7bc153c08e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eapol/eapol_framework/eapol_common/type/tls_peap/tls/src/tls_handshake_message.cpp	Thu Dec 17 08:47:43 2009 +0200
@@ -0,0 +1,1611 @@
+/*
+* Copyright (c) 2001-2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  EAP and WLAN authentication protocols.
+*
+*/
+
+
+// This is enumeration of EAPOL source code.
+#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
+	#undef EAP_FILE_NUMBER_ENUM
+	#define EAP_FILE_NUMBER_ENUM 130 
+	#undef EAP_FILE_NUMBER_DATE 
+	#define EAP_FILE_NUMBER_DATE 1127594498 
+#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
+
+
+
+#include "eap_tools.h"
+#include "eap_array.h"
+#include "eap_array_algorithms.h"
+#include "tls_handshake_message.h"
+#include "tls_record_header.h"
+#include "eap_crypto_api.h"
+#include "eap_automatic_variable.h"
+
+/** @file */
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT tls_handshake_message_c::~tls_handshake_message_c()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT tls_handshake_message_c::tls_handshake_message_c(
+	abs_eap_am_tools_c * const tools,
+	abs_tls_message_hash_c * const message_hash,
+	const bool is_client)
+: m_am_tools(tools)
+, m_message_hash(message_hash)
+, m_tls_handshake_message_buffer(tools)
+, m_unix_time(tools)
+, m_random_value(tools)
+, m_session_id(tools)
+, m_cipher_suites(tools)
+, m_compression_methods(tools)
+#if defined(USE_EAP_TLS_SESSION_TICKET)
+, m_tls_extensions(tools)
+#endif // #if defined(USE_EAP_TLS_SESSION_TICKET)
+, m_certificate_chain(tools)
+, m_certificate_authorities(tools)
+, m_certificate_types(tools)
+, m_encrypted_premaster_secret(tools)
+, m_public_dhe_key(tools)
+, m_dhe_prime(tools)
+, m_dhe_group_generator(tools)
+, m_signed_message_hash(tools)
+, m_finished_data(tools)
+, m_selected_cipher_suite(tls_cipher_suites_none)
+, m_selected_compression_method(tls_compression_method_none)
+, m_handshake_type(tls_handshake_type_none)
+, m_is_analysed(false)
+, m_is_valid(false)
+, m_is_client(is_client)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	set_is_valid();
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void tls_handshake_message_c::set_is_valid()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	m_is_valid = true;
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool tls_handshake_message_c::get_is_valid()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return m_is_valid;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void tls_handshake_message_c::set_is_analysed()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	m_is_analysed = true;
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool tls_handshake_message_c::get_is_analysed()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return m_is_analysed;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_handshake_type(tls_handshake_type_e type)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	m_handshake_type = type;
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_handshake_header_copy(
+	const tls_handshake_header_c * const tls_handshake_header)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	m_handshake_type = tls_handshake_header->get_handshake_type();
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT tls_handshake_type_e tls_handshake_message_c::get_handshake_type() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return m_handshake_type;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_cipher_suites(
+	EAP_TEMPLATE_CONST eap_array_c<u16_t> * const cipher_suites)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	m_cipher_suites.reset();
+
+	eap_status_e status = copy_simple<u16_t>(
+		cipher_suites,
+		&m_cipher_suites,
+		m_am_tools,
+		false);
+
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT EAP_TEMPLATE_CONST eap_array_c<u16_t> * tls_handshake_message_c::get_cipher_suites() EAP_TEMPLATE_CONST
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_cipher_suites;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_compression_methods(
+	EAP_TEMPLATE_CONST eap_array_c<u8_t> * const compression_methods)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = copy_simple<u8_t>(
+		compression_methods,
+		&m_compression_methods,
+		m_am_tools,
+		false);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT EAP_TEMPLATE_CONST eap_array_c<u8_t> * tls_handshake_message_c::get_compression_methods() EAP_TEMPLATE_CONST
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_compression_methods;
+}
+
+//--------------------------------------------------
+
+#if defined(USE_EAP_TLS_SESSION_TICKET)
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_tls_extensions(
+	EAP_TEMPLATE_CONST eap_array_c<tls_extension_c> * const tls_extensionss)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = copy<tls_extension_c>(
+		tls_extensionss,
+		&m_tls_extensions,
+		m_am_tools,
+		false);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif // #if defined(USE_EAP_TLS_SESSION_TICKET)
+
+//--------------------------------------------------
+
+#if defined(USE_EAP_TLS_SESSION_TICKET)
+
+EAP_FUNC_EXPORT EAP_TEMPLATE_CONST eap_array_c<tls_extension_c> * tls_handshake_message_c::get_tls_extensions() EAP_TEMPLATE_CONST
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_tls_extensions;
+}
+
+#endif // #if defined(USE_EAP_TLS_SESSION_TICKET)
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_random_value(
+	const eap_variable_data_c * const random_value)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_random_value.set_copy_of_buffer(random_value);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_random_value() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_random_value;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_session_id(
+	const eap_variable_data_c * const session_id)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_session_id.set_copy_of_buffer(session_id);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_session_id() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_session_id;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_certificate_chain(
+	EAP_TEMPLATE_CONST eap_array_c<eap_variable_data_c> * const certificate_chain)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = copy<eap_variable_data_c>(
+		certificate_chain,
+		&m_certificate_chain,
+		m_am_tools,
+		false);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT EAP_TEMPLATE_CONST eap_array_c<eap_variable_data_c> * tls_handshake_message_c::get_certificate_chain() EAP_TEMPLATE_CONST
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_certificate_chain;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_certificate_authorities(
+	EAP_TEMPLATE_CONST eap_array_c<eap_variable_data_c> * const certificate_authorities)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = copy<eap_variable_data_c>(
+		certificate_authorities,
+		&m_certificate_authorities,
+		m_am_tools,
+		false);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT EAP_TEMPLATE_CONST eap_array_c<eap_variable_data_c> * tls_handshake_message_c::get_certificate_authorities() EAP_TEMPLATE_CONST
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_certificate_authorities;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_certificate_types(
+	EAP_TEMPLATE_CONST eap_array_c<u8_t> * const certificate_types)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = copy_simple<u8_t>(
+		certificate_types,
+		&m_certificate_types,
+		m_am_tools,
+		false);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT EAP_TEMPLATE_CONST eap_array_c<u8_t> * tls_handshake_message_c::get_certificate_types() EAP_TEMPLATE_CONST
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_certificate_types;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_selected_cipher_suite(const tls_cipher_suites_e selected_cipher_suite)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	m_selected_cipher_suite = selected_cipher_suite;
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+EAP_FUNC_EXPORT tls_cipher_suites_e tls_handshake_message_c::get_selected_cipher_suite() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return m_selected_cipher_suite;
+}
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_selected_compression_method(const tls_compression_method_e selected_compression_method)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	m_selected_compression_method = selected_compression_method;
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+EAP_FUNC_EXPORT tls_compression_method_e tls_handshake_message_c::get_selected_compression_method() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return m_selected_compression_method;
+}
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_public_dhe_key(const eap_variable_data_c * const public_dhe_key)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_public_dhe_key.set_copy_of_buffer(public_dhe_key);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_public_dhe_key() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_public_dhe_key;
+}
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_encrypted_premaster_secret(const eap_variable_data_c * const encrypted_premaster_secret)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_encrypted_premaster_secret.set_copy_of_buffer(encrypted_premaster_secret);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_encrypted_premaster_secret() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_encrypted_premaster_secret;
+}
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_dhe_prime(const eap_variable_data_c * const dhe_prime)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_dhe_prime.set_copy_of_buffer(dhe_prime);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_dhe_prime() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_dhe_prime;
+}
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_dhe_group_generator(const eap_variable_data_c * const dhe_group_generator)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_dhe_group_generator.set_copy_of_buffer(dhe_group_generator);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_dhe_group_generator() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_dhe_group_generator;
+}
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_signed_message_hash(const eap_variable_data_c * const signed_message_hash)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_signed_message_hash.set_copy_of_buffer(signed_message_hash);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_signed_message_hash() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_signed_message_hash;
+}
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::set_finished_data(const eap_variable_data_c * const finished_data)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = m_finished_data.set_copy_of_buffer(finished_data);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+EAP_FUNC_EXPORT const eap_variable_data_c * tls_handshake_message_c::get_finished_data() const
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return &m_finished_data;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::u16_t_to_network_order(
+	u16_t * const value,
+	abs_eap_am_tools_c * const m_am_tools)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_UNREFERENCED_PARAMETER(m_am_tools);
+
+	*value = eap_htons(*value);
+
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::create_message_data()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status = eap_status_ok;
+
+	m_tls_handshake_message_buffer.reset();
+	status = m_tls_handshake_message_buffer.set_buffer_length(TLS_PEAP_DEFAULT_RECORD_LENGTH);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	const u32_t offset_of_tmp_tls_handshake_header = m_tls_handshake_message_buffer.get_data_length();
+
+	m_tls_handshake_message_buffer.set_data_length(
+		m_tls_handshake_message_buffer.get_data_length() + tls_handshake_header_c::get_header_length());
+
+	tls_handshake_header_c tmp_tls_handshake_header_on_tls_message_buffer(
+		m_am_tools,
+		m_tls_handshake_message_buffer.get_data_offset(
+		offset_of_tmp_tls_handshake_header, tls_handshake_header_c::get_header_length()),
+		tls_handshake_header_c::get_header_length());
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_too_long_message);
+	}
+
+	tmp_tls_handshake_header_on_tls_message_buffer.reset_header(0ul);
+	tmp_tls_handshake_header_on_tls_message_buffer.set_handshake_type(get_handshake_type());
+
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n")));
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TLS: %s: data_function: tls_handshake_message_c::create_message_data(): %s\n"),
+		(m_is_client == true ? "client": "server"),
+		tmp_tls_handshake_header_on_tls_message_buffer.get_tls_handshake_string()));
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TLS-handshake tls_handshake_header"),
+		 tmp_tls_handshake_header_on_tls_message_buffer.get_header_buffer(
+			 tls_handshake_header_c::get_header_length()),
+		 tls_handshake_header_c::get_header_length()));
+
+	const u32_t handshake_data_length_start = m_tls_handshake_message_buffer.get_data_length();
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_client_hello
+		|| tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_hello)
+	{
+		u16_t version = eap_htons(tls_version_3_1);
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&version,
+			sizeof(version));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake version"),
+			&version,
+			sizeof(version)));
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_client_hello
+		|| tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_hello)
+	{
+		if (m_random_value.get_is_valid_data() == false)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+		}
+		else
+		{
+			status = m_tls_handshake_message_buffer.add_data(
+				m_random_value.get_data(m_random_value.get_data_length()),
+				m_random_value.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake random"),
+				m_random_value.get_data(m_random_value.get_data_length()),
+				m_random_value.get_data_length()));
+		}
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_client_hello
+		|| tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_hello)
+	{
+		u8_t session_id_length = 0ul;
+
+		if (m_session_id.get_is_valid_data() == true
+			&& m_session_id.get_data_length() > 0ul)
+		{
+			session_id_length = static_cast<u8_t>(m_session_id.get_data_length());
+		}
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&session_id_length,
+			sizeof(session_id_length));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake session_id_length"),
+			&session_id_length,
+			sizeof(session_id_length)));
+
+		if (m_session_id.get_is_valid_data() == true
+			&& m_session_id.get_data_length() > 0ul)
+		{
+			status = m_tls_handshake_message_buffer.add_data(
+				m_session_id.get_data(m_session_id.get_data_length()),
+				m_session_id.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake session_id"),
+				m_session_id.get_data(m_session_id.get_data_length()),
+				m_session_id.get_data_length()));
+		}
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_client_hello)
+	{
+		u16_t data_size = static_cast<u16_t>(m_cipher_suites.get_object_count() * sizeof(u16_t));
+		u16_t data_size_network_order = eap_htons(data_size);
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&data_size_network_order,
+			sizeof(data_size_network_order));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake cipher_suite_length"),
+			&data_size_network_order,
+			sizeof(data_size_network_order)));
+
+		if (m_cipher_suites.get_object_count() > 0ul)
+		{
+			// Copy cipher suites and change them to network order.
+			eap_array_c<u16_t> * const tmp_cipher_suites = new eap_array_c<u16_t>(m_am_tools);
+
+			eap_automatic_variable_c<eap_array_c<u16_t> > automatic_tmp_cipher_suites(m_am_tools, tmp_cipher_suites);
+
+			if (tmp_cipher_suites == 0)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+			}
+
+			status = copy_simple<u16_t>(
+				&m_cipher_suites,
+				tmp_cipher_suites,
+				m_am_tools,
+				false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			status = for_each<u16_t>(tmp_cipher_suites, u16_t_to_network_order, m_am_tools, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			status = add_simple_data(tmp_cipher_suites, &m_tls_handshake_message_buffer, m_am_tools);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_hello)
+	{
+		u16_t selected_cipher_suite_network_order = eap_htons(static_cast<u8_t>(m_selected_cipher_suite));
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&selected_cipher_suite_network_order,
+			sizeof(selected_cipher_suite_network_order));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake selected_cipher_suite"),
+			&selected_cipher_suite_network_order,
+			sizeof(selected_cipher_suite_network_order)));
+
+		u8_t selected_compression_method_network_order = static_cast<u8_t>(m_selected_compression_method);
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&selected_compression_method_network_order,
+			sizeof(selected_compression_method_network_order));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake selected_compression_method"),
+			&selected_compression_method_network_order,
+			sizeof(selected_compression_method_network_order)));
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_client_hello)
+	{
+		u8_t data_size = static_cast<u8_t>(m_compression_methods.get_object_count() * sizeof(u8_t));
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&data_size,
+			sizeof(data_size));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("TLS-handshake compression_methods length"),
+			&data_size,
+			sizeof(data_size)));
+
+		if (m_compression_methods.get_object_count() > 0ul)
+		{
+			status = add_simple_data(&m_compression_methods, &m_tls_handshake_message_buffer, m_am_tools);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+	}
+
+
+#if defined(USE_EAP_TLS_SESSION_TICKET)
+
+	if (m_tls_extensions.get_object_count() > 0
+		&& (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_client_hello
+			|| tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_hello))
+	{
+		u32_t data_size(0ul);
+		u32_t ind(0ul);
+		
+		for (ind = 0ul; ind < m_tls_extensions.get_object_count(); ++ind)
+		{
+			const tls_extension_c * const extension = m_tls_extensions.get_object(ind);
+			if (extension == 0)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+			}
+
+			// Session ticket is always empty in ServerHello message.
+			const bool add_extension_data =
+				((extension->get_type() == tls_extension_type_session_ticket
+					&& tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_hello))
+				== false;
+
+			// Extension list is formatted as:
+			// 0                   1                   2                   3   
+			//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+			//                                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+			//                                 | extension list length         |
+			// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+			// | extension 1 type              | extension 1 data length       |
+			// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+			// | extension 1 data ...
+			// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+			// | extension 2 type              | extension 2 data length       |
+			// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+			// | extension 2 data ...
+			// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+			data_size += 2 * sizeof(u16_t);
+
+			if (add_extension_data == true)
+			{
+				data_size += extension->get_data_length();
+			}
+
+		} // for()
+
+
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("TLS-handshake extensions list length = %d\n"),
+			data_size));
+
+		if (data_size > 0x0000ffff)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+		}
+
+		u8_t data_size_array[2];
+		data_size_array[0] = static_cast<u8_t>((data_size & 0x0000ff00) >> 8);
+		data_size_array[1] = static_cast<u8_t>(data_size & 0x000000ff);
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&data_size_array,
+			sizeof(data_size_array));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		for (ind = 0ul; ind < m_tls_extensions.get_object_count(); ++ind)
+		{
+			const tls_extension_c * const extension = m_tls_extensions.get_object(ind);
+			if (extension == 0)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+			}
+
+			// Session ticket is always empty in ServerHello message.
+			const bool add_extension_data =
+				((extension->get_type() == tls_extension_type_session_ticket
+					&& tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_hello))
+				== false;
+
+			tls_extension_type_e type = extension->get_type();
+			u16_t network_order_type(eap_htons(type));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&network_order_type,
+				sizeof(network_order_type));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+
+			if (add_extension_data == true)
+			{
+				data_size = extension->get_data_length();
+			}
+			else
+			{
+				data_size = 0ul;
+			}
+
+			data_size_array[0] = static_cast<u8_t>((data_size & 0x0000ff00) >> 8);
+			data_size_array[1] = static_cast<u8_t>(data_size & 0x000000ff);
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&data_size_array,
+				sizeof(data_size_array));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DEBUG(
+				m_am_tools,
+				TRACE_FLAGS_DEFAULT,
+				(EAPL("TLS-handshake extension type = %s, length = %d\n"),
+				extension->get_type_string(extension->get_type()),
+				data_size));
+
+			if (add_extension_data == true)
+			{
+				EAP_TRACE_DATA_DEBUG(
+					m_am_tools,
+					TRACE_FLAGS_DEFAULT,
+					(EAPL("TLS-handshake extension data"),
+					extension->get_data(),
+					extension->get_data_length()));
+
+				status = m_tls_handshake_message_buffer.add_data(
+					extension);
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+		} // for()
+	}
+
+#endif // #if defined(USE_EAP_TLS_SESSION_TICKET)
+
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_certificate)
+	{
+		u32_t data_size = 0ul;
+		u32_t ind = 0ul;
+
+		for (ind = 0ul; ind < m_certificate_chain.get_object_count(); ind++)
+		{
+			const eap_variable_data_c * const certificate =  m_certificate_chain.get_object(ind);
+			if (certificate == 0
+				|| certificate->get_is_valid_data() == false)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+			}
+
+			// Data size includes certificate length field and certificate data.
+			data_size += (3ul + certificate->get_data_length());
+		}
+
+		if (data_size > 0x00ffffff)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+		}
+
+		u8_t data_size_array[3];
+		data_size_array[0] = static_cast<u8_t>((data_size & 0x00ff0000) >> 16);
+		data_size_array[1] = static_cast<u8_t>((data_size & 0x0000ff00) >> 8);
+		data_size_array[2] = static_cast<u8_t>(data_size & 0x000000ff);
+
+		status = m_tls_handshake_message_buffer.add_data(
+			data_size_array,
+			sizeof(data_size_array));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake certificate_chain length"),
+			data_size_array,
+			sizeof(data_size_array)));
+
+
+		for (ind = 0ul; ind < m_certificate_chain.get_object_count(); ind++)
+		{
+			const eap_variable_data_c * const certificate =  m_certificate_chain.get_object(ind);
+			if (certificate == 0
+				|| certificate->get_is_valid_data() == false)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+			}
+
+			data_size = certificate->get_data_length();
+			u8_t data_size_array[3];
+			data_size_array[0] = static_cast<u8_t>((data_size & 0x00ff0000) >> 16);
+			data_size_array[1] = static_cast<u8_t>((data_size & 0x0000ff00) >> 8);
+			data_size_array[2] = static_cast<u8_t>(data_size & 0x000000ff);
+			
+			status = m_tls_handshake_message_buffer.add_data(
+				data_size_array,
+				sizeof(data_size_array));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake certificate length"),
+				data_size_array,
+				sizeof(data_size_array)));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				certificate->get_data(certificate->get_data_length()),
+				certificate->get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake certificate"),
+				certificate->get_data(certificate->get_data_length()),
+				certificate->get_data_length()));
+		}
+	}
+
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_server_key_exchange)
+	{
+		if (m_dhe_prime.get_is_valid_data() == true)
+		{
+			u16_t dhe_prime_length_network_order = eap_htons(static_cast<u16_t>(m_dhe_prime.get_data_length()));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&dhe_prime_length_network_order,
+				sizeof(dhe_prime_length_network_order));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake dhe_prime_length"),
+				&dhe_prime_length_network_order,
+				sizeof(dhe_prime_length_network_order)));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				m_dhe_prime.get_data(m_dhe_prime.get_data_length()),
+				m_dhe_prime.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake dhe_prime"),
+				m_dhe_prime.get_data(m_dhe_prime.get_data_length()),
+				m_dhe_prime.get_data_length()));
+		}
+		else if (m_dhe_group_generator.get_is_valid_data() == true
+			|| m_public_dhe_key.get_is_valid_data() == true
+			|| m_signed_message_hash.get_is_valid_data() == true)
+		{
+			// all parameters m_dhe_prime, m_dhe_group_generator and m_public_dhe_key are needed.
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+		}
+
+		if (m_dhe_group_generator.get_is_valid_data() == true)
+		{
+			u16_t dhe_group_generator_length_network_order = eap_htons(static_cast<u16_t>(m_dhe_group_generator.get_data_length()));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&dhe_group_generator_length_network_order,
+				sizeof(dhe_group_generator_length_network_order));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake dhe_group_generator_length"),
+				&dhe_group_generator_length_network_order,
+				sizeof(dhe_group_generator_length_network_order)));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				m_dhe_group_generator.get_data(m_dhe_group_generator.get_data_length()),
+				m_dhe_group_generator.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake dhe_group_generator"),
+				m_dhe_group_generator.get_data(m_dhe_group_generator.get_data_length()),
+				m_dhe_group_generator.get_data_length()));
+		}
+		else if (m_dhe_prime.get_is_valid_data() == true
+			|| m_public_dhe_key.get_is_valid_data() == true
+			|| m_signed_message_hash.get_is_valid_data() == true)
+		{
+			// all parameters m_dhe_prime, m_dhe_group_generator and m_public_dhe_key are needed.
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+		}
+
+		if (m_public_dhe_key.get_is_valid_data() == true)
+		{
+			u16_t public_dhe_key_length_network_order = eap_htons(static_cast<u16_t>(m_public_dhe_key.get_data_length()));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&public_dhe_key_length_network_order,
+				sizeof(public_dhe_key_length_network_order));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake public_dhe_key_length"),
+				&public_dhe_key_length_network_order,
+				sizeof(public_dhe_key_length_network_order)));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				m_public_dhe_key.get_data(m_public_dhe_key.get_data_length()),
+				m_public_dhe_key.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake public_dhe_key"),
+				m_public_dhe_key.get_data(m_public_dhe_key.get_data_length()),
+				m_public_dhe_key.get_data_length()));
+		}
+		else if (m_dhe_prime.get_is_valid_data() == true
+			|| m_dhe_group_generator.get_is_valid_data() == true
+			|| m_signed_message_hash.get_is_valid_data() == true)
+		{
+			// all parameters m_dhe_prime, m_dhe_group_generator and m_public_dhe_key are needed.
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+		}
+
+		if (m_signed_message_hash.get_is_valid_data() == true)
+		{
+			if (m_signed_message_hash.get_data_length() == 0)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+			}
+
+			status = m_tls_handshake_message_buffer.add_data(
+				m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()),
+				m_signed_message_hash.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake signed_message_hash"),
+				m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()),
+				m_signed_message_hash.get_data_length()));
+		}
+	}
+
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_client_key_exchange)
+	{
+		if (m_encrypted_premaster_secret.get_is_valid_data() == true)
+		{
+			u16_t length_of_encrypted_premaster_secret_network_order
+				= eap_htons(static_cast<u16_t>(m_encrypted_premaster_secret.get_data_length()));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&length_of_encrypted_premaster_secret_network_order,
+				sizeof(length_of_encrypted_premaster_secret_network_order));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake encrypted premaster_secret"),
+				&length_of_encrypted_premaster_secret_network_order,
+				sizeof(length_of_encrypted_premaster_secret_network_order)));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				m_encrypted_premaster_secret.get_data(m_encrypted_premaster_secret.get_data_length()),
+				m_encrypted_premaster_secret.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake encrypted premaster_secret"),
+				m_encrypted_premaster_secret.get_data(m_encrypted_premaster_secret.get_data_length()),
+				m_encrypted_premaster_secret.get_data_length()));
+		}
+		else if (m_encrypted_premaster_secret.get_is_valid_data() == false
+			&& m_public_dhe_key.get_is_valid_data() == false)
+		{
+			// Either parameters m_encrypted_premaster_secret or m_public_dhe_key is needed.
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+		}
+
+		if (m_public_dhe_key.get_is_valid_data() == true)
+		{
+			u16_t length_of_public_dhe_key_length_network_order = eap_htons(static_cast<u16_t>(m_public_dhe_key.get_data_length()));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&length_of_public_dhe_key_length_network_order,
+				sizeof(length_of_public_dhe_key_length_network_order));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake public_dhe_key_length"),
+				&length_of_public_dhe_key_length_network_order,
+				sizeof(length_of_public_dhe_key_length_network_order)));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				m_public_dhe_key.get_data(m_public_dhe_key.get_data_length()),
+				m_public_dhe_key.get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake public_dhe_key"),
+				m_public_dhe_key.get_data(m_public_dhe_key.get_data_length()),
+				m_public_dhe_key.get_data_length()));
+		}
+		else if (m_encrypted_premaster_secret.get_is_valid_data() == false
+			&& m_public_dhe_key.get_is_valid_data() == false)
+		{
+			// Either parameters m_encrypted_premaster_secret or m_public_dhe_key is needed.
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+		}
+	}
+
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_certificate_request)
+	{
+		u32_t data_size = m_certificate_types.get_object_count() * sizeof(u8_t);
+
+		if (data_size > 0x000000ff)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+		}
+
+		u8_t data_size_u8_t = static_cast<u8_t>(data_size & 0x000000ff);
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&data_size_u8_t,
+			sizeof(data_size_u8_t));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake certificate_types length"),
+			&data_size_u8_t,
+			sizeof(data_size_u8_t)));
+
+		if (data_size_u8_t > 0ul)
+		{
+			status = add_simple_data(&m_certificate_types, &m_tls_handshake_message_buffer, m_am_tools);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_certificate_request)
+	{
+		u32_t data_size = 0ul;
+		u32_t ind = 0ul;
+
+		for (ind = 0ul; ind < m_certificate_authorities.get_object_count(); ind++)
+		{
+			const eap_variable_data_c * const certificate_authority =  m_certificate_authorities.get_object(ind);
+			if (certificate_authority == 0
+				|| certificate_authority->get_is_valid_data() == false)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+			}
+			data_size += certificate_authority->get_data_length();
+		}
+
+		if (data_size > 0x0000ffff)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+		}
+
+		u8_t data_size_array[2];
+		data_size_array[0] = static_cast<u8_t>((data_size & 0x0000ff00) >> 8);
+		data_size_array[1] = static_cast<u8_t>(data_size & 0x000000ff);
+
+		status = m_tls_handshake_message_buffer.add_data(
+			data_size_array,
+			sizeof(data_size_array));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake certificate_authorities length"),
+			data_size_array,
+			sizeof(data_size_array)));
+
+
+		for (ind = 0ul; ind < m_certificate_authorities.get_object_count(); ind++)
+		{
+			const eap_variable_data_c * const certificate_authority =  m_certificate_authorities.get_object(ind);
+			if (certificate_authority == 0
+				|| certificate_authority->get_is_valid_data() == false)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+			}
+
+			data_size = certificate_authority->get_data_length();
+			u8_t data_size_array[2];
+			data_size_array[0] = static_cast<u8_t>((data_size & 0x0000ff00) >> 8);
+			data_size_array[1] = static_cast<u8_t>(data_size & 0x000000ff);
+			
+			status = m_tls_handshake_message_buffer.add_data(
+				data_size_array,
+				sizeof(data_size_array));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake certificate_authority length"),
+				data_size_array,
+				sizeof(data_size_array)));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				certificate_authority->get_data(certificate_authority->get_data_length()),
+				certificate_authority->get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake certificate_authority"),
+				certificate_authority->get_data(certificate_authority->get_data_length()),
+				certificate_authority->get_data_length()));
+		}
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_certificate_verify)
+	{
+		u16_t length_of_certificate_verify_network_order = eap_htons(static_cast<u16_t>(m_signed_message_hash.get_data_length()));
+
+		status = m_tls_handshake_message_buffer.add_data(
+			&length_of_certificate_verify_network_order,
+			sizeof(length_of_certificate_verify_network_order));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("TLS-handshake certificate_verify"),
+			 &length_of_certificate_verify_network_order,
+			 sizeof(length_of_certificate_verify_network_order)));
+
+		status = m_tls_handshake_message_buffer.add_data(
+			m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()),
+			m_signed_message_hash.get_data_length());
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake signed_message_hash"),
+			m_signed_message_hash.get_data(m_signed_message_hash.get_data_length()),
+			m_signed_message_hash.get_data_length()));
+
+	}
+
+	if (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_finished)
+	{
+		eap_variable_data_c signed_message_hash(m_am_tools);
+
+		status = m_message_hash->message_hash_save_finished(m_is_client);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = m_message_hash->message_hash_create_finished(m_is_client, &signed_message_hash);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = m_tls_handshake_message_buffer.add_data(
+			signed_message_hash.get_data(signed_message_hash.get_data_length()),
+			signed_message_hash.get_data_length());
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("TLS-handshake signed_message_hash"),
+			signed_message_hash.get_data(signed_message_hash.get_data_length()),
+			signed_message_hash.get_data_length()));
+
+	}
+
+
+#if defined(USE_EAP_TLS_SESSION_TICKET)
+
+	if (m_tls_extensions.get_object_count() > 0
+		&& tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type() == tls_handshake_type_new_session_ticket)
+	{
+		const tls_extension_c * const p_new_session_ticket = tls_extension_c::get_tls_extension(
+			tls_extension_type_session_ticket,
+			&m_tls_extensions,
+			m_am_tools);
+
+		if (p_new_session_ticket != 0)
+		{
+			u32_t ticket_lifetime_hint_network_order = eap_htonl(p_new_session_ticket->get_lifetime_hint());
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&ticket_lifetime_hint_network_order,
+				sizeof(ticket_lifetime_hint_network_order));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			u32_t length_of_opaque_ticket = p_new_session_ticket->get_data_length();
+			u16_t length_of_opaque_ticket_network_order = eap_htons(static_cast<u16_t>(length_of_opaque_ticket));
+
+			status = m_tls_handshake_message_buffer.add_data(
+				&length_of_opaque_ticket_network_order,
+				sizeof(length_of_opaque_ticket_network_order));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			if (length_of_opaque_ticket > 0ul)
+			{
+				status = m_tls_handshake_message_buffer.add_data(
+					p_new_session_ticket);
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+		}
+	}
+
+#endif // #if defined(USE_EAP_TLS_SESSION_TICKET)
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	if (status == eap_status_ok)
+	{
+		u32_t handshake_data_length = m_tls_handshake_message_buffer.get_data_length() - handshake_data_length_start;
+
+		EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("handshake length %d bytes.\n"),
+			handshake_data_length));
+
+		if (handshake_data_length <= 0x00ffffff)
+		{
+			// NOTE the address of tmp_tls_handshake_header_on_tls_message_buffer must be queried again.
+			// The whole buffer might be allocated from other address.
+			tmp_tls_handshake_header_on_tls_message_buffer.set_header_buffer(
+				m_tls_handshake_message_buffer.get_data_offset(
+					offset_of_tmp_tls_handshake_header,
+					tls_handshake_header_c::get_header_length()+handshake_data_length),
+				tls_handshake_header_c::get_header_length()+handshake_data_length);
+			if (tmp_tls_handshake_header_on_tls_message_buffer.get_is_valid() == false)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_too_long_message);
+			}
+			tmp_tls_handshake_header_on_tls_message_buffer.set_data_length(handshake_data_length);
+
+
+			switch (tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type())
+			{
+			case tls_handshake_type_hello_request:
+				// This message is NOT included to TLS-message hash.
+				break;
+			case tls_handshake_type_client_hello:
+			case tls_handshake_type_server_hello:
+			case tls_handshake_type_certificate:
+			case tls_handshake_type_server_key_exchange:
+			case tls_handshake_type_certificate_request:
+			case tls_handshake_type_server_hello_done:
+			case tls_handshake_type_certificate_verify:
+			case tls_handshake_type_client_key_exchange:
+			case tls_handshake_type_finished:
+#if defined(USE_EAP_TLS_SESSION_TICKET)
+			case tls_handshake_type_new_session_ticket:
+#endif // #if defined(USE_EAP_TLS_SESSION_TICKET)
+			{
+				status = m_message_hash->message_hash_update(
+					false,
+					tmp_tls_handshake_header_on_tls_message_buffer.get_handshake_type(),
+					tmp_tls_handshake_header_on_tls_message_buffer.get_header_buffer(
+						tmp_tls_handshake_header_on_tls_message_buffer.get_header_length()
+						+ tmp_tls_handshake_header_on_tls_message_buffer.get_data_length()),
+					tmp_tls_handshake_header_on_tls_message_buffer.get_header_length()
+					+ tmp_tls_handshake_header_on_tls_message_buffer.get_data_length());
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+				break;
+			}
+			default:
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
+			} // switch()
+		}
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e tls_handshake_message_c::add_message_data(
+	eap_variable_data_c * const tls_message_buffer)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("\n")));
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TLS: %s: data_function: tls_handshake_message_c::add_message_data(): %s\n"),
+		 (m_is_client == true ? "client": "server"),
+		 tls_handshake_header_c::get_tls_handshake_string(get_handshake_type())));
+
+	eap_status_e status = eap_status_ok;
+
+	if (m_tls_handshake_message_buffer.get_is_valid_data() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_payload);
+	}
+
+	status = tls_message_buffer->add_data(
+		m_tls_handshake_message_buffer.get_data(m_tls_handshake_message_buffer.get_data_length()),
+		m_tls_handshake_message_buffer.get_data_length());
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+
+
+// End.