diff --git a/lib/TLS/build/TLS.vcxproj b/lib/TLS/build/TLS.vcxproj
index de8f54c..3d23237 100644
--- a/lib/TLS/build/TLS.vcxproj
+++ b/lib/TLS/build/TLS.vcxproj
@@ -103,10 +103,12 @@
+
+
Create
diff --git a/lib/TLS/build/TLS.vcxproj.filters b/lib/TLS/build/TLS.vcxproj.filters
index 259bf91..d5c72c5 100644
--- a/lib/TLS/build/TLS.vcxproj.filters
+++ b/lib/TLS/build/TLS.vcxproj.filters
@@ -20,6 +20,9 @@
Header Files
+
+ Header Files
+
@@ -31,5 +34,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/lib/TLS/include/Method.h b/lib/TLS/include/Method.h
new file mode 100644
index 0000000..5ae4844
--- /dev/null
+++ b/lib/TLS/include/Method.h
@@ -0,0 +1,115 @@
+/*
+ Copyright 2015-2020 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
+{
+ class method_defrag;
+}
+
+#pragma once
+
+#include "../../EAPBase/include/Method.h"
+
+
+namespace eap
+{
+ /// \addtogroup EAPBaseMethod
+ /// @{
+
+ ///
+ /// EAP-(T)TLS/PEAP class defragging method tunnel
+ ///
+ class method_defrag : public method
+ {
+ public:
+#pragma warning(push)
+#pragma warning(disable: 4480)
+
+ ///
+ /// EAP-(T)TLS/PEAP request/response packet flags
+ ///
+ /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.1 EAP-TLS Request Packet)](https://tools.ietf.org/html/rfc5216#section-3.1)
+ /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.2 EAP-TLS Response Packet)](https://tools.ietf.org/html/rfc5216#section-3.2)
+ /// \sa [The EAP-TTLS Authentication Protocol Version 0 (Chapter: 9.1. Packet Format)](https://tools.ietf.org/html/rfc5281#section-9.1)
+ /// \sa [Protected EAP Protocol (PEAP) (Chapter: 3.1. PEAP Packet Format)](https://tools.ietf.org/html/draft-josefsson-pppext-eap-tls-eap-05#section-3.1)
+ ///
+ enum flags_t : unsigned char {
+ flags_length_incl = 0x80, ///< Length included
+ flags_more_frag = 0x40, ///< More fragments
+ flags_start = 0x20, ///< Start
+ flags_ver_mask = 0x07, ///< Version mask
+ };
+
+#pragma warning(pop)
+
+ public:
+ ///
+ /// Constructs a method
+ ///
+ /// \param[in] mod Module to use for global services
+ /// \param[in] version_max Maximum protocol version supported by peer
+ /// \param[in] inner Inner method
+ ///
+ method_defrag(_In_ module &mod, _In_ unsigned char version_max, _In_ method *inner);
+
+ /// \name Session management
+ /// @{
+
+ virtual void begin_session(
+ _In_ DWORD dwFlags,
+ _In_ const EapAttributes *pAttributeArray,
+ _In_ HANDLE hTokenImpersonateUser,
+ _In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD);
+
+ /// @}
+
+ /// \name Packet processing
+ /// @{
+
+ virtual EapPeerMethodResponseAction process_request_packet(
+ _In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
+ _In_ DWORD dwReceivedPacketSize);
+
+ virtual void get_response_packet(
+ _Out_ sanitizing_blob &packet,
+ _In_opt_ DWORD size_max = MAXDWORD);
+
+ /// @}
+
+ public:
+ unsigned char m_version; ///< Negotiated protocol version
+
+ protected:
+ sanitizing_blob m_data_req; ///< Data in request
+ sanitizing_blob m_data_res; ///< Data in response
+ bool m_send_res; ///< Are we sending a response?
+
+ ///
+ /// Communication phase
+ ///
+ enum class phase_t {
+ unknown = -1, ///< Unknown phase
+ init = 0, ///< Binding exchange
+ established, ///< Connection established
+ } m_phase; ///< What phase is our communication at?
+ };
+
+ /// @}
+}
diff --git a/lib/TLS/src/Method.cpp b/lib/TLS/src/Method.cpp
new file mode 100644
index 0000000..a3a425e
--- /dev/null
+++ b/lib/TLS/src/Method.cpp
@@ -0,0 +1,156 @@
+/*
+ Copyright 2015-2020 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::method_defrag
+//////////////////////////////////////////////////////////////////////
+
+eap::method_defrag::method_defrag(_In_ module &mod, _In_ unsigned char version_max, _In_ method *inner) :
+ m_version(version_max),
+ m_phase(phase_t::unknown),
+ m_send_res(false),
+ method(mod, inner)
+{
+}
+
+
+void eap::method_defrag::begin_session(
+ _In_ DWORD dwFlags,
+ _In_ const EapAttributes *pAttributeArray,
+ _In_ HANDLE hTokenImpersonateUser,
+ _In_opt_ DWORD dwMaxSendPacketSize)
+{
+ // Inner method may generate packets of up to 4GB.
+ // But, we can not do the fragmentation if we have less space than flags+length.
+ if (dwMaxSendPacketSize < 5)
+ throw invalid_argument(string_printf(__FUNCTION__ " Maximum packet size too small (minimum: %u, available: %u).", 5, dwMaxSendPacketSize));
+ method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, MAXDWORD);
+
+ m_phase = phase_t::init;
+}
+
+
+EapPeerMethodResponseAction eap::method_defrag::process_request_packet(
+ _In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
+ _In_ DWORD dwReceivedPacketSize)
+{
+ auto data_packet = reinterpret_cast(pReceivedPacket);
+
+ if (dwReceivedPacketSize < 1)
+ throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete packet flags.");
+
+ // To prevent version downgrade attacks, negotiate protocol version on binding exchange only. Then stick to it!
+ unsigned char data_version = data_packet[0] & flags_ver_mask;
+ if (m_phase == phase_t::init) {
+ m_version = min(data_version, m_version);
+ m_module.log_event(&EAPMETHOD_DEFRAG_VERSION,
+ event_data(m_version),
+ event_data(data_version),
+ event_data::blank);
+ m_phase = phase_t::established;
+ } else if (data_version != m_version)
+ throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Protocol version mismatch.");
+
+ // Get packet content pointers for more readable code later on.
+ auto
+ data_content = data_packet + (data_packet[0] & flags_length_incl ? 5 : 1),
+ data_content_end = data_packet + dwReceivedPacketSize;
+ if (data_content > data_content_end)
+ throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete data.");
+
+ // Do the defragmentation.
+ if (data_packet[0] & flags_more_frag) {
+ if (m_data_req.empty()) {
+ // Start a new packet.
+ if (data_packet[0] & flags_length_incl) {
+ // Preallocate data according to the Length field.
+ m_data_req.reserve(ntohl(*reinterpret_cast(data_packet + 1)));
+ }
+ }
+ m_data_req.insert(m_data_req.end(), data_content, data_content_end);
+
+ // Respond with ACK packet (empty packet).
+ m_data_res.clear();
+ m_send_res = true;
+ return EapPeerMethodResponseActionSend;
+ } else if (!m_data_req.empty()) {
+ // Last fragment received. Append data.
+ m_data_req.insert(m_data_req.end(), data_content, data_content_end);
+ } else {
+ // This is a complete non-fragmented packet.
+ m_data_req.assign(data_content, data_content_end);
+ }
+
+ if (m_send_res) {
+ // We are sending a fragmented message.
+ if (m_data_req.empty() && (data_packet[0] & (flags_length_incl | flags_more_frag | flags_start)) == 0) {
+ // Received packet is the ACK of our fragmented message packet. Send the next fragment.
+ return EapPeerMethodResponseActionSend;
+ } else
+ throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " ACK expected.");
+ }
+
+ // Process the data with underlying method.
+ auto action = method::process_request_packet(m_data_req.data(), (DWORD)m_data_req.size());
+
+ // Packet was processed. Clear its data since we use the absence of data to detect first of fragmented message packages.
+ m_data_req.clear();
+ return action;
+}
+
+
+void eap::method_defrag::get_response_packet(
+ _Out_ sanitizing_blob &packet,
+ _In_opt_ DWORD size_max)
+{
+ assert(size_max >= 5); // We can not do the fragmentation if we have less space than flags+length.
+
+ if (!m_send_res) {
+ // Get data from underlying method.
+ method::get_response_packet(m_data_res, MAXDWORD);
+ }
+
+ size_t size_data = m_data_res.size();
+ assert(size_data <= MAXDWORD); // Packets spanning over 4GB are not supported.
+
+ packet.clear();
+ if (size_data + 1 > size_max) {
+ // Write one fragment.
+ packet.push_back(flags_length_incl | flags_more_frag | m_version);
+ unsigned int length = htonl((unsigned int)size_data);
+ packet.insert(packet.end(), reinterpret_cast(&length), reinterpret_cast(&length + 1));
+ auto data_begin = m_data_res.begin() + 0, data_end = data_begin + (size_max - 5);
+ packet.insert(packet.end(), data_begin, data_end);
+ m_data_res.erase(data_begin, data_end);
+ m_send_res = true;
+ } else {
+ // Write single/last fragment.
+ packet.push_back(m_version);
+ packet.insert(packet.end(), m_data_res.begin(), m_data_res.end());
+ m_data_res.clear();
+ m_send_res = false;
+ }
+}
diff --git a/lib/TLS/src/StdAfx.h b/lib/TLS/src/StdAfx.h
index 78ab7db..810c157 100644
--- a/lib/TLS/src/StdAfx.h
+++ b/lib/TLS/src/StdAfx.h
@@ -22,6 +22,7 @@
#include "../include/Config.h"
#include "../include/Credentials.h"
+#include "../include/Method.h"
#include "../../EAPBase/include/EAPXML.h"
diff --git a/lib/TTLS/include/Method.h b/lib/TTLS/include/Method.h
index 1409085..a5db103 100644
--- a/lib/TTLS/include/Method.h
+++ b/lib/TTLS/include/Method.h
@@ -20,7 +20,6 @@
namespace eap
{
- class method_defrag;
class method_eapmsg;
class method_tls_tunnel;
}
@@ -41,86 +40,6 @@ namespace eap
/// \addtogroup EAPBaseMethod
/// @{
- ///
- /// EAP-(T)TLS/PEAP class defragging method tunnel
- ///
- class method_defrag : public method
- {
- public:
-#pragma warning(push)
-#pragma warning(disable: 4480)
-
- ///
- /// EAP-(T)TLS/PEAP request/response packet flags
- ///
- /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.1 EAP-TLS Request Packet)](https://tools.ietf.org/html/rfc5216#section-3.1)
- /// \sa [The EAP-TLS Authentication Protocol (Chapter: 3.2 EAP-TLS Response Packet)](https://tools.ietf.org/html/rfc5216#section-3.2)
- /// \sa [The EAP-TTLS Authentication Protocol Version 0 (Chapter: 9.1. Packet Format)](https://tools.ietf.org/html/rfc5281#section-9.1)
- /// \sa [Protected EAP Protocol (PEAP) Version 2 (Chapter: 3.2. PEAPv2 Packet Format)](https://tools.ietf.org/html/draft-josefsson-pppext-eap-tls-eap-10#section-3.2)
- ///
- enum flags_t : unsigned char {
- flags_length_incl = 0x80, ///< Length included
- flags_more_frag = 0x40, ///< More fragments
- flags_start = 0x20, ///< Start
- flags_tls_length_incl = 0x10, ///< TLS Length included
- flags_ver_mask = 0x07, ///< Version mask
- };
-
-#pragma warning(pop)
-
- public:
- ///
- /// Constructs a method
- ///
- /// \param[in] mod Module to use for global services
- /// \param[in] version_max Maximum protocol version supported by peer
- /// \param[in] inner Inner method
- ///
- method_defrag(_In_ module &mod, _In_ unsigned char version_max, _In_ method *inner);
-
- /// \name Session management
- /// @{
-
- virtual void begin_session(
- _In_ DWORD dwFlags,
- _In_ const EapAttributes *pAttributeArray,
- _In_ HANDLE hTokenImpersonateUser,
- _In_opt_ DWORD dwMaxSendPacketSize = MAXDWORD);
-
- /// @}
-
- /// \name Packet processing
- /// @{
-
- virtual EapPeerMethodResponseAction process_request_packet(
- _In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
- _In_ DWORD dwReceivedPacketSize);
-
- virtual void get_response_packet(
- _Out_ sanitizing_blob &packet,
- _In_opt_ DWORD size_max = MAXDWORD);
-
- /// @}
-
- public:
- unsigned char m_version; ///< Negotiated protocol version
-
- protected:
- sanitizing_blob m_data_req; ///< Data in request
- sanitizing_blob m_data_res; ///< Data in response
- bool m_send_res; ///< Are we sending a response?
-
- ///
- /// Communication phase
- ///
- enum class phase_t {
- unknown = -1, ///< Unknown phase
- init = 0, ///< Binding exchange
- established, ///< Connection established
- } m_phase; ///< What phase is our communication at?
- };
-
-
///
/// Diameter EAP-Message tunnel method
///
diff --git a/lib/TTLS/src/Method.cpp b/lib/TTLS/src/Method.cpp
index a4bfbd6..ebed10c 100644
--- a/lib/TTLS/src/Method.cpp
+++ b/lib/TTLS/src/Method.cpp
@@ -26,138 +26,6 @@ using namespace std;
using namespace winstd;
-//////////////////////////////////////////////////////////////////////
-// eap::method_defrag
-//////////////////////////////////////////////////////////////////////
-
-eap::method_defrag::method_defrag(_In_ module &mod, _In_ unsigned char version_max, _In_ method *inner) :
- m_version(version_max),
- m_phase(phase_t::unknown),
- m_send_res(false),
- method(mod, inner)
-{
-}
-
-
-void eap::method_defrag::begin_session(
- _In_ DWORD dwFlags,
- _In_ const EapAttributes *pAttributeArray,
- _In_ HANDLE hTokenImpersonateUser,
- _In_opt_ DWORD dwMaxSendPacketSize)
-{
- // Inner method may generate packets of up to 4GB.
- // But, we can not do the fragmentation if we have less space than flags+length.
- if (dwMaxSendPacketSize < 5)
- throw invalid_argument(string_printf(__FUNCTION__ " Maximum packet size too small (minimum: %u, available: %u).", 5, dwMaxSendPacketSize));
- method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, MAXDWORD);
-
- m_phase = phase_t::init;
-}
-
-
-EapPeerMethodResponseAction eap::method_defrag::process_request_packet(
- _In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
- _In_ DWORD dwReceivedPacketSize)
-{
- auto data_packet = reinterpret_cast(pReceivedPacket);
-
- if (dwReceivedPacketSize < 1)
- throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete packet flags.");
-
- // To prevent version downgrade attacks, negotiate protocol version on binding exchange only. Then stick to it!
- unsigned char data_version = data_packet[0] & flags_ver_mask;
- if (m_phase == phase_t::init) {
- m_version = min(data_version, m_version);
- m_module.log_event(&EAPMETHOD_DEFRAG_VERSION,
- event_data(m_version),
- event_data(data_version),
- event_data::blank);
- m_phase = phase_t::established;
- } else if (data_version != m_version)
- throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Protocol version mismatch.");
-
- // Get packet content pointers for more readable code later on.
- auto
- data_content = data_packet + (data_packet[0] & flags_length_incl ? 5 : 1),
- data_content_end = data_packet + dwReceivedPacketSize;
- if (data_content > data_content_end)
- throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " Incomplete data.");
-
- // Do the defragmentation.
- if (data_packet[0] & flags_more_frag) {
- if (m_data_req.empty()) {
- // Start a new packet.
- if (data_packet[0] & flags_length_incl) {
- // Preallocate data according to the Length field.
- m_data_req.reserve(ntohl(*reinterpret_cast(data_packet + 1)));
- }
- }
- m_data_req.insert(m_data_req.end(), data_content, data_content_end);
-
- // Respond with ACK packet (empty packet).
- m_data_res.clear();
- m_send_res = true;
- return EapPeerMethodResponseActionSend;
- } else if (!m_data_req.empty()) {
- // Last fragment received. Append data.
- m_data_req.insert(m_data_req.end(), data_content, data_content_end);
- } else {
- // This is a complete non-fragmented packet.
- m_data_req.assign(data_content, data_content_end);
- }
-
- if (m_send_res) {
- // We are sending a fragmented message.
- if (m_data_req.empty() && (data_packet[0] & (flags_length_incl | flags_more_frag | flags_start)) == 0) {
- // Received packet is the ACK of our fragmented message packet. Send the next fragment.
- return EapPeerMethodResponseActionSend;
- } else
- throw win_runtime_error(EAP_E_EAPHOST_METHOD_INVALID_PACKET, __FUNCTION__ " ACK expected.");
- }
-
- // Process the data with underlying method.
- auto action = method::process_request_packet(m_data_req.data(), (DWORD)m_data_req.size());
-
- // Packet was processed. Clear its data since we use the absence of data to detect first of fragmented message packages.
- m_data_req.clear();
- return action;
-}
-
-
-void eap::method_defrag::get_response_packet(
- _Out_ sanitizing_blob &packet,
- _In_opt_ DWORD size_max)
-{
- assert(size_max >= 5); // We can not do the fragmentation if we have less space than flags+length.
-
- if (!m_send_res) {
- // Get data from underlying method.
- method::get_response_packet(m_data_res, MAXDWORD);
- }
-
- size_t size_data = m_data_res.size();
- assert(size_data <= MAXDWORD); // Packets spanning over 4GB are not supported.
-
- packet.clear();
- if (size_data + 1 > size_max) {
- // Write one fragment.
- packet.push_back(flags_length_incl | flags_more_frag | m_version);
- unsigned int length = htonl((unsigned int)size_data);
- packet.insert(packet.end(), reinterpret_cast(&length), reinterpret_cast(&length + 1));
- auto data_begin = m_data_res.begin() + 0, data_end = data_begin + (size_max - 5);
- packet.insert(packet.end(), data_begin, data_end);
- m_data_res.erase(data_begin, data_end);
- m_send_res = true;
- } else {
- // Write single/last fragment.
- packet.push_back(m_version);
- packet.insert(packet.end(), m_data_res.begin(), m_data_res.end());
- m_data_res.clear();
- m_send_res = false;
- }
-}
-
-
//////////////////////////////////////////////////////////////////////
// eap::method_eapmsg
//////////////////////////////////////////////////////////////////////
diff --git a/lib/TTLS/src/StdAfx.h b/lib/TTLS/src/StdAfx.h
index 7e028eb..076b835 100644
--- a/lib/TTLS/src/StdAfx.h
+++ b/lib/TTLS/src/StdAfx.h
@@ -27,6 +27,8 @@
#include "../include/Method.h"
#include "../include/Module.h"
+#include "../../TLS/include/Method.h"
+
#include "../../PAP/include/Config.h"
#include "../../PAP/include/Method.h"