diff --git a/implementation/e2e_protection/include/buffer/buffer.hpp b/implementation/e2e_protection/include/buffer/buffer.hpp index 95205f8db..678828172 100644 --- a/implementation/e2e_protection/include/buffer/buffer.hpp +++ b/implementation/e2e_protection/include/buffer/buffer.hpp @@ -36,6 +36,8 @@ class buffer_view { const uint8_t *end(void) const { return data_ptr_ + data_length_; } + size_t data_length(void) const { return data_length_; } + private: const uint8_t *data_ptr_; size_t data_length_; diff --git a/implementation/e2e_protection/include/crc/crc.hpp b/implementation/e2e_protection/include/crc/crc.hpp index ab7b959e7..ac8e448f2 100644 --- a/implementation/e2e_protection/include/crc/crc.hpp +++ b/implementation/e2e_protection/include/crc/crc.hpp @@ -17,6 +17,8 @@ class e2e_crc { const uint8_t _start_value = 0x00U); static uint32_t calculate_profile_04(buffer_view _buffer_view, const uint32_t _start_value = 0x00000000U); + static uint16_t calculate_profile_05(buffer_view _buffer_view, + const uint16_t _start_value = 0xFFFFU); static uint64_t calculate_profile_07(buffer_view _buffer_view, const uint64_t _start_value = 0x0000000000000000U); @@ -25,6 +27,7 @@ class e2e_crc { private: static const uint8_t lookup_table_profile_01_[256]; static const uint32_t lookup_table_profile_04_[256]; + static const uint16_t lookup_table_profile_05_[256]; static const uint64_t lookup_table_profile_07_[256]; static const uint32_t lookup_table_profile_custom_[256]; diff --git a/implementation/e2e_protection/include/e2e/profile/profile05/checker.hpp b/implementation/e2e_protection/include/e2e/profile/profile05/checker.hpp new file mode 100644 index 000000000..3805132b0 --- /dev/null +++ b/implementation/e2e_protection/include/e2e/profile/profile05/checker.hpp @@ -0,0 +1,47 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE05_CHECKER_HPP +#define VSOMEIP_V3_E2E_PROFILE05_CHECKER_HPP + +#include + +#include "../profile05/profile_05.hpp" +#include "../profile_interface/checker.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +class profile_05_checker final : public e2e::profile_interface::checker { + +public: + profile_05_checker(void) = delete; + + // [SWS_E2E_00389] initialize state + explicit profile_05_checker(const profile_config &_config) : + config_(_config) {} + + void check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) override final; + +private: + bool verify_input(const e2e_buffer &_buffer) const; + bool verify_counter(instance_t _instance, uint8_t _received_counter); + + bool read_8(const e2e_buffer &_buffer, uint8_t &_data, size_t _index) const; + bool read_16(const e2e_buffer &_buffer, uint16_t &_data, size_t _index) const; + + std::mutex check_mutex_; + + profile_config config_; + std::map counter_; +}; + +} // namespace profile_05 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE05_CHECKER_HPP diff --git a/implementation/e2e_protection/include/e2e/profile/profile05/profile_05.hpp b/implementation/e2e_protection/include/e2e/profile/profile05/profile_05.hpp new file mode 100644 index 000000000..92d5a26eb --- /dev/null +++ b/implementation/e2e_protection/include/e2e/profile/profile05/profile_05.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE05_PROFILE05_HPP +#define VSOMEIP_V3_E2E_PROFILE05_PROFILE05_HPP + +#include + +#include + +#include "../../../buffer/buffer.hpp" + +// The MSB of the dataID is the instance identifier. +// Therefore, the instance identifier must fit into a single byte. +#define VSOMEIP_E2E_PROFILE05_MAX_INSTANCE 0x00ff + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +struct profile_config; + +class profile_05 { +public: + static uint16_t compute_crc(const profile_config &_config, const e2e_buffer &_buffer); + + static bool is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer); +}; + +struct profile_config { + profile_config() = delete; + + profile_config(uint32_t _data_id, uint16_t _data_length, + size_t _offset, uint16_t _max_delta_counter) + + : data_id_(_data_id), data_length_(_data_length), + offset_(_offset), max_delta_counter_(_max_delta_counter), + base_(VSOMEIP_SOMEIP_HEADER_SIZE) { + } + profile_config(const profile_config &_config) = default; + profile_config &operator=(const profile_config &_config) = default; + + uint32_t data_id_; + uint16_t data_length_; + size_t offset_; // This must be configured in bit but as a multiple of 8. + // As we must use it as an index, we do the math once at + // configuration time and use the correct data type here. + // Thus, this value is always the byte where the CRC starts. + uint16_t max_delta_counter_; + + // SOME/IP base + size_t base_; +}; + +} // namespace profile_05 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE05_PROFILE05_HPP diff --git a/implementation/e2e_protection/include/e2e/profile/profile05/protector.hpp b/implementation/e2e_protection/include/e2e/profile/profile05/protector.hpp new file mode 100644 index 000000000..a65968518 --- /dev/null +++ b/implementation/e2e_protection/include/e2e/profile/profile05/protector.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef VSOMEIP_V3_E2E_PROFILE05_PROTECTOR_HPP +#define VSOMEIP_V3_E2E_PROFILE05_PROTECTOR_HPP + +#include +#include + +#include "../profile05/profile_05.hpp" +#include "../profile_interface/protector.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +class protector final : public e2e::profile_interface::protector { +public: + protector(void) = delete; + + explicit protector(const profile_config &_config) + : config_(_config) {} + + void protect(e2e_buffer &_buffer, instance_t _instance) override final; + +private: + bool verify_inputs(e2e_buffer &_buffer); + uint8_t get_counter(instance_t _instance) const; + void increment_counter(instance_t _instance); + + void write_counter(e2e_buffer &_buffer, uint8_t _data, size_t _index); + void write_crc(e2e_buffer &_buffer, uint16_t _data, size_t _index); + +private: + profile_config config_; + std::map counter_; + std::mutex protect_mutex_; +}; + +} // namespace profile_05 +} // namespace e2e +} // namespace vsomeip_v3 + +#endif // VSOMEIP_V3_E2E_PROFILE05_PROTECTOR_HPP diff --git a/implementation/e2e_protection/src/crc/crc.cpp b/implementation/e2e_protection/src/crc/crc.cpp index 4c79c9f41..89b70d0e5 100644 --- a/implementation/e2e_protection/src/crc/crc.cpp +++ b/implementation/e2e_protection/src/crc/crc.cpp @@ -120,6 +120,63 @@ const uint32_t e2e_crc::lookup_table_profile_04_[256] = { 0x0C8DF352U, 0x3C08FCA7U, 0x6D87ECB8U, 0x5D02E34DU, 0xCE99CC86U, 0xFE1CC373U, 0xAF93D36CU, 0x9F16DC99U }; + +/** +* Calculates the CRC16 over the provided range. +*/ +uint16_t e2e_crc::calculate_profile_05(buffer_view _buffer_view, const uint16_t _start_value) { + const uint8_t * buffer = _buffer_view.begin(); + uint32_t buffer_length = (uint32_t)_buffer_view.data_length(); + uint16_t crc = _start_value; + + /* Process all data (byte wise) */ + for (uint32_t i = 0; i < buffer_length; ++i) { + /* Process one byte of data */ + crc = lookup_table_profile_05_[((uint8_t)(crc >> 8U)) ^ buffer[i]] ^ + ((uint16_t)(crc << 8U)); + } + + /* Specified final XOR value for CRC16 is 0, no need to actually xor anything here */ + return crc; +} + + +const uint16_t e2e_crc::lookup_table_profile_05_[256] = { + 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50A5U, 0x60C6U, 0x70E7U, + 0x8108U, 0x9129U, 0xA14AU, 0xB16BU, 0xC18CU, 0xD1ADU, 0xE1CEU, 0xF1EFU, + 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52B5U, 0x4294U, 0x72F7U, 0x62D6U, + 0x9339U, 0x8318U, 0xB37BU, 0xA35AU, 0xD3BDU, 0xC39CU, 0xF3FFU, 0xE3DEU, + 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64E6U, 0x74C7U, 0x44A4U, 0x5485U, + 0xA56AU, 0xB54BU, 0x8528U, 0x9509U, 0xE5EEU, 0xF5CFU, 0xC5ACU, 0xD58DU, + 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76D7U, 0x66F6U, 0x5695U, 0x46B4U, + 0xB75BU, 0xA77AU, 0x9719U, 0x8738U, 0xF7DFU, 0xE7FEU, 0xD79DU, 0xC7BCU, + 0x48C4U, 0x58E5U, 0x6886U, 0x78A7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, + 0xC9CCU, 0xD9EDU, 0xE98EU, 0xF9AFU, 0x8948U, 0x9969U, 0xA90AU, 0xB92BU, + 0x5AF5U, 0x4AD4U, 0x7AB7U, 0x6A96U, 0x1A71U, 0x0A50U, 0x3A33U, 0x2A12U, + 0xDBFDU, 0xCBDCU, 0xFBBFU, 0xEB9EU, 0x9B79U, 0x8B58U, 0xBB3BU, 0xAB1AU, + 0x6CA6U, 0x7C87U, 0x4CE4U, 0x5CC5U, 0x2C22U, 0x3C03U, 0x0C60U, 0x1C41U, + 0xEDAEU, 0xFD8FU, 0xCDECU, 0xDDCDU, 0xAD2AU, 0xBD0BU, 0x8D68U, 0x9D49U, + 0x7E97U, 0x6EB6U, 0x5ED5U, 0x4EF4U, 0x3E13U, 0x2E32U, 0x1E51U, 0x0E70U, + 0xFF9FU, 0xEFBEU, 0xDFDDU, 0xCFFCU, 0xBF1BU, 0xAF3AU, 0x9F59U, 0x8F78U, + 0x9188U, 0x81A9U, 0xB1CAU, 0xA1EBU, 0xD10CU, 0xC12DU, 0xF14EU, 0xE16FU, + 0x1080U, 0x00A1U, 0x30C2U, 0x20E3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, + 0x83B9U, 0x9398U, 0xA3FBU, 0xB3DAU, 0xC33DU, 0xD31CU, 0xE37FU, 0xF35EU, + 0x02B1U, 0x1290U, 0x22F3U, 0x32D2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, + 0xB5EAU, 0xA5CBU, 0x95A8U, 0x8589U, 0xF56EU, 0xE54FU, 0xD52CU, 0xC50DU, + 0x34E2U, 0x24C3U, 0x14A0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, + 0xA7DBU, 0xB7FAU, 0x8799U, 0x97B8U, 0xE75FU, 0xF77EU, 0xC71DU, 0xD73CU, + 0x26D3U, 0x36F2U, 0x0691U, 0x16B0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, + 0xD94CU, 0xC96DU, 0xF90EU, 0xE92FU, 0x99C8U, 0x89E9U, 0xB98AU, 0xA9ABU, + 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18C0U, 0x08E1U, 0x3882U, 0x28A3U, + 0xCB7DU, 0xDB5CU, 0xEB3FU, 0xFB1EU, 0x8BF9U, 0x9BD8U, 0xABBBU, 0xBB9AU, + 0x4A75U, 0x5A54U, 0x6A37U, 0x7A16U, 0x0AF1U, 0x1AD0U, 0x2AB3U, 0x3A92U, + 0xFD2EU, 0xED0FU, 0xDD6CU, 0xCD4DU, 0xBDAAU, 0xAD8BU, 0x9DE8U, 0x8DC9U, + 0x7C26U, 0x6C07U, 0x5C64U, 0x4C45U, 0x3CA2U, 0x2C83U, 0x1CE0U, 0x0CC1U, + 0xEF1FU, 0xFF3EU, 0xCF5DU, 0xDF7CU, 0xAF9BU, 0xBFBAU, 0x8FD9U, 0x9FF8U, + 0x6E17U, 0x7E36U, 0x4E55U, 0x5E74U, 0x2E93U, 0x3EB2U, 0x0ED1U, 0x1EF0U +}; + + /** * Calculates the CRC over the provided range. * diff --git a/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp b/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp index e441b5323..3a9643ee9 100644 --- a/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp +++ b/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp @@ -18,6 +18,10 @@ #include "../../../../e2e_protection/include/e2e/profile/profile04/profile_04.hpp" #include "../../../../e2e_protection/include/e2e/profile/profile04/protector.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile05/checker.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile05/profile_05.hpp" +#include "../../../../e2e_protection/include/e2e/profile/profile05/protector.hpp" + #include "../../../../e2e_protection/include/e2e/profile/profile_custom/checker.hpp" #include "../../../../e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp" #include "../../../../e2e_protection/include/e2e/profile/profile_custom/protector.hpp" @@ -86,6 +90,11 @@ bool e2e_provider_impl::add_configuration(std::shared_ptr config) return true; } + if (config->profile == "P05") { + process_e2e_profile(config); + return true; + } + if (config->profile == "P07") { process_e2e_profile(config); return true; @@ -178,6 +187,26 @@ e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr &_con min_data_length, max_data_length, max_delta_counter); } +template<> +vsomeip_v3::e2e::profile05::profile_config +e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr &_config) { + + uint32_t data_id = read_value_from_config(_config, "data_id"); + uint16_t data_length = read_value_from_config(_config, "data_length"); + + size_t offset = read_value_from_config(_config, "crc_offset"); + if (offset % 8) + VSOMEIP_ERROR << "Offset in E2E P05 configuration must be multiple of 8" + " (" << offset << ")"; + offset /= 8; + + uint16_t max_delta_counter = read_value_from_config(_config, + "max_delta_counter", uint16_t(0xffff)); + + return e2e::profile05::profile_config(data_id, data_length, + offset, max_delta_counter); +} + template<> e2e::profile_custom::profile_config e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr& config) { diff --git a/implementation/e2e_protection/src/e2e/profile/profile05/checker.cpp b/implementation/e2e_protection/src/e2e/profile/profile05/checker.cpp new file mode 100644 index 000000000..bb943ba72 --- /dev/null +++ b/implementation/e2e_protection/src/e2e/profile/profile05/checker.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include + +#include "../../../../include/e2e/profile/profile05/checker.hpp" +#include "../../../../../utility/include/byteorder.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +void profile_05_checker::check(const e2e_buffer &_buffer, instance_t _instance, + e2e::profile_interface::check_status_t &_generic_check_status) { + + (void)_instance; + + std::lock_guard lock(check_mutex_); + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR; + + if (_instance > VSOMEIP_E2E_PROFILE05_MAX_INSTANCE) { + VSOMEIP_ERROR << "E2E Profile 5 can only be used for instances [1-255]"; + return; + } + + if (profile_05::is_buffer_length_valid(config_, _buffer)) { + uint8_t its_received_counter; + if (read_8(_buffer, its_received_counter, 2)) { + uint16_t its_received_crc; + if (read_16(_buffer, its_received_crc, 0)) { + uint16_t its_crc = profile_05::compute_crc(config_, _buffer); + if (its_received_crc != its_crc) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_WRONG_CRC; + VSOMEIP_ERROR << std::hex << "E2E P05 protection: CRC16 does not match: calculated CRC: " + << its_crc << " received CRC: " << its_received_crc; + } else { + if (verify_counter(_instance, its_received_counter)) { + _generic_check_status = e2e::profile_interface::generic_check_status::E2E_OK; + } + } + } + } + } +} + +bool +profile_05_checker::verify_counter(instance_t _instance, uint8_t _received_counter) { + + uint8_t its_delta(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) { + uint8_t its_counter = find_counter->second; + if (its_counter < _received_counter) + its_delta = uint8_t(_received_counter - its_counter); + else + its_delta = uint8_t(uint8_t(0xff) - its_counter + _received_counter); + } else { + counter_[_instance] = _received_counter; + } + + return (its_delta <= config_.max_delta_counter_); +} + +bool +profile_05_checker::read_8(const e2e_buffer &_buffer, + uint8_t &_data, size_t _index) const { + + _data = _buffer[config_.offset_ + _index]; + return true; +} + +bool +profile_05_checker::read_16(const e2e_buffer &_buffer, + uint16_t &_data, size_t _index) const { + + _data = VSOMEIP_BYTES_TO_WORD(_buffer[config_.offset_ + _index + 1], + _buffer[config_.offset_ + _index]); + return true; +} + +} // namespace profile01 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/implementation/e2e_protection/src/e2e/profile/profile05/profile_05.cpp b/implementation/e2e_protection/src/e2e/profile/profile05/profile_05.cpp new file mode 100644 index 000000000..03efc444f --- /dev/null +++ b/implementation/e2e_protection/src/e2e/profile/profile05/profile_05.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "../../../../include/crc/crc.hpp" +#include "../../../../include/e2e/profile/profile05/profile_05.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +uint16_t profile_05::compute_crc(const profile_config &_config, const e2e_buffer &_buffer) { + + static const int crcSize = sizeof(uint16_t); + + buffer_view its_before(_buffer, _config.offset_); + uint16_t computed_crc = e2e_crc::calculate_profile_05(its_before); + + if ((_config.offset_ + crcSize) < _buffer.size()) { + buffer_view its_after(_buffer, _config.offset_ + crcSize, _buffer.size()); + computed_crc = e2e_crc::calculate_profile_05(its_after, computed_crc); + } + + uint8_t dataId[2]; + dataId[0] = (_config.data_id_ >> 0) & 0xFF; + dataId[1] = (_config.data_id_ >> 8) & 0xFF; + buffer_view dataIdView(dataId, sizeof(dataId)); + + computed_crc = e2e_crc::calculate_profile_05(dataIdView, computed_crc); + + return computed_crc; +} + +bool profile_05::is_buffer_length_valid(const profile_config &_config, const e2e_buffer &_buffer) { + return ((_config.data_length_ / 8) + 1U <= _buffer.size()); +} +} // namespace profile05 +} // namespace e2e +} // namespace vsomeip_v3 diff --git a/implementation/e2e_protection/src/e2e/profile/profile05/protector.cpp b/implementation/e2e_protection/src/e2e/profile/profile05/protector.cpp new file mode 100644 index 000000000..f8ab9de4e --- /dev/null +++ b/implementation/e2e_protection/src/e2e/profile/profile05/protector.cpp @@ -0,0 +1,78 @@ +// Copyright (C) 2020-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include "../../../../include/e2e/profile/profile05/protector.hpp" +#include "../../../../../utility/include/byteorder.hpp" + +namespace vsomeip_v3 { +namespace e2e { +namespace profile05 { + +void protector::protect(e2e_buffer &_buffer, instance_t _instance) { + + (void)_instance; + + std::lock_guard lock(protect_mutex_); + + if (_instance > VSOMEIP_E2E_PROFILE05_MAX_INSTANCE) { + VSOMEIP_ERROR << "E2E Profile 5 can only be used for instances [1-255]"; + return; + } + + if (profile_05::is_buffer_length_valid(config_, _buffer)) { + // write the current Counter value in Data + write_counter(_buffer, get_counter(_instance), 2); + + // compute the CRC + uint16_t its_crc = profile_05::compute_crc(config_, _buffer); + + write_crc(_buffer, its_crc, 0); + + // increment the Counter (new value will be used in the next invocation of E2E_P05Protect()), + increment_counter(_instance); + } +} + +void +protector::write_counter(e2e_buffer &_buffer, uint8_t _data, size_t _index) { + + _buffer[config_.offset_ + _index] = _data; +} + +void +protector::write_crc(e2e_buffer &_buffer, uint16_t _data, size_t _index) { + + _buffer[config_.offset_ + _index] = VSOMEIP_WORD_BYTE0(_data); + _buffer[config_.offset_ + _index + 1] = VSOMEIP_WORD_BYTE1(_data); +} + +uint8_t +protector::get_counter(instance_t _instance) const { + + uint8_t its_counter(0); + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + its_counter = find_counter->second; + + return its_counter; +} + +void +protector::increment_counter(instance_t _instance) { + + auto find_counter = counter_.find(_instance); + if (find_counter != counter_.end()) + find_counter->second++; + else + counter_[_instance] = 1; +} + +} // namespace profile05 +} // namespace e2e +} // namespace vsomeip_v3