From 844b185887a5129a050551404bee73d6e5fa3205 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Thu, 1 Sep 2016 10:25:33 +0200 Subject: [PATCH] EAP packet classes organized in hierarchy now --- lib/EAPBase/build/EAPBase.vcxproj | 1 + lib/EAPBase/build/EAPBase.vcxproj.filters | 3 + lib/EAPBase/include/EAP.h | 57 ++++++++ lib/EAPBase/src/EAP.cpp | 83 +++++++++++ lib/PAP/include/Method.h | 55 ------- lib/PAP/src/Method.cpp | 59 -------- lib/TLS/include/Method.h | 85 +---------- lib/TLS/include/TLS.h | 117 +++++++++++++++ lib/TLS/src/Method.cpp | 169 +--------------------- lib/TLS/src/TLS.cpp | 162 +++++++++++++++++++++ lib/TTLS/build/TTLS.vcxproj | 1 + lib/TTLS/build/TTLS.vcxproj.filters | 3 + lib/TTLS/include/Method.h | 15 +- lib/TTLS/include/TTLS.h | 52 +++++++ lib/TTLS/src/Method.cpp | 6 +- lib/TTLS/src/StdAfx.h | 1 + 16 files changed, 492 insertions(+), 377 deletions(-) create mode 100644 lib/EAPBase/src/EAP.cpp create mode 100644 lib/TTLS/include/TTLS.h diff --git a/lib/EAPBase/build/EAPBase.vcxproj b/lib/EAPBase/build/EAPBase.vcxproj index 3b7c1a7..9294069 100644 --- a/lib/EAPBase/build/EAPBase.vcxproj +++ b/lib/EAPBase/build/EAPBase.vcxproj @@ -90,6 +90,7 @@ + diff --git a/lib/EAPBase/build/EAPBase.vcxproj.filters b/lib/EAPBase/build/EAPBase.vcxproj.filters index 2f249ca..baddccc 100644 --- a/lib/EAPBase/build/EAPBase.vcxproj.filters +++ b/lib/EAPBase/build/EAPBase.vcxproj.filters @@ -49,5 +49,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/lib/EAPBase/include/EAP.h b/lib/EAPBase/include/EAP.h index cf5c572..5d9c70a 100644 --- a/lib/EAPBase/include/EAP.h +++ b/lib/EAPBase/include/EAP.h @@ -85,6 +85,11 @@ namespace eap /// Diameter AVP /// struct diameter_avp; + + /// + /// EAP packet + /// + class packet; } /// @@ -638,6 +643,58 @@ namespace eap #pragma warning(pop) }; #pragma pack(pop) + + + class packet + { + public: + /// + /// Constructs an empty packet + /// + packet(); + + /// + /// Copies a packet + /// + /// \param[in] other Packet to copy from + /// + packet(_In_ const packet &other); + + /// + /// Moves a packet + /// + /// \param[in] other Packet to move from + /// + packet(_Inout_ packet &&other); + + /// + /// Copies a packet + /// + /// \param[in] other Packet to copy from + /// + /// \returns Reference to this object + /// + packet& operator=(_In_ const packet &other); + + /// + /// Moves a packet + /// + /// \param[in] other Packet to move from + /// + /// \returns Reference to this object + /// + packet& operator=(_Inout_ packet &&other); + + /// + /// Empty the packet + /// + virtual void clear(); + + public: + EapCode m_code; ///< Packet code + unsigned char m_id; ///< Packet ID + sanitizing_blob m_data; ///< Packet data + }; } diff --git a/lib/EAPBase/src/EAP.cpp b/lib/EAPBase/src/EAP.cpp new file mode 100644 index 0000000..64e9072 --- /dev/null +++ b/lib/EAPBase/src/EAP.cpp @@ -0,0 +1,83 @@ +/* + Copyright 2015-2016 Amebis + Copyright 2016 GÉANT + + This file is part of GÉANTLink. + + GÉANTLink is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GÉANTLink is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GÉANTLink. If not, see . +*/ + +#include "StdAfx.h" + +using namespace std; +using namespace winstd; + + +////////////////////////////////////////////////////////////////////// +// eap::packet +////////////////////////////////////////////////////////////////////// + +eap::packet::packet() : + m_code((EapCode)0), + m_id(0) +{ +} + + +eap::packet::packet(_In_ const packet &other) : + m_code(other.m_code), + m_id (other.m_id ), + m_data(other.m_data) +{ +} + + +eap::packet::packet(_Inout_ packet &&other) : + m_code(std::move(other.m_code)), + m_id (std::move(other.m_id )), + m_data(std::move(other.m_data)) +{ +} + + +eap::packet& eap::packet::operator=(_In_ const packet &other) +{ + if (this != std::addressof(other)) { + m_code = other.m_code; + m_id = other.m_id ; + m_data = other.m_data; + } + + return *this; +} + + +eap::packet& eap::packet::operator=(_Inout_ packet &&other) +{ + if (this != std::addressof(other)) { + m_code = std::move(other.m_code); + m_id = std::move(other.m_id ); + m_data = std::move(other.m_data); + } + + return *this; +} + + +void eap::packet::clear() +{ + m_code = (EapCode)0; + m_id = 0; + m_data.clear(); +} diff --git a/lib/PAP/include/Method.h b/lib/PAP/include/Method.h index c39efb3..81361f3 100644 --- a/lib/PAP/include/Method.h +++ b/lib/PAP/include/Method.h @@ -39,61 +39,6 @@ namespace eap { class method_pap : public method { - public: - /// - /// EAP-PAP packet (data) - /// - class packet - { - public: - /// - /// Constructs an empty packet - /// - packet(); - - /// - /// Copies a packet - /// - /// \param[in] other Packet to copy from - /// - packet(_In_ const packet &other); - - /// - /// Moves a packet - /// - /// \param[in] other Packet to move from - /// - packet(_Inout_ packet &&other); - - /// - /// Copies a packet - /// - /// \param[in] other Packet to copy from - /// - /// \returns Reference to this object - /// - packet& operator=(_In_ const packet &other); - - /// - /// Moves a packet - /// - /// \param[in] other Packet to move from - /// - /// \returns Reference to this object - /// - packet& operator=(_Inout_ packet &&other); - - /// - /// Empty the packet - /// - void clear(); - - public: - EapCode m_code; ///< Packet code - unsigned char m_id; ///< Packet ID - sanitizing_blob m_data; ///< Packet data - }; - public: /// /// Constructs an EAP method diff --git a/lib/PAP/src/Method.cpp b/lib/PAP/src/Method.cpp index 07ebbd0..47d8dc0 100644 --- a/lib/PAP/src/Method.cpp +++ b/lib/PAP/src/Method.cpp @@ -24,65 +24,6 @@ using namespace std; using namespace winstd; -////////////////////////////////////////////////////////////////////// -// eap::method_pap::packet -////////////////////////////////////////////////////////////////////// - -eap::method_pap::packet::packet() : - m_code((EapCode)0), - m_id(0) -{ -} - - -eap::method_pap::packet::packet(_In_ const packet &other) : - m_code(other.m_code), - m_id (other.m_id ), - m_data(other.m_data) -{ -} - - -eap::method_pap::packet::packet(_Inout_ packet &&other) : - m_code(std::move(other.m_code)), - m_id (std::move(other.m_id )), - m_data(std::move(other.m_data)) -{ -} - - -eap::method_pap::packet& eap::method_pap::packet::operator=(_In_ const packet &other) -{ - if (this != std::addressof(other)) { - m_code = other.m_code; - m_id = other.m_id ; - m_data = other.m_data; - } - - return *this; -} - - -eap::method_pap::packet& eap::method_pap::packet::operator=(_Inout_ packet &&other) -{ - if (this != std::addressof(other)) { - m_code = std::move(other.m_code); - m_id = std::move(other.m_id ); - m_data = std::move(other.m_data); - } - - return *this; -} - - -void eap::method_pap::packet::clear() -{ - m_code = (EapCode)0; - m_id = 0; - m_data.clear(); -} - - ////////////////////////////////////////////////////////////////////// // eap::method_pap ////////////////////////////////////////////////////////////////////// diff --git a/lib/TLS/include/Method.h b/lib/TLS/include/Method.h index b04f286..51617dd 100644 --- a/lib/TLS/include/Method.h +++ b/lib/TLS/include/Method.h @@ -47,87 +47,6 @@ namespace eap class method_tls : public method { public: -#pragma warning(push) -#pragma warning(disable: 4480) - - /// - /// EAP-TLS request packet flags - /// - /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.1 EAP-TLS Request Packet)](https://tools.ietf.org/html/rfc5216#section-3.1) - /// - enum flags_req_t : unsigned char { - flags_req_length_incl = 0x80, ///< Length included - flags_req_more_frag = 0x40, ///< More fragments - flags_req_start = 0x20, ///< Start - }; - - /// - /// EAP-TLS response packet flags - /// - /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.2 EAP-TLS Response Packet)](https://tools.ietf.org/html/rfc5216#section-3.2) - /// - enum flags_res_t : unsigned char { - flags_res_length_incl = 0x80, ///< Length included - flags_res_more_frag = 0x40, ///< More fragments - }; - -#pragma warning(pop) - - /// - /// EAP-TLS packet (data) - /// - class packet - { - public: - /// - /// Constructs an empty packet - /// - packet(); - - /// - /// Copies a packet - /// - /// \param[in] other Packet to copy from - /// - packet(_In_ const packet &other); - - /// - /// Moves a packet - /// - /// \param[in] other Packet to move from - /// - packet(_Inout_ packet &&other); - - /// - /// Copies a packet - /// - /// \param[in] other Packet to copy from - /// - /// \returns Reference to this object - /// - packet& operator=(_In_ const packet &other); - - /// - /// Moves a packet - /// - /// \param[in] other Packet to move from - /// - /// \returns Reference to this object - /// - packet& operator=(_Inout_ packet &&other); - - /// - /// Empty the packet - /// - void clear(); - - public: - EapCode m_code; ///< Packet code - unsigned char m_id; ///< Packet ID - unsigned char m_flags; ///< Packet flags - std::vector m_data; ///< Packet data - }; - #pragma pack(push) #pragma pack(1) /// @@ -489,8 +408,8 @@ namespace eap credentials_tls &m_cred; ///< EAP-TLS user credentials HANDLE m_user_ctx; ///< Handle to user context - packet m_packet_req; ///< Request packet - packet m_packet_res; ///< Response packet + packet_tls m_packet_req; ///< Request packet + packet_tls m_packet_res; ///< Response packet #if EAP_TLS < EAP_TLS_SCHANNEL winstd::crypt_prov m_cp; ///< Cryptography provider for general services diff --git a/lib/TLS/include/TLS.h b/lib/TLS/include/TLS.h index c0419af..509cb41 100644 --- a/lib/TLS/include/TLS.h +++ b/lib/TLS/include/TLS.h @@ -91,6 +91,11 @@ namespace eap /// \sa [The Transport Layer Security (TLS) Protocol Version 1.2 (Chapter 6.1. Connection States)](https://tools.ietf.org/html/rfc5246#section-6.1) /// class tls_conn_state; + + /// + /// EAP-TLS packet + /// + class packet_tls; } ///// @@ -523,4 +528,116 @@ namespace eap size_t m_size_mac_hash; ///< Message authenticy check algorithm result size (has to comply with `m_alg_mac`) hmac_padding m_padding_hmac; ///< Padding (key) for HMAC calculation }; + + + class packet_tls : public packet + { + public: +#pragma warning(push) +#pragma warning(disable: 4480) + + /// + /// EAP-TLS request packet flags + /// + /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.1 EAP-TLS Request Packet)](https://tools.ietf.org/html/rfc5216#section-3.1) + /// + enum flags_req_t : unsigned char { + flags_req_length_incl = 0x80, ///< Length included + flags_req_more_frag = 0x40, ///< More fragments + flags_req_start = 0x20, ///< Start + }; + + /// + /// EAP-TLS response packet flags + /// + /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.2 EAP-TLS Response Packet)](https://tools.ietf.org/html/rfc5216#section-3.2) + /// + enum flags_res_t : unsigned char { + flags_res_length_incl = 0x80, ///< Length included + flags_res_more_frag = 0x40, ///< More fragments + }; + +#pragma warning(pop) + + public: + /// + /// Constructs an empty packet + /// + packet_tls(); + + /// + /// Copies a packet + /// + /// \param[in] other Packet to copy from + /// + packet_tls(_In_ const packet_tls &other); + + /// + /// Moves a packet + /// + /// \param[in] other Packet to move from + /// + packet_tls(_Inout_ packet_tls &&other); + + /// + /// Copies a packet + /// + /// \param[in] other Packet to copy from + /// + /// \returns Reference to this object + /// + packet_tls& operator=(_In_ const packet_tls &other); + + /// + /// Moves a packet + /// + /// \param[in] other Packet to move from + /// + /// \returns Reference to this object + /// + packet_tls& operator=(_Inout_ packet_tls &&other); + + /// + /// Empty the packet + /// + virtual void clear(); + + /// + /// Appends fragment + /// + /// \param[in] pck EAP packet fragment + /// + /// \returns + /// - \c true if this was the last fragment of a packet + /// - \c false if more fragments are to follow + /// + bool append_frag(_In_ const EapPacket *pck); + + /// + /// Gets next fragment of the packet + /// + /// \param[out ] pck Memory to write EAP packet to + /// \param[inout] size_max Available size of \p pck (in bytes) + /// + /// \returns Final size of the packet (fragment) + /// + unsigned short get_frag(_Out_bytecap_(size_max) EapPacket *pck, _In_ size_t size_max); + + /// + /// Is this packet an ACK + /// + /// \param[in] id ID of originating EAP packet + /// + inline bool is_ack(_In_ unsigned char id) const + { + return + m_code == EapCodeRequest && + m_id == id && + m_data.empty() && + !(m_flags & (flags_req_length_incl | flags_req_more_frag | flags_req_start)); + } + + public: + unsigned char m_flags; ///< Packet flags + }; } diff --git a/lib/TLS/src/Method.cpp b/lib/TLS/src/Method.cpp index 7dbe957..e147ae6 100644 --- a/lib/TLS/src/Method.cpp +++ b/lib/TLS/src/Method.cpp @@ -56,71 +56,6 @@ static const unsigned char s_compression_suite[] = { #endif -////////////////////////////////////////////////////////////////////// -// eap::method_tls::packet -////////////////////////////////////////////////////////////////////// - -eap::method_tls::packet::packet() : - m_code((EapCode)0), - m_id(0), - m_flags(0) -{ -} - - -eap::method_tls::packet::packet(_In_ const packet &other) : - m_code (other.m_code ), - m_id (other.m_id ), - m_flags(other.m_flags), - m_data (other.m_data ) -{ -} - - -eap::method_tls::packet::packet(_Inout_ packet &&other) : - m_code (std::move(other.m_code )), - m_id (std::move(other.m_id )), - m_flags(std::move(other.m_flags)), - m_data (std::move(other.m_data )) -{ -} - - -eap::method_tls::packet& eap::method_tls::packet::operator=(_In_ const packet &other) -{ - if (this != std::addressof(other)) { - m_code = other.m_code ; - m_id = other.m_id ; - m_flags = other.m_flags; - m_data = other.m_data ; - } - - return *this; -} - - -eap::method_tls::packet& eap::method_tls::packet::operator=(_Inout_ packet &&other) -{ - if (this != std::addressof(other)) { - m_code = std::move(other.m_code ); - m_id = std::move(other.m_id ); - m_flags = std::move(other.m_flags); - m_data = std::move(other.m_data ); - } - - return *this; -} - - -void eap::method_tls::packet::clear() -{ - m_code = (EapCode)0; - m_id = 0; - m_flags = 0; - m_data.clear(); -} - - ////////////////////////////////////////////////////////////////////// // eap::method_tls ////////////////////////////////////////////////////////////////////// @@ -336,39 +271,8 @@ void eap::method_tls::process_request_packet( //else if (pReceivedPacket->Data[0] != eap_type_tls) // Skip method check, to allow TTLS extension. // throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, string_printf(__FUNCTION__ " Packet is not EAP-TLS (expected: %u, received: %u).", eap_type_tls, pReceivedPacket->Data[0])); - // Get packet data pointer and size for more readable code later on. - const unsigned char *packet_data_ptr; - size_t packet_data_size; - if (pReceivedPacket->Data[1] & flags_req_length_incl) { - // Length field is included. - packet_data_ptr = pReceivedPacket->Data + 6; - packet_data_size = dwReceivedPacketSize - 10; - } else { - // Length field not included. - packet_data_ptr = pReceivedPacket->Data + 2; - packet_data_size = dwReceivedPacketSize - 6; - } - - // Do the EAP-TLS defragmentation. - if (pReceivedPacket->Data[1] & flags_req_more_frag) { - if (m_packet_req.m_data.empty()) { - // Start a new packet. - if (pReceivedPacket->Data[1] & flags_req_length_incl) { - // Preallocate data according to the Length field. - size_t size_tot = ntohl(*(unsigned int*)(pReceivedPacket->Data + 2)); - m_packet_req.m_data.reserve(size_tot); - m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_FIRST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)packet_data_size), event_data((unsigned int)size_tot), event_data::blank); - } else { - // The Length field was not included. Odd. Nevermind, no pre-allocation then. - m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_FIRST1, event_data((unsigned int)eap_type_tls), event_data((unsigned int)packet_data_size), event_data::blank); - } - } else { - // Mid fragment received. - m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_MID, event_data((unsigned int)eap_type_tls), event_data((unsigned int)packet_data_size), event_data((unsigned int)m_packet_req.m_data.size()), event_data::blank); - } - m_packet_req.m_data.insert(m_packet_req.m_data.end(), packet_data_ptr, packet_data_ptr + packet_data_size); - - // Reply with ACK packet. + if (!m_packet_req.append_frag(pReceivedPacket)) { + // This was not the only/last fragment. Reply with ACK packet. m_packet_res.m_code = EapCodeResponse; m_packet_res.m_id = pReceivedPacket->Id; m_packet_res.m_flags = 0; @@ -376,27 +280,11 @@ void eap::method_tls::process_request_packet( pEapOutput->fAllowNotifications = FALSE; pEapOutput->action = EapPeerMethodResponseActionSend; return; - } else if (!m_packet_req.m_data.empty()) { - // Last fragment received. Append data. - m_packet_req.m_data.insert(m_packet_req.m_data.end(), packet_data_ptr, packet_data_ptr + packet_data_size); - m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_LAST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)packet_data_size), event_data((unsigned int)m_packet_req.m_data.size()), event_data::blank); - } else { - // This is a complete non-fragmented packet. - m_packet_req.m_data.assign(packet_data_ptr, packet_data_ptr + packet_data_size); - m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_tls), event_data((unsigned int)packet_data_size), event_data::blank); } - m_packet_req.m_code = (EapCode)pReceivedPacket->Code; - m_packet_req.m_id = pReceivedPacket->Id; - m_packet_req.m_flags = pReceivedPacket->Data[1]; - - if (m_packet_res.m_flags & flags_res_more_frag) { + if (m_packet_res.m_flags & packet_tls::flags_res_more_frag) { // We are sending a fragmented message. - if ( m_packet_req.m_code == EapCodeRequest && - m_packet_req.m_id == m_packet_res.m_id && - m_packet_req.m_data.empty() && - !(m_packet_req.m_flags & (flags_req_length_incl | flags_req_more_frag | flags_req_start))) - { + if (m_packet_req.is_ack(m_packet_res.m_id)) { // This is the ACK of our fragmented message packet. Send the next fragment. m_packet_res.m_id++; pEapOutput->fAllowNotifications = FALSE; @@ -567,7 +455,7 @@ void eap::method_tls::process_request_packet( m_phase = phase_client_hello; } #else - if (pReceivedPacket->Code == EapCodeRequest && (m_packet_req.m_flags & flags_req_start)) { + if (pReceivedPacket->Code == EapCodeRequest && (m_packet_req.m_flags & packet_tls::flags_req_start)) { // This is the EAP-TLS start message: (re)initialize method. m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_tls), event_data::blank); m_phase = phase_handshake_init; @@ -603,52 +491,7 @@ void eap::method_tls::get_response_packet( assert(pdwSendPacketSize); assert(pSendPacket); - unsigned int - size_data = (unsigned int)m_packet_res.m_data.size(), - size_packet = size_data + 6; - unsigned short size_packet_limit = (unsigned short)std::min(*pdwSendPacketSize, USHRT_MAX); - unsigned char *data_dst; - - if (!(m_packet_res.m_flags & flags_res_more_frag)) { - // Not fragmented. - if (size_packet <= size_packet_limit) { - // No need to fragment the packet. - m_packet_res.m_flags &= ~flags_res_length_incl; // No need to explicitly include the Length field either. - data_dst = pSendPacket->Data + 2; - m_module.log_event(&EAPMETHOD_PACKET_SEND, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data::blank); - } else { - // But it should be fragmented. - m_packet_res.m_flags |= flags_res_length_incl | flags_res_more_frag; - *(unsigned int*)(pSendPacket->Data + 2) = (unsigned int)size_packet; - data_dst = pSendPacket->Data + 6; - size_data = size_packet_limit - 10; - size_packet = size_packet_limit; - m_module.log_event(&EAPMETHOD_PACKET_SEND_FRAG_FIRST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data((unsigned int)(m_packet_res.m_data.size() - size_data)), event_data::blank); - } - } else { - // Continuing the fragmented packet... - if (size_packet > size_packet_limit) { - // This is a mid fragment. - m_packet_res.m_flags &= ~flags_res_length_incl; - size_data = size_packet_limit - 6; - size_packet = size_packet_limit; - m_module.log_event(&EAPMETHOD_PACKET_SEND_FRAG_MID, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data((unsigned int)(m_packet_res.m_data.size() - size_data)), event_data::blank); - } else { - // This is the last fragment. - m_packet_res.m_flags &= ~(flags_res_length_incl | flags_res_more_frag); - m_module.log_event(&EAPMETHOD_PACKET_SEND_FRAG_LAST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data((unsigned int)(m_packet_res.m_data.size() - size_data)), event_data::blank); - } - data_dst = pSendPacket->Data + 2; - } - - pSendPacket->Code = (BYTE)m_packet_res.m_code; - pSendPacket->Id = m_packet_res.m_id; - *(unsigned short*)pSendPacket->Length = htons((unsigned short)size_packet); - pSendPacket->Data[0] = (BYTE)eap_type_tls; - pSendPacket->Data[1] = m_packet_res.m_flags; - memcpy(data_dst, m_packet_res.m_data.data(), size_data); - m_packet_res.m_data.erase(m_packet_res.m_data.begin(), m_packet_res.m_data.begin() + size_data); - *pdwSendPacketSize = size_packet; + *pdwSendPacketSize = m_packet_res.get_frag(pSendPacket, *pdwSendPacketSize); } diff --git a/lib/TLS/src/TLS.cpp b/lib/TLS/src/TLS.cpp index 9f5d728..f4ff6a7 100644 --- a/lib/TLS/src/TLS.cpp +++ b/lib/TLS/src/TLS.cpp @@ -430,3 +430,165 @@ void eap::tls_conn_state::set_cipher(_In_ const unsigned char cipher[2]) } else throw win_runtime_error(ERROR_NOT_SUPPORTED, string_printf(__FUNCTION__ " Unknown cipher (received 0x%02x%02x).", cipher[0], cipher[1])); } + + +////////////////////////////////////////////////////////////////////// +// eap::packet_tls +////////////////////////////////////////////////////////////////////// + +eap::packet_tls::packet_tls() : + m_flags(0), + packet() +{ +} + + +eap::packet_tls::packet_tls(_In_ const packet_tls &other) : + m_flags(other.m_flags), + packet (other ) +{ +} + + +eap::packet_tls::packet_tls(_Inout_ packet_tls &&other) : + m_flags(std::move(other.m_flags)), + packet (std::move(other )) +{ +} + + +eap::packet_tls& eap::packet_tls::operator=(_In_ const packet_tls &other) +{ + if (this != std::addressof(other)) { + (packet&)*this = other; + m_flags = other.m_flags; + } + + return *this; +} + + +eap::packet_tls& eap::packet_tls::operator=(_Inout_ packet_tls &&other) +{ + if (this != std::addressof(other)) { + (packet&)*this = std::move(other); + m_flags = std::move(other.m_flags); + } + + return *this; +} + + +void eap::packet_tls::clear() +{ + packet::clear(); + m_flags = 0; +} + + +bool eap::packet_tls::append_frag(_In_ const EapPacket *pck) +{ + assert(pck); + + // Get packet data pointer and size for more readable code later on. + const unsigned char *packet_data_ptr; + size_t size_packet_data; + if (pck->Data[1] & flags_req_length_incl) { + // Length field is included. + packet_data_ptr = pck->Data + 6; + size_packet_data = ntohs(*(unsigned short*)pck->Length) - 10; + } else { + // Length field not included. + packet_data_ptr = pck->Data + 2; + size_packet_data = ntohs(*(unsigned short*)pck->Length) - 6; + } + + // Do the EAP-TLS defragmentation. + if (pck->Data[1] & flags_req_more_frag) { + if (m_data.empty()) { + // Start a new packet. + if (pck->Data[1] & flags_req_length_incl) { + // Preallocate data according to the Length field. + size_t size_tot = ntohl(*(unsigned int*)(pck->Data + 2)); + m_data.reserve(size_tot); + //m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_FIRST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_packet_data), event_data((unsigned int)size_tot), event_data::blank); + } else { + // The Length field was not included. Odd. Nevermind, no pre-allocation then. + //m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_FIRST1, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_packet_data), event_data::blank); + } + } else { + // Mid fragment received. + //m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_MID, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_packet_data), event_data((unsigned int)m_data.size()), event_data::blank); + } + m_data.insert(m_data.end(), packet_data_ptr, packet_data_ptr + size_packet_data); + + return false; + } else if (!m_data.empty()) { + // Last fragment received. Append data. + m_data.insert(m_data.end(), packet_data_ptr, packet_data_ptr + size_packet_data); + //m_module.log_event(&EAPMETHOD_PACKET_RECV_FRAG_LAST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_packet_data), event_data((unsigned int)m_data.size()), event_data::blank); + } else { + // This is a complete non-fragmented packet. + m_data.assign(packet_data_ptr, packet_data_ptr + size_packet_data); + //m_module.log_event(&EAPMETHOD_PACKET_RECV, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_packet_data), event_data::blank); + } + + m_code = (EapCode)pck->Code; + m_id = pck->Id; + m_flags = pck->Data[1]; + + return true; +} + + +unsigned short eap::packet_tls::get_frag(_Out_bytecap_(size_pck) EapPacket *pck, _In_ size_t size_max) +{ + assert(pck); + + size_t size_data = m_data.size(); + assert(size_data <= UINT_MAX - 6); // Packets spanning over 4GB are not supported by EAP. + unsigned int size_packet = (unsigned int)size_data + 6; + unsigned short size_packet_limit = (unsigned short)std::min(size_max, USHRT_MAX); + unsigned char *data_dst; + + if (!(m_flags & flags_res_more_frag)) { + // Not fragmented. + if (size_packet <= size_packet_limit) { + // No need to fragment the packet. + m_flags &= ~flags_res_length_incl; // No need to explicitly include the Length field either. + data_dst = pck->Data + 2; + //m_module.log_event(&EAPMETHOD_PACKET_SEND, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data::blank); + } else { + // But it should be fragmented. + m_flags |= flags_res_length_incl | flags_res_more_frag; + *(unsigned int*)(pck->Data + 2) = htonl(size_packet); + data_dst = pck->Data + 6; + size_data = size_packet_limit - 10; + size_packet = size_packet_limit; + //m_module.log_event(&EAPMETHOD_PACKET_SEND_FRAG_FIRST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data((unsigned int)(m_data.size() - size_data)), event_data::blank); + } + } else { + // Continuing the fragmented packet... + if (size_packet > size_packet_limit) { + // This is a mid fragment. + m_flags &= ~flags_res_length_incl; + size_data = size_packet_limit - 6; + size_packet = size_packet_limit; + //m_module.log_event(&EAPMETHOD_PACKET_SEND_FRAG_MID, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data((unsigned int)(m_data.size() - size_data)), event_data::blank); + } else { + // This is the last fragment. + m_flags &= ~(flags_res_length_incl | flags_res_more_frag); + //m_module.log_event(&EAPMETHOD_PACKET_SEND_FRAG_LAST, event_data((unsigned int)eap_type_tls), event_data((unsigned int)size_data), event_data((unsigned int)(m_data.size() - size_data)), event_data::blank); + } + data_dst = pck->Data + 2; + } + + pck->Code = (BYTE)m_code; + pck->Id = m_id; + *(unsigned short*)pck->Length = htons((unsigned short)size_packet); + pck->Data[0] = (BYTE)eap_type_tls; + pck->Data[1] = m_flags; + memcpy(data_dst, m_data.data(), size_data); + m_data.erase(m_data.begin(), m_data.begin() + size_data); + return (unsigned short)size_packet; +} diff --git a/lib/TTLS/build/TTLS.vcxproj b/lib/TTLS/build/TTLS.vcxproj index 0f5716f..8539920 100644 --- a/lib/TTLS/build/TTLS.vcxproj +++ b/lib/TTLS/build/TTLS.vcxproj @@ -83,6 +83,7 @@ + diff --git a/lib/TTLS/build/TTLS.vcxproj.filters b/lib/TTLS/build/TTLS.vcxproj.filters index 5cd912e..1aa920b 100644 --- a/lib/TTLS/build/TTLS.vcxproj.filters +++ b/lib/TTLS/build/TTLS.vcxproj.filters @@ -26,6 +26,9 @@ Header Files + + Header Files + diff --git a/lib/TTLS/include/Method.h b/lib/TTLS/include/Method.h index 3ab96f2..18115dc 100644 --- a/lib/TTLS/include/Method.h +++ b/lib/TTLS/include/Method.h @@ -30,6 +30,7 @@ namespace eap #include "Config.h" #include "Credentials.h" +#include "TTLS.h" #include "../../TLS/include/Method.h" #include "../../EAPBase/include/Method.h" @@ -39,20 +40,6 @@ namespace eap { class method_ttls : public method_tls { - public: - /// - /// EAP-TTLS packet flags - /// - /// \sa [Extensible Authentication Protocol Tunneled Transport Layer Security Authenticated Protocol Version 0 (EAP-TTLSv0) (Chapter: 9.1 Packet Format)](https://tools.ietf.org/html/rfc5281#section-9.1) - /// - #pragma warning(suppress: 4480) - enum flags_t : unsigned char { - flags_length_incl = method_tls::flags_req_length_incl, ///< Length included - flags_more_frag = method_tls::flags_req_more_frag, ///< More fragments - flags_start = method_tls::flags_req_start, ///< Start - flags_ver_mask = 0x07, ///< Version mask - }; - public: /// /// Constructs an EAP method diff --git a/lib/TTLS/include/TTLS.h b/lib/TTLS/include/TTLS.h new file mode 100644 index 0000000..7f22386 --- /dev/null +++ b/lib/TTLS/include/TTLS.h @@ -0,0 +1,52 @@ +/* + Copyright 2015-2016 Amebis + Copyright 2016 GÉANT + + This file is part of GÉANTLink. + + GÉANTLink is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + GÉANTLink is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GÉANTLink. If not, see . +*/ + +namespace eap +{ + /// + /// EAP-TTLS packet + /// + class packet_ttls; +} + +#pragma once + +#include "../../TLS/include/TLS.h" + + +namespace eap +{ + class packet_ttls : public packet_tls + { + public: + /// + /// EAP-TTLS packet flags + /// + /// \sa [Extensible Authentication Protocol Tunneled Transport Layer Security Authenticated Protocol Version 0 (EAP-TTLSv0) (Chapter: 9.1 Packet Format)](https://tools.ietf.org/html/rfc5281#section-9.1) + /// + #pragma warning(suppress: 4480) + enum flags_t : unsigned char { + flags_length_incl = packet_tls::flags_req_length_incl, ///< Length included + flags_more_frag = packet_tls::flags_req_more_frag, ///< More fragments + flags_start = packet_tls::flags_req_start, ///< Start + flags_ver_mask = 0x07, ///< Version mask + }; + }; +} diff --git a/lib/TTLS/src/Method.cpp b/lib/TTLS/src/Method.cpp index ced1d49..2c90e22 100644 --- a/lib/TTLS/src/Method.cpp +++ b/lib/TTLS/src/Method.cpp @@ -95,11 +95,11 @@ void eap::method_ttls::process_request_packet( _In_ DWORD dwReceivedPacketSize, _Inout_ EapPeerMethodOutput *pEapOutput) { - if (pReceivedPacket->Code == EapCodeRequest && (pReceivedPacket->Data[1] & flags_start)) { + if (pReceivedPacket->Code == EapCodeRequest && (pReceivedPacket->Data[1] & packet_ttls::flags_start)) { // This is a start EAP-TTLS packet. // Determine minimum EAP-TTLS version supported by server and us. - version_t ver_remote = (version_t)(pReceivedPacket->Data[1] & flags_ver_mask); + version_t ver_remote = (version_t)(pReceivedPacket->Data[1] & packet_ttls::flags_ver_mask); m_version = std::min(ver_remote, version_0); m_module.log_event(&EAPMETHOD_TTLS_HANDSHAKE_START, event_data((unsigned int)eap_type_ttls), event_data((unsigned char)m_version), event_data((unsigned char)ver_remote), event_data::blank); } @@ -117,7 +117,7 @@ void eap::method_ttls::get_response_packet( // Change packet type to EAP-TTLS, and add EAP-TTLS version. pSendPacket->Data[0] = (BYTE)eap_type_ttls; - pSendPacket->Data[1] &= ~flags_ver_mask; + pSendPacket->Data[1] &= ~packet_ttls::flags_ver_mask; pSendPacket->Data[1] |= m_version; } diff --git a/lib/TTLS/src/StdAfx.h b/lib/TTLS/src/StdAfx.h index 5a8b430..57b1ef2 100644 --- a/lib/TTLS/src/StdAfx.h +++ b/lib/TTLS/src/StdAfx.h @@ -24,6 +24,7 @@ #include "../include/Credentials.h" #include "../include/Method.h" #include "../include/Module.h" +#include "../include/TTLS.h" #include "../../PAP/include/Config.h" #include "../../PAP/include/Credentials.h"