diff --git a/include/dot11.h b/include/dot11.h index 255e596..14a960a 100644 --- a/include/dot11.h +++ b/include/dot11.h @@ -35,6 +35,7 @@ #include "small_uint.h" namespace Tins { + class RSNInformation; /** * \brief Class representing an 802.11 frame. @@ -509,132 +510,6 @@ namespace Tins { std::list _options; }; - /** - * \brief Class that models the RSN information structure. - */ - class RSNInformation { - public: - /** - * \brief Enum that represents the different cypher suites. - */ - enum CypherSuites { - WEP_40 = 0x01ac0f00, - TKIP = 0x02ac0f00, - CCMP = 0x04ac0f00, - WEP_104 = 0x05ac0f00 - }; - - /** - * \brief Enum that represents the different akm suites. - */ - enum AKMSuites { - PMKSA = 0x01ac0f00, - PSK = 0x02ac0f00 - }; - - /** - * The type used to store the cypher suites. - */ - typedef std::vector cyphers_type; - - /** - * The type used to store the AKM suites. - */ - typedef std::vector akm_type; - - /** - * The type returned on serialization. - */ - typedef std::vector serialization_type; - - /** - * \brief Creates an instance of RSNInformation. - * - * By default, the version is set to 1. - */ - RSNInformation(); - - /** - * \brief Helper function to create a WPA2-PSK RSNInformation - * \return An instance RSNInformation which contains information - * for a WPA2-PSK AP. - */ - static RSNInformation wpa2_psk(); - - /** - * \brief Adds a pairwise cypher suite. - * \param cypher The pairwise cypher suite to be added. - */ - void add_pairwise_cypher(CypherSuites cypher); - - /** - * \brief Adds a akm suite. - * \param akm The akm suite to be added. - */ - void add_akm_cypher(AKMSuites akm); - - /** - * \brief Sets the group suite cypher. - * \param group The group suite cypher to be set. - */ - void group_suite(CypherSuites group); - - /** - * \brief Sets the version. - * \param ver The version to be set. - */ - void version(uint16_t ver); - - /** - * \brief Sets the capabilities field. - * \param cap The capabilities to be set. - */ - void capabilities(uint16_t cap); - - /* Getters */ - - /** - * \brief Getter for the group suite field. - * \return The group suite field. - */ - CypherSuites group_suite() const { return _group_suite; } - - /** - * \brief Getter for the version field. - * \return The version field. - */ - uint16_t version() const { return Utils::le_to_host(_version); } - - /** - * \brief Getter for the capabilities field. - * \return The version field. - */ - uint16_t capabilities() const { return Utils::le_to_host(_capabilities); } - - /** - * \brief Getter for the pairwise cypher suite list. - * \return A list of pairwise cypher suites. - */ - const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; } - - /** - * \brief Getter for the akm suite list. - * \return A list of akm suites. - */ - const akm_type &akm_cyphers() const { return _akm_cyphers; } - - /** - * \brief Serializes this object. - * \return The result of the serialization. - */ - serialization_type serialize() const; - private: - uint16_t _version, _capabilities; - CypherSuites _group_suite; - akm_type _akm_cyphers; - cyphers_type _pairwise_cyphers; - }; - /** * \brief Abstract class that englobes all Management frames in the 802.11 protocol. */ diff --git a/include/rsn_information.h b/include/rsn_information.h new file mode 100644 index 0000000..e6276f0 --- /dev/null +++ b/include/rsn_information.h @@ -0,0 +1,159 @@ +/* + * libtins is a net packet wrapper library for crafting and + * interpreting sniffed packets. + * + * Copyright (C) 2011 Nasel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef TINS_RSN_INFORMATION +#define TINS_RSN_INFORMATION + +#include +#include +#include "utils.h" + +namespace Tins{ + /** + * \brief Class that models the RSN information structure. + */ + class RSNInformation { + public: + /** + * \brief Enum that represents the different cypher suites. + */ + enum CypherSuites { + WEP_40 = 0x01ac0f00, + TKIP = 0x02ac0f00, + CCMP = 0x04ac0f00, + WEP_104 = 0x05ac0f00 + }; + + /** + * \brief Enum that represents the different akm suites. + */ + enum AKMSuites { + PMKSA = 0x01ac0f00, + PSK = 0x02ac0f00 + }; + + /** + * The type used to store the cypher suites. + */ + typedef std::vector cyphers_type; + + /** + * The type used to store the AKM suites. + */ + typedef std::vector akm_type; + + /** + * The type returned on serialization. + */ + typedef std::vector serialization_type; + + /** + * \brief Creates an instance of RSNInformation. + * + * By default, the version is set to 1. + */ + RSNInformation(); + + RSNInformation(const uint8_t *buffer, uint32_t total_sz); + + /** + * \brief Helper function to create a WPA2-PSK RSNInformation + * \return An instance RSNInformation which contains information + * for a WPA2-PSK AP. + */ + static RSNInformation wpa2_psk(); + + /** + * \brief Adds a pairwise cypher suite. + * \param cypher The pairwise cypher suite to be added. + */ + void add_pairwise_cypher(CypherSuites cypher); + + /** + * \brief Adds a akm suite. + * \param akm The akm suite to be added. + */ + void add_akm_cypher(AKMSuites akm); + + /** + * \brief Sets the group suite cypher. + * \param group The group suite cypher to be set. + */ + void group_suite(CypherSuites group); + + /** + * \brief Sets the version. + * \param ver The version to be set. + */ + void version(uint16_t ver); + + /** + * \brief Sets the capabilities field. + * \param cap The capabilities to be set. + */ + void capabilities(uint16_t cap); + + /* Getters */ + + /** + * \brief Getter for the group suite field. + * \return The group suite field. + */ + CypherSuites group_suite() const { return _group_suite; } + + /** + * \brief Getter for the version field. + * \return The version field. + */ + uint16_t version() const { return Utils::le_to_host(_version); } + + /** + * \brief Getter for the capabilities field. + * \return The version field. + */ + uint16_t capabilities() const { return Utils::le_to_host(_capabilities); } + + /** + * \brief Getter for the pairwise cypher suite list. + * \return A list of pairwise cypher suites. + */ + const cyphers_type &pairwise_cyphers() const { return _pairwise_cyphers; } + + /** + * \brief Getter for the akm suite list. + * \return A list of akm suites. + */ + const akm_type &akm_cyphers() const { return _akm_cyphers; } + + /** + * \brief Serializes this object. + * \return The result of the serialization. + */ + serialization_type serialize() const; + private: + uint16_t _version, _capabilities; + CypherSuites _group_suite; + akm_type _akm_cyphers; + cyphers_type _pairwise_cyphers; + }; +} // namespace Tins + +#endif // TINS_RSN_INFORMATION diff --git a/include/small_uint.h b/include/small_uint.h new file mode 100644 index 0000000..b47c556 --- /dev/null +++ b/include/small_uint.h @@ -0,0 +1,74 @@ +#ifndef TINS_SMALL_UINT_H +#define TINS_SMALL_UINT_H + +#include +#include + +namespace Tins { +template +class small_uint { +private: + template + struct if_then_else { + typedef OnTrue type; + }; + + template + struct if_then_else { + typedef OnFalse type; + }; + + template + struct best_type { + typedef typename if_then_else< + (i <= 8), + uint8_t, + typename if_then_else< + (i <= 16), + uint16_t, + typename if_then_else< + (i <= 32), + uint32_t, + uint64_t + >::type + >::type + >::type type; + }; + + template + struct power { + static const uint64_t value = base * power::value; + }; + + template + struct power { + static const uint64_t value = 1; + }; +public: + class value_to_large : public std::exception { + public: + const char *what() const throw() { + return "Value is too large"; + } + }; + + typedef typename best_type::type repr_type; + static const repr_type max_value = power<2, n>::value - 1; + + small_uint() : value() {} + + small_uint(repr_type val) { + if(val > max_value) + throw value_to_large(); + value = val; + } + + operator repr_type() const { + return value; + } +private: + repr_type value; +}; + +} // namespace Tins +#endif // TINS_SMALL_UINT_H diff --git a/src/dot11.cpp b/src/dot11.cpp index de77972..a89c15a 100644 --- a/src/dot11.cpp +++ b/src/dot11.cpp @@ -35,6 +35,7 @@ #include "radiotap.h" #include "sniffer.h" #include "utils.h" +#include "rsn_information.h" #include "snap.h" using std::pair; @@ -569,46 +570,10 @@ void Dot11ManagementFrame::challenge_text(const std::string &text) { // Getters RSNInformation Dot11ManagementFrame::rsn_information() { - const char *err_msg = "Malformed RSN information option"; const Dot11::Dot11Option *option = search_option(RSN); if(!option || option->data_size() < (sizeof(uint16_t) << 1) + sizeof(uint32_t)) throw std::runtime_error("RSN information not set"); - RSNInformation rsn; - const uint8_t *buffer = option->data_ptr(); - uint32_t bytes_left = option->data_size(); - rsn.version(*(uint16_t*)buffer); - buffer += sizeof(uint16_t); - rsn.group_suite((RSNInformation::CypherSuites)*(uint32_t*)buffer); - buffer += sizeof(uint32_t); - - bytes_left -= (sizeof(uint16_t) << 1) + sizeof(uint32_t); - if(bytes_left < sizeof(uint16_t)) - throw std::runtime_error(err_msg); - uint16_t count = *(uint16_t*)buffer; - buffer += sizeof(uint16_t); - if(count * sizeof(uint32_t) > bytes_left) - throw std::runtime_error(err_msg); - bytes_left -= count * sizeof(uint32_t); - while(count--) { - rsn.add_pairwise_cypher((RSNInformation::CypherSuites)*(uint32_t*)buffer); - buffer += sizeof(uint32_t); - } - if(bytes_left < sizeof(uint16_t)) - throw std::runtime_error(err_msg); - count = *(uint16_t*)buffer; - buffer += sizeof(uint16_t); - bytes_left -= sizeof(uint16_t); - if(count * sizeof(uint32_t) > bytes_left) - throw std::runtime_error(err_msg); - bytes_left -= count * sizeof(uint32_t); - while(count--) { - rsn.add_akm_cypher((RSNInformation::AKMSuites)*(uint32_t*)buffer); - buffer += sizeof(uint32_t); - } - if(bytes_left < sizeof(uint16_t)) - throw std::runtime_error(err_msg); - rsn.capabilities(*(uint16_t*)buffer); - return rsn; + return RSNInformation(option->data_ptr(), option->data_size()); } string Dot11ManagementFrame::ssid() const { @@ -1568,64 +1533,4 @@ uint32_t Dot11BlockAck::header_size() const { return Dot11ControlTA::header_size() + sizeof(_start_sequence) + sizeof(_start_sequence) + sizeof(_bitmap); } -/* RSNInformation */ - -RSNInformation::RSNInformation() : _version(1), _capabilities(0) { - -} - -void RSNInformation::add_pairwise_cypher(CypherSuites cypher) { - _pairwise_cyphers.push_back(cypher); -} - -void RSNInformation::add_akm_cypher(AKMSuites akm) { - _akm_cyphers.push_back(akm); -} - -void RSNInformation::group_suite(CypherSuites group) { - _group_suite = group; -} - -void RSNInformation::version(uint16_t ver) { - _version = Utils::host_to_le(ver); -} - -void RSNInformation::capabilities(uint16_t cap) { - _capabilities = Utils::host_to_le(cap); -} - -RSNInformation::serialization_type RSNInformation::serialize() const { - uint32_t size = sizeof(_version) + sizeof(_capabilities) + sizeof(uint32_t); - size += (sizeof(uint16_t) << 1); // 2 lists count. - size += sizeof(uint32_t) * (_akm_cyphers.size() + _pairwise_cyphers.size()); - - serialization_type buffer(size); - serialization_type::value_type *ptr = &buffer[0]; - *(uint16_t*)ptr = _version; - ptr += sizeof(_version); - *(uint32_t*)ptr = _group_suite; - ptr += sizeof(uint32_t); - *(uint16_t*)ptr = _pairwise_cyphers.size(); - ptr += sizeof(uint16_t); - for(cyphers_type::const_iterator it = _pairwise_cyphers.begin(); it != _pairwise_cyphers.end(); ++it) { - *(uint32_t*)ptr = *it; - ptr += sizeof(uint32_t); - } - *(uint16_t*)ptr = _akm_cyphers.size(); - ptr += sizeof(uint16_t); - for(akm_type::const_iterator it = _akm_cyphers.begin(); it != _akm_cyphers.end(); ++it) { - *(uint32_t*)ptr = *it; - ptr += sizeof(uint32_t); - } - *(uint16_t*)ptr = _capabilities; - return buffer; -} - -RSNInformation RSNInformation::wpa2_psk() { - RSNInformation info; - info.group_suite(RSNInformation::CCMP); - info.add_pairwise_cypher(RSNInformation::CCMP); - info.add_akm_cypher(RSNInformation::PSK); - return info; -} } diff --git a/src/eapol.cpp b/src/eapol.cpp index c46ef36..3a149b4 100644 --- a/src/eapol.cpp +++ b/src/eapol.cpp @@ -24,6 +24,7 @@ #include #include "eapol.h" #include "dot11.h" +#include "rsn_information.h" namespace Tins { diff --git a/src/rsn_information.cpp b/src/rsn_information.cpp new file mode 100644 index 0000000..0bb261c --- /dev/null +++ b/src/rsn_information.cpp @@ -0,0 +1,120 @@ +/* + * libtins is a net packet wrapper library for crafting and + * interpreting sniffed packets. + * + * Copyright (C) 2011 Nasel + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "rsn_information.h" + +namespace Tins { +RSNInformation::RSNInformation() : _version(1), _capabilities(0) { + +} + +RSNInformation::RSNInformation(const uint8_t *buffer, uint32_t total_sz) { + const char *err_msg = "Malformed RSN information structure"; + version(Utils::le_to_host(*(uint16_t*)buffer)); + buffer += sizeof(uint16_t); + group_suite((RSNInformation::CypherSuites)*(uint32_t*)buffer); + buffer += sizeof(uint32_t); + + total_sz -= (sizeof(uint16_t) << 1) + sizeof(uint32_t); + if(total_sz < sizeof(uint16_t)) + throw std::runtime_error(err_msg); + uint16_t count = *(uint16_t*)buffer; + buffer += sizeof(uint16_t); + if(count * sizeof(uint32_t) > total_sz) + throw std::runtime_error(err_msg); + total_sz -= count * sizeof(uint32_t); + while(count--) { + add_pairwise_cypher((RSNInformation::CypherSuites)*(uint32_t*)buffer); + buffer += sizeof(uint32_t); + } + if(total_sz < sizeof(uint16_t)) + throw std::runtime_error(err_msg); + count = *(uint16_t*)buffer; + buffer += sizeof(uint16_t); + total_sz -= sizeof(uint16_t); + if(count * sizeof(uint32_t) > total_sz) + throw std::runtime_error(err_msg); + total_sz -= count * sizeof(uint32_t); + while(count--) { + add_akm_cypher((RSNInformation::AKMSuites)*(uint32_t*)buffer); + buffer += sizeof(uint32_t); + } + if(total_sz < sizeof(uint16_t)) + throw std::runtime_error(err_msg); + capabilities(Utils::le_to_host(*(uint16_t*)buffer)); +} + +void RSNInformation::add_pairwise_cypher(CypherSuites cypher) { + _pairwise_cyphers.push_back(cypher); +} + +void RSNInformation::add_akm_cypher(AKMSuites akm) { + _akm_cyphers.push_back(akm); +} + +void RSNInformation::group_suite(CypherSuites group) { + _group_suite = group; +} + +void RSNInformation::version(uint16_t ver) { + _version = Utils::host_to_le(ver); +} + +void RSNInformation::capabilities(uint16_t cap) { + _capabilities = Utils::host_to_le(cap); +} + +RSNInformation::serialization_type RSNInformation::serialize() const { + uint32_t size = sizeof(_version) + sizeof(_capabilities) + sizeof(uint32_t); + size += (sizeof(uint16_t) << 1); // 2 lists count. + size += sizeof(uint32_t) * (_akm_cyphers.size() + _pairwise_cyphers.size()); + + serialization_type buffer(size); + serialization_type::value_type *ptr = &buffer[0]; + *(uint16_t*)ptr = _version; + ptr += sizeof(_version); + *(uint32_t*)ptr = _group_suite; + ptr += sizeof(uint32_t); + *(uint16_t*)ptr = _pairwise_cyphers.size(); + ptr += sizeof(uint16_t); + for(cyphers_type::const_iterator it = _pairwise_cyphers.begin(); it != _pairwise_cyphers.end(); ++it) { + *(uint32_t*)ptr = *it; + ptr += sizeof(uint32_t); + } + *(uint16_t*)ptr = _akm_cyphers.size(); + ptr += sizeof(uint16_t); + for(akm_type::const_iterator it = _akm_cyphers.begin(); it != _akm_cyphers.end(); ++it) { + *(uint32_t*)ptr = *it; + ptr += sizeof(uint32_t); + } + *(uint16_t*)ptr = _capabilities; + return buffer; +} + +RSNInformation RSNInformation::wpa2_psk() { + RSNInformation info; + info.group_suite(RSNInformation::CCMP); + info.add_pairwise_cypher(RSNInformation::CCMP); + info.add_akm_cypher(RSNInformation::PSK); + return info; +} +} diff --git a/tests/src/dot11/beacon.cpp b/tests/src/dot11/beacon.cpp index b72aa4f..e9a861a 100644 --- a/tests/src/dot11/beacon.cpp +++ b/tests/src/dot11/beacon.cpp @@ -3,6 +3,7 @@ #include #include #include "dot11.h" +#include "rsn_information.h" #include "tests/dot11.h"