diff --git a/ccsrc/Framework/include/base_time.hh b/ccsrc/Framework/include/base_time.hh index 03fa8f6cd453f1ed6bcde16fff8b47b86b7a9ecf..ae67b57073b531569978ab9125b60c5bd4251e63 100644 --- a/ccsrc/Framework/include/base_time.hh +++ b/ccsrc/Framework/include/base_time.hh @@ -1,6 +1,6 @@ /*! * \file base_time.hh - * \brief Header file for the control port base_time functionality. + * \brief Header file for base_time functionality. * \author ETSI STF525 * \copyright ETSI Copyright Notification * No part may be reproduced except as authorized by written permission. diff --git a/ccsrc/Framework/include/codec_factory.hh b/ccsrc/Framework/include/codec_factory.hh index 9d09b73a1020be923e5a818d4c1e34da80d45bd6..ca93662ea36f8d12c763677a0824f637ff934565 100644 --- a/ccsrc/Framework/include/codec_factory.hh +++ b/ccsrc/Framework/include/codec_factory.hh @@ -32,7 +32,7 @@ public: //! \publicsection */ codec_factory(){}; /*! - * \fn codec* create_codec(const std::string & type, const std::string & param); + * \fn codec* create_codec(const std::string& type, const std::string& param); * \brief Create the codecs stack based on the provided codecs stack description (cf. remark) * \param[in] p_type The provided codecs stack description * \param[in] p_params Optional parameters diff --git a/ccsrc/Framework/include/codec_gen.hh b/ccsrc/Framework/include/codec_gen.hh index 82cfc8b047ad47c2900397ff39a4e7e8a410883b..b36664cc417cbe805cf591e622a6a2bdefc79925 100644 --- a/ccsrc/Framework/include/codec_gen.hh +++ b/ccsrc/Framework/include/codec_gen.hh @@ -50,7 +50,7 @@ public: //! \publicsection */ virtual int encode(const TPDUEnc &p_message, OCTETSTRING &p_data) = 0; /*! - * \fn int decode(const OCTETSTRING& p_, TPDUDec& p_message, params_its* p_params = NULL); + * \fn int decode(const OCTETSTRING& p_, TPDUDec& p_message, params* p_params = NULL); * \brief Encode typed message into an octet string format * \param[in] p_data The message in its octet string * \param[out] p_message The decoded typed message diff --git a/ccsrc/Framework/include/codec_stack_builder.hh b/ccsrc/Framework/include/codec_stack_builder.hh index ca1be9f655c8ab0fa1757fedb9702e7bd7054f6b..9e81d6b9bb45aacc3733edc6b36d870305167d29 100644 --- a/ccsrc/Framework/include/codec_stack_builder.hh +++ b/ccsrc/Framework/include/codec_stack_builder.hh @@ -38,24 +38,24 @@ public: //! \publicsection static codec_stack_builder *get_instance() { return _instance ? _instance : _instance = new codec_stack_builder(); }; /*! - * \fn void register_codec_factory(const std::string & p_type, codec_factory* p_codec_factory); + * \fn void register_codec_factory(const std::string& p_type, codec_factory* p_codec_factory); * \brief Add a new codec factory * \param[in] p_type The codec identifier (e.g. GN for the GeoNetworking codec...) * \param[in] p_codec_factory A reference to the \see codec_factory * \static */ - static void register_codec_factory(const std::string &p_type, codec_factory *p_codec_factory) { + static void register_codec_factory(const std::string& p_type, codec_factory *p_codec_factory) { codec_stack_builder::get_instance()->_register_codec_factory(p_type, p_codec_factory); }; private: //! \privatesection /*! - * \fn void _register_codec_factory(const std::string & p_type, codec_factory* p_codec_factory); + * \fn void _register_codec_factory(const std::string& p_type, codec_factory* p_codec_factory); * \brief Add a new codec factory * \param[in] p_type The codec identifier (e.g. GN for the GeoNetworking codec...) * \param[in] p_codec_factory A reference to the \see codec_factory */ - void _register_codec_factory(const std::string &p_type, codec_factory *p_codec_factory) { _codecs[p_type] = p_codec_factory; }; + void _register_codec_factory(const std::string& p_type, codec_factory *p_codec_factory) { _codecs[p_type] = p_codec_factory; }; public: //! \publicsection /*! diff --git a/ccsrc/Framework/include/converter.hh b/ccsrc/Framework/include/converter.hh index 6070f2d80e6bdf0ec4cb089b102fc9e9177c43f0..cdb29e94bc4cfa2d5adcff218c8198d93ce6091b 100644 --- a/ccsrc/Framework/include/converter.hh +++ b/ccsrc/Framework/include/converter.hh @@ -104,7 +104,7 @@ public: * \param[in] p_value The string value * \return The hexadecimal value */ - std::string string_to_hexa(const std::string &p_value, const bool p_uppercase = false); + std::string string_to_hexa(const std::string& p_value, const bool p_uppercase = false); /*! * \brief Convert a bytes array int32_t an hexadecimal string * \param[in] p_value The bytes array value @@ -116,7 +116,7 @@ public: * \param[in] p_value The hexadecimal value * \return The bytes array value */ - std::vector hexa_to_bytes(const std::string &p_value); + std::vector hexa_to_bytes(const std::string& p_value); /*! * \brief Convert a time in time_t format into a string formated according to RFC 822, 1036, 1123, 2822 @@ -279,7 +279,7 @@ public: * \param[in] p_value The string value * \return The bytes array value */ - inline std::vector string_to_bytes(const std::string &p_value) const { + inline std::vector string_to_bytes(const std::string& p_value) const { return std::vector(p_value.begin(), p_value.end()); }; // End of string_to_bytes @@ -298,7 +298,7 @@ public: * \param[in] p_value The string value * \return The integer value */ - inline int32_t string_to_int(const std::string &p_value) const { + inline int32_t string_to_int(const std::string& p_value) const { return std::stoi(p_value); // return atoi(p_value.c_str()); }; // End of string_to_int @@ -318,13 +318,13 @@ public: * \brief Convert a string in to lower case * \param[in/out] p_value The string value to convert */ - inline void to_lower(std::string &p_value) { std::transform(p_value.begin(), p_value.end(), p_value.begin(), ::tolower); } + inline void to_lower(std::string& p_value) { std::transform(p_value.begin(), p_value.end(), p_value.begin(), ::tolower); } /*! * \brief Convert a string in to upper case * \param[in/out] p_value The string value to convert */ - inline void to_upper(std::string &p_value) { std::transform(p_value.begin(), p_value.end(), p_value.begin(), ::toupper); } + inline void to_upper(std::string& p_value) { std::transform(p_value.begin(), p_value.end(), p_value.begin(), ::toupper); } public: /*! @@ -333,7 +333,7 @@ public: * \param[in] p_trim_chars The special characters to be omitted. Default: ' ' and TAB * \return The new string value */ - std::string trim(const std::string &p_value, const std::string &p_trim_chars = " \t"); + std::string trim(const std::string& p_value, const std::string& p_trim_chars = " \t"); /*! * \brief Convert the provided string into a list of arguments @@ -349,7 +349,7 @@ public: * } * \endcode */ - std::vector split(const std::string &p_value, const std::string &p_separator); + std::vector split(const std::string& p_value, const std::string& p_separator); /*! * \brief Convert the provided string into a list of arguments @@ -364,24 +364,33 @@ public: * } * \endcode */ - std::vector split_arguments_line(const std::string &p_value); + std::vector split_arguments_line(const std::string& p_value); + + /*! + * \brief Replace string or character into the the provided string + * \param[in] p_value The original string value + * \param[in] p_from The pattern to be replaced + * \param[in] p_to The new pattern + * \return The modified string + */ + std::string replace(const std::string& p_value, const std::string& p_from, const std::string& p_to); /*! * \brief Convert the provided buffer into a Base64 * \param[in] p_value The buffer value * \return The Base64 encoded buffert */ - std::vector buffer_to_base64(const std::vector &p_value); + std::vector buffer_to_base64(const std::vector &p_value, const bool p_is_url = false); /*! * \brief Convert the provided Base64 buffer * \param[in] p_value The buffer value * \return The Base64 encoded buffert */ - std::vector base64_to_buffer(const std::vector &p_value); + std::vector base64_to_buffer(const std::vector &p_value, const bool p_remove_crlf = true); static const std::string lut_u; static const std::string lut_l; - static const std::string base64_enc_map; + static const std::string base64_enc_map[2]; }; // End of class converter diff --git a/ccsrc/Framework/include/layer.hh b/ccsrc/Framework/include/layer.hh index 8268401767cc76fecf09231ab30a718bc89588ea..8a2183f141126f82bd1f9113fe7e5f822643d691 100644 --- a/ccsrc/Framework/include/layer.hh +++ b/ccsrc/Framework/include/layer.hh @@ -47,7 +47,7 @@ public: //! \publicsection * \remark This constructor is called by the layer factory * \see layer_factory */ - explicit layer(const std::string &p_type) : upperLayers(), lowerLayers(), type(std::string(p_type.begin(), p_type.end())){}; + explicit layer(const std::string& p_type) : upperLayers(), lowerLayers(), type(std::string(p_type.begin(), p_type.end())){}; /*! * \brief Default destructor @@ -102,7 +102,7 @@ public: //! \publicsection /*! * \virtual - * \fn void receive_data(OCTETSTRING& data, params_its& params); + * \fn void receive_data(OCTETSTRING& data, params& params); * \brief Receive bytes formated data from the lower layers * \param[in] p_data The bytes formated data received * \param[in] p_params Some lower layers parameters values when data was received @@ -117,7 +117,7 @@ public: //! \publicsection * \brief Remove the specified upper layer protocol from the list of the upper layer * \param[in] The layer protocol to be removed */ - inline const std::string &to_string() const { return type; }; + inline const std::string& to_string() const { return type; }; protected: //! \protectedsection inline void to_all_layers(std::vector &layers, OCTETSTRING &data, params ¶ms) { diff --git a/ccsrc/Framework/include/layer_factory.hh b/ccsrc/Framework/include/layer_factory.hh index 7b8ac35a611565cef89956c2a142bfe3b0576604..e3c1429d65ddad2a5bc7a3625349c015b15a5435 100644 --- a/ccsrc/Framework/include/layer_factory.hh +++ b/ccsrc/Framework/include/layer_factory.hh @@ -30,58 +30,16 @@ public: //! \publicsection */ layer_factory(){}; /*! - * \fn layer* create_layer(const std::string & type, const std::string & param); + * \fn layer* create_layer(const std::string& type, const std::string& param); * \brief Create the layers stack based on the provided layers stack description (cf. remark) * \param[in] p_type The provided layers stack description * \param[in] p_params Optional parameters * \return 0 on success, -1 otherwise * \remark The description below introduces layers stack in case of ITS project: - * CAM layer - * next_header : btpA|btpB (overwrite BTP.type) - * header_type : tsb|gbc - * header_sub_type : sh (single hop) - * DENM layer - * next_header : btpA|btpB (overwrite BTP.type) - * header_type : tsb|gbc - * BTP layer - * type : btpA|btpB - * destination port: dst_port - * source port : src_port - * device_mode : Set to 1 if the layer shall encapsulate upper layer PDU - * GN layer - * its_aid : ITS AID as defined by ETSI TS 102 965 V1.2.1. Default: 141 - * ll_address : GeoNetworking address of the Test System - * latitude : latitude of the Test System - * longitude : longitude of the Test System - * beaconing : Set to 1 if GnLayer shall start beaconing - * Beaconing timer expiry : expiry (ms) - * device_mode : Set to 1 if the layer shall encapsulate upper layer PDU - * secured_mode : Set to 1 if message exchanges shall be signed - * encrypted_mode : Set to 1 if message exchanges shall be encrypted - * NOTE: For signed & encrypted message exchanges, both secured_mode and encrypted_mode shall be set to 1 - * certificate : Certificate identifier the Test Adapter shall use - * secure_db_path : Path to the certificates and keys storage location - * hash : Hash algorithm to be used when secured mode is set - * Authorized values are SHA-256 or SHA-384 - * Default: SHA-256 - * signature : Signature algorithm to be used when secured mode is set - * Authorized values are NISTP-256, BP-256 and BP-384 - * Default: NISTP-256 - * cypher : Cyphering algorithm to be used when secured mode is set * Ethernet layer * mac_src :Source MAC address * mac_bc :Broadcast address * eth_type : Ethernet type - * Commsignia layer - * mac_src : Device MAC address, used to discard packets - * To indicate no filering, use the value 000000000000 - * mac_bc : Broadcast address - * eth_type : Ethernet type, used to discard packets - * target_host : Device address - * target_port : Device port - * source_port : Test System port - * interface_id: Interface id, used to discard packets - * tx_power : TX power (dB) * UDP layer (IP/UDP based on Pcap) * dst_ip : destination IPv4 address (aa.bb.cc.dd) * dst_port: destination port @@ -99,23 +57,7 @@ public: //! \publicsection * frame_offset: Frame offset, used to skip packets with frame number < frame_offset * time_offset : Time offset, used to skip packets with time offset < time_offset * save_mode : 1 to save sent packet, 0 otherwise - * Here are some examples: - * GeoNetworking multiple component case: - * NodeB.geoNetworkingPort.params := -"GN(ll_address=04e548000001,latitude=43551050,longitude=10298730,beaconing=0,expiry=1000,its_aid=141)/COMMSIGNIA(mac_src=04e548000001,mac_bc=FFFFFFFFFFFF,eth_type=8947,target_host=10.200.1.101,target_port=7942,source_port=7943,its_aid=141,interface_id=2,tx_power=-32)/UDP(dst_ip=192.168.56.1,dst_port=12346,src_ip=192.168.156.4,src_port=12345)/ETH(mac_src=04e548000001,mac_dst=0A0027000011,eth_type=0800)/PCAP(mac_src=04e548000001,file=/home/vagrant/TriesAndDelete/etsi_its/testdata/TC_AUTO_IOT_DENM_RWW_BV_01_short.pcap,filter=and -(udp port 30000 or udp port 7943))" NodeC.geoNetworkingPort.params := -"GN(ll_address=70b3d5791b48,latitude=43551050,longitude=10298730,beaconing=0,expiry=1000,its_aid=141)/COMMSIGNIA(mac_src=70b3d5791b48,mac_bc=FFFFFFFFFFFF,eth_type=8947,target_host=10.200.1.101,target_port=7942,source_port=7943,its_aid=141,interface_id=2,tx_power=-32)/UDP(dst_ip=192.168.56.1,dst_port=12346,src_ip=192.168.156.4,src_port=12345)/ETH(mac_src=70b3d5791b48,mac_dst=0A0027000011,eth_type=0800)/PCAP(mac_src=70b3d5791b48,file=/home/vagrant/TriesAndDelete/etsi_its/testdata/TC_AUTO_IOT_DENM_RWW_BV_01_short.pcap,filter=and -(udp port 30000 or udp port 7943))" - * NodeB.geoNetworkingPort.params := -"GN(ll_address=04e548000001,latitude=43551050,longitude=10298730,beaconing=0,expiry=1000,its_aid=141)/ETH(mac_src=04e548000001,mac_dst=0A0027000011,eth_type=0800)/PCAP(mac_src=04e548000001,file=/home/vagrant/TriesAndDelete/etsi_its/testdata/TC_AUTO_IOT_DENM_RWW_BV_01.pcap,filter=and -ether src 04e548000001)" #NodeC.geoNetworkingPort.params := -"GN(ll_address=70b3d5791b48,latitude=43551050,longitude=10298730,beaconing=0,expiry=1000,its_aid=141)/ETH(mac_src=70b3d5791b48,mac_dst=0A0027000011,eth_type=0800)/PCAP(mac_src=70b3d5791b48,file=/home/vagrant/TriesAndDelete/etsi_its/testdata/TC_AUTO_IOT_DENM_RWW_BV_01.pcap,filter=and -ether src 70b3d5791b48)" - * UpperTester port based on UDP - * system.utPort.params := -"UT_GN/UDP(dst_ip=192.168.1.1,dst_port=12346,src_ip=192.168.156.4,src_port=12345)/ETH(mac_src=026f8338c1e5,mac_dst=0A0027000011,eth_type=0800)/PCAP(mac_src=0800275c4959,nic=enp0s8,filter=and -udp port 12346)" * \pure */ - virtual layer *create_layer(const std::string &p_type, const std::string &p_params) = 0; + virtual layer *create_layer(const std::string& p_type, const std::string& p_params) = 0; }; // End of class layer_factory diff --git a/ccsrc/Framework/include/layer_stack_builder.hh b/ccsrc/Framework/include/layer_stack_builder.hh index 2d1b25a59eac4e0dfeb395256945a4659b5535f6..83ad20b394379cc371ad0f7e43ec7fe0f60528c4 100644 --- a/ccsrc/Framework/include/layer_stack_builder.hh +++ b/ccsrc/Framework/include/layer_stack_builder.hh @@ -38,22 +38,22 @@ public: //! \publicsection static layer_stack_builder *get_instance(); /*! - * \fn void register_layer_factory(const std::string & p_type, layer_factory* p_layer_factory); + * \fn void register_layer_factory(const std::string& p_type, layer_factory* p_layer_factory); * \brief Add a new layer factory * \param[in] p_type The layer identifier (e.g. GN for the GeoNetworking layer...) * \param[in] p_layer_factory A reference to the \see layer_factory * \static */ - static void register_layer_factory(const std::string &p_type, layer_factory *p_layer_factory); + static void register_layer_factory(const std::string& p_type, layer_factory *p_layer_factory); private: //! \privatesection /*! - * \fn void _register_layer_factory(const std::string & p_type, layer_factory* p_layer_factory); + * \fn void _register_layer_factory(const std::string& p_type, layer_factory* p_layer_factory); * \brief Add a new layer factory * \param[in] p_type The layer identifier (e.g. GN for the GeoNetworking layer...) * \param[in] p_layer_factory A reference to the \see layer_factory */ - void _register_layer_factory(const std::string &p_type, layer_factory *p_layer_factory); + void _register_layer_factory(const std::string& p_type, layer_factory *p_layer_factory); public: //! \publicsection /*! diff --git a/ccsrc/Framework/include/oer_codec.hh b/ccsrc/Framework/include/oer_codec.hh deleted file mode 100644 index 51a32cd1c5ec5cb62d86d67d3a84d6f2b0389045..0000000000000000000000000000000000000000 --- a/ccsrc/Framework/include/oer_codec.hh +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "params.hh" - -class OCTETSTRING; -class CHARSTRING; -class BITSTRING; - -struct asn_TYPE_descriptor_s; -class asn1_recode_oer { -protected: - int xer2oer(const asn_TYPE_descriptor_s &td, TTCN_Buffer &buf); - int oer2xer(const asn_TYPE_descriptor_s &td, TTCN_Buffer &buf); - int recode(const asn_TYPE_descriptor_s &td, int from, int to, TTCN_Buffer &buf); -}; - -template class oer_codec : public asn1_recode_oer { -public: - virtual int encode(const TPDU &msg, BITSTRING &bits) = 0; - virtual int decode(const BITSTRING &bits, TPDU &msg) = 0; - -protected: - inline int _decode(const TTCN_Typedescriptor_t &ttcn, const asn_TYPE_descriptor_s &td, const BITSTRING &p_data, TPDU &msg) { - TTCN_Buffer buf(bit2oct(p_data)); - TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING); - int rc = oer2xer(td, buf); - if (rc > 0) { - msg.decode(ttcn, buf, TTCN_EncDec::CT_BER, BER_ACCEPT_ALL); - rc = buf.get_len(); - } - return rc; - } - inline int _encode(const TTCN_Typedescriptor_t &ttcn, const asn_TYPE_descriptor_s &td, const TPDU &msg, BITSTRING &p_data) { - int rc = -1; - TTCN_Buffer buf; - TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING); - msg.encode(ttcn, buf, TTCN_EncDec::CT_BER, BER_ENCODE_DER); - if (buf.get_len() > 0) { - rc = xer2oer(td, buf); - if (rc > 0) { - p_data = oct2bit(OCTETSTRING(buf.get_len(), buf.get_data())); - } - } - return rc; - } -}; - -#endif diff --git a/ccsrc/Framework/include/params.hh b/ccsrc/Framework/include/params.hh index 6bb5dcd1b95474a44f4d5111cd1f60358b742dc8..bc683cfe98daed266062f38488ccb8722c3bc5e1 100644 --- a/ccsrc/Framework/include/params.hh +++ b/ccsrc/Framework/include/params.hh @@ -35,14 +35,15 @@ public: //! \publicsection static const std::string& nic; //! Network Interface Card parameter name - static const std::string& server; //! HTTP server address (e.g. www.etsi.org) - static const std::string& port; //! HTTP server port. Default: 80 + static const std::string& server; //! Remote server address (e.g. www.etsi.org) + static const std::string& port; //! Remote server port. Default: 80 static const std::string& use_ssl; //! Set to 1 to use SSL to communicate with the HTTP server. Default: false static const std::string& mutual_auth; //! Set to 1 to use mutual authentication. Default: false static const std::string& trusted_ca_list; //! List of trusted CA certificates static const std::string& certificate; //! Chain of certificates static const std::string& privkey; //! Certificate private key static const std::string& server_mode; //! Does the test sytem acting as a server. Default: 0 + static const std::string& local_server; //! Local server address (e.g. localhost) static const std::string& local_port; //! Local listener port. Default: 80 static const std::string& method; //! HTTP method type. Default: POST diff --git a/ccsrc/Framework/include/per_codec.hh b/ccsrc/Framework/include/per_codec.hh deleted file mode 100644 index 077d74ad549b648d3deccc599e6039cb496a76eb..0000000000000000000000000000000000000000 --- a/ccsrc/Framework/include/per_codec.hh +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * \file per_codec.hh - * \brief Header file for TITAN message to ASN.1 PER message codec. - * \author ETSI STF525 - * \copyright ETSI Copyright Notification - * No part may be reproduced except as authorized by written permission. - * The copyright and the foregoing restriction extend to reproduction in all media. - * All rights reserved. - * \version 0.1 - */ -#pragma once - -#include "asn1_recode_per.hh" -#include "params.hh" - -class BITSTRING; //! Forward declaration of TITAN class -class TTCN_Typedescriptor_t; //! Forward declaration of TITAN class - -struct asn_TYPE_descriptor_s; //! Declare asn1c class - -/*! - * \class per_codec - * \brief This class provides the interface for all ASN.1 PER codecs. - * \remark This class uses asn1c external tool - */ -template class per_codec : public asn1_recode_per { -public: //! \publicsection - /*! - * \fn int encode(const TPDU& p_message, BITSTRING& p_bitstring); - * \brief Encode TITAN message into ASN.1 PER message - * \param[in] p_message The PDU message to encode - * \param[out] p_bitstring The encoded PDU message in bit string format - * \pure - */ - virtual int encode(const TPDU &p_message, BITSTRING &p_bitstring) = 0; - /*! - * \fn int decode(const BITSTRING& p_bitstring, TPDU& p_message); - * \brief Decode ASN.1 PER message into TITAN message - * \param[in] p_bitstring The network message in bit string format to decode - * \param[out] p_message The PDU message - * \pure - */ - virtual int decode(const BITSTRING &p_bitstring, TPDU &p_message) = 0; - -protected: //! \protectedsection - int _decode(const TTCN_Typedescriptor_t &ttcn, const asn_TYPE_descriptor_s &td, const BITSTRING &p_data, TPDU &msg); - int _encode(const TTCN_Typedescriptor_t &ttcn, const asn_TYPE_descriptor_s &td, const TPDU &msg, BITSTRING &p_data); -}; // End of class per_codec - -#include "per_codec.t.hh" diff --git a/ccsrc/Framework/include/per_codec.t.hh b/ccsrc/Framework/include/per_codec.t.hh deleted file mode 100644 index 6973dc6d7c32a9b8252ae75681081d66cd23e498..0000000000000000000000000000000000000000 --- a/ccsrc/Framework/include/per_codec.t.hh +++ /dev/null @@ -1,26 +0,0 @@ -#include - -template int per_codec::_decode(const TTCN_Typedescriptor_t &ttcn, const asn_TYPE_descriptor_s &td, const BITSTRING &p_data, TPDU &msg) { - TTCN_Buffer buf(bit2oct(p_data)); - TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING); - int rc = per2ber(td, buf); - if (rc > 0) { - msg.decode(ttcn, buf, TTCN_EncDec::CT_BER, BER_ACCEPT_ALL); - rc = buf.get_len(); - } - return rc; -} - -template int per_codec::_encode(const TTCN_Typedescriptor_t &ttcn, const asn_TYPE_descriptor_s &td, const TPDU &msg, BITSTRING &p_data) { - int rc = -1; - TTCN_Buffer buf; - TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING); - msg.encode(ttcn, buf, TTCN_EncDec::CT_BER, BER_ENCODE_DER); - if (buf.get_len() > 0) { - rc = ber2per(td, buf); - if (rc > 0) { - p_data = oct2bit(OCTETSTRING(buf.get_len(), buf.get_data())); - } - } - return rc; -} diff --git a/ccsrc/Framework/include/registration.hh b/ccsrc/Framework/include/registration.hh index df24ea1cfdd3b14c171de8a6f375b80d5e689c15..0b2dbfeb87aafe141153af8a5e755d9cf0db59be 100644 --- a/ccsrc/Framework/include/registration.hh +++ b/ccsrc/Framework/include/registration.hh @@ -35,8 +35,8 @@ public: }; public: - void add_item(const std::string &type, TItem *f); - TItem *get_item(const std::string &type); + void add_item(const std::string& type, TItem *f); + TItem *get_item(const std::string& type); }; // End of class registration template registration *registration::_instance = nullptr; @@ -46,9 +46,9 @@ template registration ®istration::get_instance return (_instance != nullptr) ? *_instance : *(_instance = new registration()); } -template void registration::add_item(const std::string &type, TItem *f) { _items[type] = f; } +template void registration::add_item(const std::string& type, TItem *f) { _items[type] = f; } -template TItem *registration::get_item(const std::string &type) { +template TItem *registration::get_item(const std::string& type) { typename std::map::const_iterator it = _items.find(type); if (it == _items.cend()) { return nullptr; diff --git a/ccsrc/Framework/include/t_layer.hh b/ccsrc/Framework/include/t_layer.hh index 286bd3169b92258ec085b0ab5425ea22c23097d5..cbb5edf34d7b4b920741384830549fbac2b08e76 100644 --- a/ccsrc/Framework/include/t_layer.hh +++ b/ccsrc/Framework/include/t_layer.hh @@ -39,7 +39,7 @@ public: //! \publicsection * \remark This constructor is called by the layer factory * \see layer_factory */ - explicit t_layer(const std::string &p_type) : layer(p_type), upperPorts(){}; + explicit t_layer(const std::string& p_type) : layer(p_type), upperPorts(){}; /*! * \inline * \fn void add_upper_port(TPort * p_port); diff --git a/ccsrc/Framework/src/base_time.cc b/ccsrc/Framework/src/base_time.cc index 38331193d666b1354b31cdc7b0ebc07ed135734c..28c2cc60bc5ce25ef94b3ac81889439019a6c0a4 100644 --- a/ccsrc/Framework/src/base_time.cc +++ b/ccsrc/Framework/src/base_time.cc @@ -1,6 +1,6 @@ /*! * \file base_time.cc - * \brief Source file for the control port base_time functionality. + * \brief Source file base_time functionality. * \author ETSI STF525 * \copyright ETSI Copyright Notification * No part may be reproduced except as authorized by written permission. diff --git a/ccsrc/Framework/src/converter.cc b/ccsrc/Framework/src/converter.cc index e9ad4d1476ff8563e79a712ac1e9eeae18787636..9df0ad962ba26aa7ebd97530983c22be8d3ecfc5 100644 --- a/ccsrc/Framework/src/converter.cc +++ b/ccsrc/Framework/src/converter.cc @@ -1,5 +1,7 @@ #include "converter.hh" + #include + converter *converter::instance = NULL; uint16_t converter::swap(const uint16_t p_value) { @@ -14,7 +16,7 @@ uint32_t converter::swap(const uint32_t p_value) { const std::string converter::lut_u = "0123456789ABCDEF"; const std::string converter::lut_l = "0123456789abcdef"; -std::string converter::string_to_hexa(const std::string &p_value, const bool p_uppercase) { +std::string converter::string_to_hexa(const std::string& p_value, const bool p_uppercase) { std::string input(p_value); std::for_each(input.begin(), input.end(), [](char &c) { c = std::toupper(c); }); @@ -40,22 +42,22 @@ std::string converter::string_to_hexa(const std::string &p_value, const bo } std::string converter::bytes_to_hexa(const std::vector &p_value, const bool p_uppercase) { - std::string ret; - ret.assign(p_value.size() * 2, ' '); + std::string out; + out.assign(p_value.size() * 2, ' '); if (p_uppercase) { // TODO Use pointer to reduce code size for (size_t i = 0; i < p_value.size(); i++) { uint8_t c = p_value[i]; - ret[i * 2] = lut_u[c >> 4]; - ret[i * 2 + 1] = lut_u[c & 0xF]; + out[i * 2] = lut_u[c >> 4]; + out[i * 2 + 1] = lut_u[c & 0xF]; } } else { for (size_t i = 0; i < p_value.size(); i++) { uint8_t c = p_value[i]; - ret[i * 2] = lut_l[c >> 4]; - ret[i * 2 + 1] = lut_l[c & 0xF]; + out[i * 2] = lut_l[c >> 4]; + out[i * 2 + 1] = lut_l[c & 0xF]; } } - return ret; + return out; } inline uint8_t char2byte(const char p_ch) { @@ -68,7 +70,7 @@ inline uint8_t char2byte(const char p_ch) { return s; } -std::vector converter::hexa_to_bytes(const std::string &p_value) { +std::vector converter::hexa_to_bytes(const std::string& p_value) { // Sanity check std::vector output; size_t i = 0, idx = 0, outlen = (p_value.length() + 1) / 2; @@ -100,7 +102,7 @@ std::string converter::time_to_string(const struct tm &p_time) { return std::string(buffer); } -std::string converter::trim(const std::string &str, const std::string &whitespace) { +std::string converter::trim(const std::string& str, const std::string& whitespace) { size_t strBegin = str.find_first_not_of(whitespace); if (strBegin == std::string::npos) return ""; // no content @@ -111,7 +113,7 @@ std::string converter::trim(const std::string &str, const std::string &whitespac return str.substr(strBegin, strRange); } -std::vector converter::split(const std::string &p_value, const std::string &p_separator) { +std::vector converter::split(const std::string& p_value, const std::string& p_separator) { std::vector output; std::size_t current, previous = 0; current = p_value.find(p_separator); @@ -125,7 +127,7 @@ std::vector converter::split(const std::string &p_value, const std: return output; } -std::vector converter::split_arguments_line(const std::string &p_value) { +std::vector converter::split_arguments_line(const std::string& p_value) { std::vector output; std::string line = trim(p_value); if (!line.empty() && (line[0] == '-')) { // Valid command line @@ -147,49 +149,122 @@ std::vector converter::split_arguments_line(const std::string &p_va return output; } -const std::string converter::base64_enc_map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const std::string converter::base64_enc_map[2] = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + }; + +/** + * @brief Return the position of chr within base64_encode() + * @param[in] chr + * @return Return the position of chr within base64_encode() + */ +static unsigned char pos_of_char(const unsigned char chr) { + if ((chr >= 'A' && chr <= 'Z')) { + return static_cast(chr - 'A'); + } else if ((chr >= 'a' && chr <= 'z')) { + return static_cast(chr - 'a' + ('Z' - 'A') + 1); + } else if ((chr >= '0' && chr <= '9')) { + return static_cast(chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2); + } else if ((chr == '+' || chr == '-')) { + return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters ( + } else if ((chr == '/' || chr == '_')) { + return 63; // Idem for '/' and '_' + } else { + throw std::runtime_error("Input is not valid base64-encoded data."); + } +} + +static std::string insert_linebreaks(std::string str, size_t distance) { + if (!str.length()) { + return ""; + } + size_t pos = distance; + while (pos < str.size()) { + str.insert(pos, "\n"); + pos += distance + 1; + } + return str; +} + +std::string converter::replace(const std::string& p_value, const std::string& p_from, const std::string& p_to) { + size_t start_pos = 0; + std::string str(p_value); + while((start_pos = str.find(p_from, start_pos)) != std::string::npos) { + str.replace(start_pos, p_from.length(), p_to); + start_pos += p_to.length(); // Handles case where 'p_to' is a substring of 'p_from' + } + return str; +} + +std::vector converter::buffer_to_base64(const std::vector &p_value, const bool p_is_url) { + const std::string& base64_enc_map_ = converter::base64_enc_map[(p_is_url) ? 1 : 0]; + const unsigned char trailing_char = (p_is_url) ? '.' : '='; -std::vector converter::buffer_to_base64(const std::vector &p_value) { std::vector out; + //out.resize((p_value.size() + 2) / 3 * 4); + + unsigned int pos = 0; + while (pos < p_value.size()) { + out.push_back(base64_enc_map_[(p_value[pos + 0] & 0xfc) >> 2]); + + if (pos+1 < p_value.size()) { + out.push_back(base64_enc_map_[((p_value[pos + 0] & 0x03) << 4) + ((p_value[pos + 1] & 0xf0) >> 4)]); - int val = 0, valb = -6; - for (unsigned char c : p_value) { - val = (val << 8) + c; - valb += 8; - while (valb >= 0) { - out.push_back(converter::base64_enc_map[(val >> valb) & 0x3F]); - valb -= 6; + if (pos+2 < p_value.size()) { + out.push_back(base64_enc_map_[((p_value[pos + 1] & 0x0f) << 2) + ((p_value[pos + 2] & 0xc0) >> 6)]); + out.push_back(base64_enc_map_[ p_value[pos + 2] & 0x3f]); + } else { + out.push_back(base64_enc_map_[(p_value[pos + 1] & 0x0f) << 2]); + out.push_back(trailing_char); + } + } else { + out.push_back(base64_enc_map_[(p_value[pos + 0] & 0x03) << 4]); + out.push_back(trailing_char); + out.push_back(trailing_char); + } + pos += 3; } // End of 'while' statement - } // End of 'for' statement - if (valb > -6) { - out.push_back(converter::base64_enc_map[((val << 8) >> (valb + 8)) & 0x3F]); - } - while (out.size() % 4) { - out.push_back('='); - } // End of 'while' statement return out; } -std::vector converter::base64_to_buffer(const std::vector &p_value) { - std::vector out; +std::vector converter::base64_to_buffer(const std::vector &p_value, const bool p_remove_crlf) { - std::vector T(256, -1); - for (int i = 0; i < 64; i++) { - T[converter::base64_enc_map[i]] = i; + if (p_value.size() == 0) { + return std::vector(); } - int val = 0, valb = -8; - for (unsigned char c : p_value) { - if (T[c] == -1) { - break; - } - val = (val << 6) + T[c]; - valb += 6; - if (valb >= 0) { - out.push_back((unsigned char)char((val >> valb) & 0xFF)); - valb -= 8; + std::vector value(p_value); + if (p_remove_crlf) { + value.erase(std::remove(value.begin(), value.end(), '\r'), value.end()); + value.erase(std::remove(value.begin(), value.end(), '\n'), value.end()); + } + + std::vector out; + //out.resize(value.size() / 4 * 3); + + size_t pos = 0; + while (pos < value.size()) { + size_t pos_of_char_1 = pos_of_char(value[pos + 1]); + out.push_back(((pos_of_char(value[pos])) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)); + + if ((pos + 2 < value.size()) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045) + value[pos + 2] != '=' && + value[pos + 2] != '.' // accept URL-safe base 64 strings, too, so check for '.' also. + ) { + //Emit a chunk's second byte (which might not be produced in the last chunk). + unsigned int pos_of_char_2 = pos_of_char(value[pos + 2]); + out.push_back(((pos_of_char_1 & 0x0f) << 4) + ((pos_of_char_2 & 0x3c) >> 2)); + + if ((pos + 3 < value.size()) && value[pos + 3] != '=' && value[pos + 3] != '.' ) { + // Emit a chunk's third byte (which might not be produced in the last chunk). + out.push_back(((pos_of_char_2 & 0x03 ) << 6) + pos_of_char(value[pos + 3])); + } } - } // End of 'for' statement + + pos += 4; + } // End of 'while' statement + return out; } diff --git a/ccsrc/Framework/src/layer_factory.cc b/ccsrc/Framework/src/layer_factory.cc index 2a106304c1160b29020add8d68926fddb16c4431..e812ac70a3f01e46b9cd3bd82da0ef6dd59d8268 100644 --- a/ccsrc/Framework/src/layer_factory.cc +++ b/ccsrc/Framework/src/layer_factory.cc @@ -10,17 +10,17 @@ layer_stack_builder *layer_stack_builder::_instance = NULL; // static functions layer_stack_builder *layer_stack_builder::get_instance() { return _instance ? _instance : _instance = new layer_stack_builder(); } -void layer_stack_builder::register_layer_factory(const std::string &p_type, layer_factory *p_layer_factory) { +void layer_stack_builder::register_layer_factory(const std::string& p_type, layer_factory *p_layer_factory) { layer_stack_builder::get_instance()->_register_layer_factory(p_type, p_layer_factory); } // member functions layer_stack_builder::layer_stack_builder() {} -void layer_stack_builder::_register_layer_factory(const std::string &p_type, layer_factory *p_layer_factory) { _layer_factories[p_type] = p_layer_factory; } +void layer_stack_builder::_register_layer_factory(const std::string& p_type, layer_factory *p_layer_factory) { _layer_factories[p_type] = p_layer_factory; } layer *layer_stack_builder::create_layer_stack(const char *p_layer_stack_description) { - loggers::get_instance().log(">>> layer_stack_builder::create_layer_stack: %s", p_layer_stack_description); + loggers::get_instance().log(">>> layer_stack_builder::create_layer_stack: '%s'", p_layer_stack_description); layer *entry = NULL; // Initial layer (the first declared) layer *up = NULL; // Upper layer @@ -36,12 +36,12 @@ layer *layer_stack_builder::create_layer_stack(const char *p_layer_stack_descrip m[2].str().c_str(), m[3].str().c_str()); LayerFactoryMap::iterator i = _layer_factories.find(m[1].str()); if (i == _layer_factories.end()) { - loggers::get_instance().error("layer_stack_builder::create_layer_stack: %s: Unknown layer type", m[1].str().c_str()); + loggers::get_instance().error("layer_stack_builder::create_layer_stack: '%s': Unknown layer type", m[1].str().c_str()); } loggers::get_instance().log("layer_stack_builder::create_layer_stack: Create layer %s, %s", m[1].str().c_str(), m[3].str().c_str()); layer *l = i->second->create_layer(m[1].str(), m[3].str()); if (NULL == l) { - loggers::get_instance().error("layer_stack_builder::create_layer_stack: %s: Layer creation error", m[1].str().c_str()); + loggers::get_instance().error("layer_stack_builder::create_layer_stack: '%s': Layer creation error", m[1].str().c_str()); } loggers::get_instance().log("layer_stack_builder::create_layer_stack: Setup layers for %s - %p", l->to_string().c_str(), (void*)l); diff --git a/ccsrc/Framework/src/params.cc b/ccsrc/Framework/src/params.cc index 5040dbe0837f346ab0f4a40554e7d3a9e5a2d6fe..a18371414d5992bb40be3c8733784f0666d323cf 100644 --- a/ccsrc/Framework/src/params.cc +++ b/ccsrc/Framework/src/params.cc @@ -37,6 +37,7 @@ const std::string& params::certificate = std::string("certificate"); const std::string& params::privkey = std::string("privkey"); const std::string& params::server_mode = std::string("server_mode"); +const std::string& params::local_server = std::string("local_server"); const std::string& params::local_port = std::string("local_port"); const std::string& params::method = std::string("method"); @@ -51,7 +52,7 @@ void params::convert(params &p_param, const std::string p_parameters) { if (p_parameters.length() == 0) { return; } - loggers::get_instance().log(">>> params::convert: %s", p_parameters.c_str()); + loggers::get_instance().log(">>> params::convert: '%s'", p_parameters.c_str()); // Extract parameters try { std::regex rgx("(\\w+)=(.*?)(,|$)"); diff --git a/ccsrc/Helpers/helpers_externals.cc b/ccsrc/Helpers/helpers_externals.cc index b38729221d12fcfc29c346202d2b6ad21cfec7d0..37d1f3e62e5096219539d0b6e8ac4573edf85b84 100644 --- a/ccsrc/Helpers/helpers_externals.cc +++ b/ccsrc/Helpers/helpers_externals.cc @@ -1,8 +1,14 @@ -#include "LibHelpers_Functions.hh" #include +#include +#include +#include + +#include "LibHelpers_Functions.hh" #include "base_time.hh" +#include "converter.hh" #include "loggers.hh" +#include "xml_converters.hh" #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -29,7 +35,7 @@ namespace LibHelpers__Functions { * @see function f_getMinuteOfTheYear() return MinuteOfTheYear */ INTEGER fx__getMinuteOfTheYear() { - // TODO: this is just a sceleton. fill in the function + // TODO: this is just a skeleton. fill in the function return 0; } @@ -39,8 +45,113 @@ namespace LibHelpers__Functions { * @see function f_getDSecond() return DSecond */ INTEGER fx__getDSecond() { - // TODO: this is just a sceleton. fill in the function + // TODO: this is just a skeleton. fill in the function return 0; } + /** + * @desc Encode into Base64 + * @return p_to_encode - The buffer to be encoded + * @see function f_enc_base64(in octetstring p_to_encode) return octetstring + */ + OCTETSTRING fx__enc__base64(const OCTETSTRING& p_to_encode) { + loggers::get_instance().log_msg(">>> fx__enc__base64: ", p_to_encode); + + const std::vector to_encode(static_cast(p_to_encode), static_cast(p_to_encode) + p_to_encode.lengthof()); + std::vector b64 = converter::get_instance().buffer_to_base64(to_encode); + OCTETSTRING os(b64.size(), b64.data()); + loggers::get_instance().log_msg("<<< fx__enc__base64: ", os); + return os; + } + + /** + * @desc Decode from Base64 + * @return p_to_decode - The buffer to be decoded + * @see function f_dec_base64(in octetstring p_to_decode) return octetstring + */ + OCTETSTRING fx__dec__base64(const OCTETSTRING& p_to_decode) { + loggers::get_instance().log_msg(">>> fx__dec__base64: ", p_to_decode); + + const std::vector to_decode(static_cast(p_to_decode), static_cast(p_to_decode) + p_to_decode.lengthof()); + std::vector b64 = converter::get_instance().base64_to_buffer(to_decode); + OCTETSTRING os(b64.size(), b64.data()); + loggers::get_instance().log_msg("<<< fx__dec__base64: ", os); + return os; + } + + static unsigned char random_char() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(0, 255); + return static_cast(dis(gen)); + } + + static std::string generate_hex(const unsigned int len) { + std::stringstream ss; + for(auto i = 0; i < len; i++) { + auto rc = random_char(); + std::stringstream hexstream; + hexstream << std::hex << int(rc); + auto hex = hexstream.str(); + ss << (hex.length() < 2 ? '0' + hex : hex); + } + return ss.str(); + } + + /** + * @brief Generate a new UUID + * @return The UUID in string format on success, a null string otherwise + */ + CHARSTRING fx__generate__uuid() { // ddb848c4-f7fd-445f-bdc8-033d15d7c528 + loggers::get_instance().log(">>> fx__generate__uuid"); + + std::stringstream ss; + ss << generate_hex(6) << "-"; + ss << generate_hex(2) << "-"; + ss << generate_hex(2) << "-"; + ss << generate_hex(2) << "-"; + ss << generate_hex(6); + + CHARSTRING uuid(ss.str().c_str()); + loggers::get_instance().log_msg("fx__generate__uuid: ", uuid); + return uuid; + } + + /** + * @brief Retrieve the current local date/time formatted as yyyy-mm-ddThh:mm:ss.lll+nn:00 + * @return The the current date/time on success, a null string otherwise + */ + CHARSTRING fx__get__current__date__time(const INTEGER& p__shift__time) { //2018-01-18T13:19:35.367+01:00 + loggers::get_instance().log(">>> fx__get__current__date__time"); + + time_t t = std::time(nullptr); + if (p__shift__time != 0) { + t += static_cast(p__shift__time); + } + auto tm = *std::localtime(&t); + std::ostringstream oss; + oss << std::put_time(&tm, "%FT%TZ");//%FT%T%Z + + CHARSTRING dt(oss.str().c_str()); + loggers::get_instance().log_msg("fx__get__current__date__time: ", dt); + return dt; + } + + /** + * @brief Retrieve the local date/time in the past formatted as yyyy-mm-ddThh:mm:ss.lll+nn:00 + * @return The the current date/time on success, a null string otherwise + */ + CHARSTRING fx__get__current__date__time__past() { //2018-01-18T13:19:35.367+01:00 + loggers::get_instance().log(">>> fx__get__current__date__time"); + + time_t t = std::time(nullptr); + auto tm = *std::localtime(&t); + std::ostringstream oss; + oss << std::put_time(&tm, "%FT%TZ");//%FT%T%Z + + CHARSTRING dt(oss.str().c_str()); + loggers::get_instance().log_msg("fx__get__current__date__time: ", dt); + return dt; + } + } // namespace LibHelpers__Functions diff --git a/ccsrc/Protocols/ETH/ethernet_layer.cc b/ccsrc/Protocols/ETH/ethernet_layer.cc index 134d4d7dc6e0985aeedd6c1ca4d12fb2d3551339..0b6bff730f4ffb7a8aea986f5be4727a50d6a1a0 100644 --- a/ccsrc/Protocols/ETH/ethernet_layer.cc +++ b/ccsrc/Protocols/ETH/ethernet_layer.cc @@ -2,8 +2,8 @@ #include "loggers.hh" -ethernet_layer::ethernet_layer(const std::string & p_type, const std::string & p_param) : layer(p_type), _params() { - loggers::get_instance().log(">>> ethernet_layer::ethernet_layer: %s, %s", to_string().c_str(), p_param.c_str()); +ethernet_layer::ethernet_layer(const std::string& p_type, const std::string& p_param) : layer(p_type), _params() { + loggers::get_instance().log(">>> ethernet_layer::ethernet_layer: '%s', %s", to_string().c_str(), p_param.c_str()); // Setup parameters params::convert(_params, p_param); params::const_iterator it = _params.find("mac_src"); @@ -68,7 +68,7 @@ void ethernet_layer::receive_data(OCTETSTRING& p_data, params& p_params) { // Extract ethertype OCTETSTRING proto = OCTETSTRING(2, 2 + static_cast(p_data)); //loggers::get_instance().log_msg("ethernet_layer::receive_data: proto: ", proto); - OCTETSTRING data = OCTETSTRING(data.lengthof() - 14, 14 + static_cast(p_data)); + OCTETSTRING data = OCTETSTRING(p_data.lengthof() - 14, 14 + static_cast(p_data)); // Update params CHARSTRING s = oct2str(dst); p_params.insert(std::pair(params::mac_dst, std::string(static_cast(s)))); diff --git a/ccsrc/Protocols/ETH/ethernet_layer.hh b/ccsrc/Protocols/ETH/ethernet_layer.hh index f510350bc21528b8da602a59d8eccebf2c155d48..57ae7c2e203d3dcab61aa2887afb041ef1a2cfab 100644 --- a/ccsrc/Protocols/ETH/ethernet_layer.hh +++ b/ccsrc/Protocols/ETH/ethernet_layer.hh @@ -23,7 +23,7 @@ public: //! \publicsection * \param[in] p_type \todo * \param[in] p_param \todo */ - ethernet_layer(const std::string &p_type, const std::string &p_param); + ethernet_layer(const std::string& p_type, const std::string& p_param); /*! * \brief Default destructor */ diff --git a/ccsrc/Protocols/ETH/ethernet_layer_factory.hh b/ccsrc/Protocols/ETH/ethernet_layer_factory.hh index 7adf9f4c242fcb60c532a04e7c2b08d9ed2ab51b..091b68d4ab4c876b3424f045f92381521a454eb4 100644 --- a/ccsrc/Protocols/ETH/ethernet_layer_factory.hh +++ b/ccsrc/Protocols/ETH/ethernet_layer_factory.hh @@ -31,12 +31,12 @@ public: //! \publicsection layer_stack_builder::register_layer_factory("ETH", this); }; /*! - * \fn layer* create_layer(const std::string & type, const std::string & param); + * \fn layer* create_layer(const std::string& type, const std::string& param); * \brief Create the layers stack based on the provided layers stack description * \param[in] p_type The provided layers stack description * \param[in] p_params Optional parameters * \return 0 on success, -1 otherwise * \inline */ - inline virtual layer *create_layer(const std::string &p_type, const std::string &p_param) { return new ethernet_layer(p_type, p_param); }; + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new ethernet_layer(p_type, p_param); }; }; // End of class ethernet_layer_factory diff --git a/ccsrc/Protocols/Http/http_codec.cc b/ccsrc/Protocols/Http/http_codec.cc index 832276918a793546307919e3d573e4131ea15145..bd1363218fd9b5ee87ea487782877a5132ad4648 100644 --- a/ccsrc/Protocols/Http/http_codec.cc +++ b/ccsrc/Protocols/Http/http_codec.cc @@ -1,684 +1,760 @@ -#include -#include -#include - -#include "codec_stack_builder.hh" - -#include "http_codec.hh" - -#include "loggers.hh" - -#include "LibHttp_TypesAndValues.hh" -#include "LibHttp_MessageBodyTypes.hh" -#include "LibHttp_XmlMessageBodyTypes.hh" -#include "LibHttp_JsonMessageBodyTypes.hh" - -int http_codec::encode(const LibHttp__TypesAndValues::HttpMessage &msg, OCTETSTRING &data) { - loggers::get_instance().log_msg(">>> http_codec::encode: ", (const Base_Type &)msg); - loggers::get_instance().log(">>> http_codec::encode: %p", this); - - TTCN_EncDec::clear_error(); - TTCN_Buffer encoding_buffer; - - _ec.reset(); - - int result; - if (msg.ischosen(LibHttp__TypesAndValues::HttpMessage::ALT_request)) { - result = encode_request(msg.request(), encoding_buffer); - } else if (msg.ischosen(LibHttp__TypesAndValues::HttpMessage::ALT_response)) { - result = encode_response(msg.response(), encoding_buffer); - } else { - loggers::get_instance().warning("http_codec::encode: Unbound HttpMessage"); - return -1; - } - - data = OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data()); - - loggers::get_instance().log_msg("<<< http_codec::encode: data=", data); - return result; -} - -int http_codec::decode(const OCTETSTRING &data, LibHttp__TypesAndValues::HttpMessage &msg, params *params) { - loggers::get_instance().log_msg(">>> http_codec::decode: data=", data); - - // Sanity checks - if ((data[0].get_octet() & 0x80) == 0x80) { - loggers::get_instance().warning("http_codec::decode: Unicode format not supported"); - return -1; - } - - TTCN_EncDec::clear_error(); - TTCN_Buffer decoding_buffer(data); - loggers::get_instance().log_to_hexa("http_codec::decode: decoding_buffer=", decoding_buffer); - - _dc.reset(); - - _params = params; - - // Get the first line (e.g. HTTP/1.1 302 Found or POST / HTTP/1.1) - CHARSTRING message_id; - if (get_line(decoding_buffer, message_id) == -1) { - loggers::get_instance().warning("http_codec::decode: get_line failed, errno: %d", errno); - return -1; - } - loggers::get_instance().log_msg("http_codec::decode: message_id: ", message_id); - // Extract parameters - try { - std::string str(static_cast(message_id)); - std::regex rgx("\\s*(\\w+)/"); - std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); - std::smatch m = *begin; - loggers::get_instance().log("http_codec::decode: %d - %s", m.size(), m[0].str().c_str()); - if (m[0].str().compare("HTTP/") == 0) { // HTTP response - LibHttp__TypesAndValues::Response response; - std::regex rgx("\\s*HTTP/(\\d+)\\.(\\d+)\\s+(\\d+)\\s+([\\w\\s\\t\\v\\f]+)*"); - std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); - std::smatch m = *begin; - loggers::get_instance().log("http_codec::decode: Process response: %d", m.size()); - if (m.size() != 5) { - loggers::get_instance().warning("http_codec::decode: Unsupported tag"); - return -1; - } - response.version__major() = std::stoi(m[1].str().c_str()); - response.version__minor() = std::stoi(m[2].str().c_str()); - response.statuscode() = std::stoi(m[3].str().c_str()); - response.statustext() = CHARSTRING(m[4].str().c_str()); - LibHttp__TypesAndValues::Headers headers; - std::string content_type; - decode_headers(decoding_buffer, headers, content_type); - response.header() = headers; - loggers::get_instance().log_to_hexa("Before decoding Body: ", decoding_buffer); - LibHttp__MessageBodyTypes::HttpMessageBody body; - if (decode_body(decoding_buffer, body, content_type) == -1) { - response.body().set_to_omit(); - } else { - response.body() = OPTIONAL(body); - } - // Add lower layers parameters - loggers::get_instance().log("http_codec::decode: Add lower layers parameters"); - params->log(); - params::const_iterator it = params->find(params::use_ssl); - if (it != params->cend()) { - loggers::get_instance().log("http_codec::receive_data: tls=%s", it->second.c_str()); - response.tls() = (it->second.compare("1") == 0) ? true : false; - } else { - response.tls().set_to_omit(); - } - it = params->find(params::mutual_auth); - if (it != params->cend()) { - loggers::get_instance().log("http_codec::receive_data: mutual_tls=%s", it->second.c_str()); - response.mutual__tls() = (it->second.compare("1") == 0) ? true : false; - } else { - response.mutual__tls().set_to_omit(); - } - msg.response() = response; - } else { // HTTP request - LibHttp__TypesAndValues::Request request; - std::regex rgx("\\s*(\\w+)\\s+(.+)\\s+HTTP/(\\d)\\.(\\d)"); - std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); - std::smatch m = *begin; - if (m.size() != 5) { - loggers::get_instance().error("http_codec::decode: Unsupported tag"); - return -1; - } - request.method() = CHARSTRING(m[1].str().c_str()); - request.uri() = CHARSTRING(m[2].str().c_str()); - request.version__major() = std::stoi(m[3].str().c_str()); - request.version__minor() = std::stoi(m[4].str().c_str()); - LibHttp__TypesAndValues::Headers headers; - std::string content_type; - decode_headers(decoding_buffer, headers, content_type); - request.header() = headers; - OPTIONAL body; - body.set_to_omit(); - if (decode_body(decoding_buffer, body, content_type) == -1) { - request.body().set_to_omit(); - } else { - request.body() = body; - } - msg.request() = request; - } - - loggers::get_instance().log_msg("<<< http_codec::decode: ", (const Base_Type &)msg); - return 0; - } catch (const std::logic_error &e) { - return -1; - } -} - -int http_codec::encode_request(const LibHttp__TypesAndValues::Request &p_request, TTCN_Buffer &p_encoding_buffer) { - loggers::get_instance().log_msg(">>> http_codec::encode_request: ", (const Base_Type &)p_request); - - // Encode generic part - p_encoding_buffer.put_cs(p_request.method()); - p_encoding_buffer.put_c(' '); - p_encoding_buffer.put_cs(p_request.uri()); - p_encoding_buffer.put_cs(" HTTP/"); - p_encoding_buffer.put_cs(int2str(p_request.version__major())); - p_encoding_buffer.put_c('.'); - p_encoding_buffer.put_cs(int2str(p_request.version__minor())); - p_encoding_buffer.put_cs("\r\n"); - - // Encode headers excepeted the Content-Length - const LibHttp__TypesAndValues::Headers &headers = p_request.header(); - std::string content_type; - for (int i = 0; i < headers.size_of(); i++) { - const LibHttp__TypesAndValues::Header &header = headers[i]; - loggers::get_instance().log_msg("http_codec::encode_request: Processing header ", header.header__name()); - if (std::string(static_cast(header.header__name())).compare("Content-Length") == 0) { // Skip it, processed later - loggers::get_instance().log("http_codec::encode_request: Skip it"); - continue; - } else { - p_encoding_buffer.put_cs(header.header__name()); - p_encoding_buffer.put_cs(": "); - const OPTIONAL &o = header.header__value(); - if (o.ispresent()) { - const LibHttp__TypesAndValues::charstring__list &v = dynamic_cast &>(o); - if (v.size_of() > 0) { - loggers::get_instance().log_msg("http_codec::encode_request: Processing value ", v[0]); - if (std::string(static_cast(header.header__name())).compare("Content-Type") == 0) { // Store it for HTTP body payload encoding - loggers::get_instance().log("http_codec::encode_request: Storing Content-Type"); - int j = 0; - while (j < v.size_of()) { - content_type += v[j++]; - } // End of 'while' statement - } - p_encoding_buffer.put_cs(v[0]); - int j = 1; - while (j < v.size_of()) { - p_encoding_buffer.put_cs(", "); - loggers::get_instance().log_msg("http_codec::encode_request: Processing value ", v[j]); - p_encoding_buffer.put_cs(v[j++]); - } // End of 'while' statement - } - } // else, do not include it - } - p_encoding_buffer.put_cs("\r\n"); - } // End of 'for' statement - - // Encode message body - const OPTIONAL &v = p_request.body(); - OCTETSTRING os; - if (v.ispresent()) { - const LibHttp__MessageBodyTypes::HttpMessageBody &body = static_cast(*v.get_opt_value()); - loggers::get_instance().log_msg("http_codec::encode_request: body: ", body); - if (encode_body(body, os, content_type) == -1) { - loggers::get_instance().warning("http_codec::encode_request: Failed to encode HTTP body"); - _ec.length = 0; - _ec.is_content_length_present = 0x00; - } else { - _ec.length = os.lengthof(); - _ec.is_content_length_present = 0x01; - } - loggers::get_instance().log("http_codec::encode_request: length=%d", _ec.length); - } else { - loggers::get_instance().log("http_codec::encode_request: HTTP body field not present"); - _ec.length = 0; - _ec.is_content_length_present = 0x00; - } - - // Encode Content-Length header - p_encoding_buffer.put_cs("Content-Length: "); - if (_ec.length != 0) { - loggers::get_instance().log("http_codec::encode_request: Content-Length: %s", - static_cast(int2str(_ec.length + 2 /*Stand for the last CRLF*/))); - p_encoding_buffer.put_cs(static_cast(int2str(_ec.length))); - _ec.is_content_length_present = 0x01; - } else { - p_encoding_buffer.put_cs("0"); - _ec.is_content_length_present = 0x00; - } - loggers::get_instance().log("http_codec::encode_request: Content-Length: %d - %x", _ec.length, _ec.is_content_length_present); - p_encoding_buffer.put_cs("\r\n"); - - // Add message body - p_encoding_buffer.put_cs("\r\n"); - if (_ec.is_content_length_present == 0x01) { - loggers::get_instance().log_msg("http_codec::encode_request: Add body ", os); - p_encoding_buffer.put_os(os); - // p_encoding_buffer.put_cs("\r\n"); - } - - loggers::get_instance().log_to_hexa("<<< http_codec::encode_request: ", p_encoding_buffer); - return 0; -} - -int http_codec::encode_response(const LibHttp__TypesAndValues::Response &p_response, TTCN_Buffer &p_encoding_buffer) { - loggers::get_instance().log_msg(">>> http_codec::encode_response: ", (const Base_Type &)p_response); - - // Encode generic part - p_encoding_buffer.put_cs("HTTP/"); - p_encoding_buffer.put_cs(int2str(p_response.version__major())); - p_encoding_buffer.put_c('.'); - p_encoding_buffer.put_cs(int2str(p_response.version__minor())); - p_encoding_buffer.put_cs(" "); - p_encoding_buffer.put_cs(int2str(p_response.statuscode())); - p_encoding_buffer.put_cs(" "); - if (p_response.statustext().lengthof() != 0) { - p_encoding_buffer.put_cs(p_response.statustext()); - } - p_encoding_buffer.put_cs("\r\n"); - - // Encode headers excepeted the Content-Length - const LibHttp__TypesAndValues::Headers &headers = p_response.header(); - std::string content_type; - for (int i = 0; i < headers.size_of(); i++) { - const LibHttp__TypesAndValues::Header &header = headers[i]; - loggers::get_instance().log_msg("http_codec::encode_response: Processing header ", header.header__name()); - if (std::string(static_cast(header.header__name())).compare("Content-Length") == 0) { - continue; - } else { - p_encoding_buffer.put_cs(header.header__name()); - p_encoding_buffer.put_cs(": "); - const OPTIONAL &o = header.header__value(); - if (o.ispresent()) { - const LibHttp__TypesAndValues::charstring__list &v = dynamic_cast &>(o); - if (v.size_of() > 0) { - loggers::get_instance().log_msg("http_codec::encode_response: Processing value ", v[0]); - if (std::string(static_cast(header.header__name())).compare("Content-Type") == 0) { // Store it for HTTP body payload encoding - loggers::get_instance().log("http_codec::encode_response: Storing Content-Type"); - int j = 0; - while (j < v.size_of()) { - content_type += v[j++]; - } // End of 'while' statement - } - p_encoding_buffer.put_cs(v[0]); - int j = 1; - while (j < v.size_of()) { - p_encoding_buffer.put_cs(", "); - loggers::get_instance().log_msg("http_codec::encode_response: Processing value ", v[j]); - p_encoding_buffer.put_cs(v[j++]); - j += 1; - } // End of 'while' statement - } - } // else, do not include it - } - p_encoding_buffer.put_cs("\r\n"); - } // End of 'for' statement - - // Encode message body - const OPTIONAL &v = p_response.body(); - OCTETSTRING os; - if (v.ispresent()) { - const LibHttp__MessageBodyTypes::HttpMessageBody &body = static_cast(*v.get_opt_value()); - loggers::get_instance().log_msg("http_codec::encode_response: body: ", body); - if (encode_body(body, os, content_type) == -1) { - _ec.length = 0; - _ec.is_content_length_present = 0x00; - } else { - _ec.length = os.lengthof(); - _ec.is_content_length_present = 0x01; - } - loggers::get_instance().log("http_codec::encode_response: length=%d", _ec.length); - } else { - loggers::get_instance().log("http_codec::encode_response: HTTP body field not present"); - _ec.length = 0; - _ec.is_content_length_present = 0x00; - } - - // Encode Content-Length header - p_encoding_buffer.put_cs("Content-Length: "); - if (_ec.length != 0) { - loggers::get_instance().log("http_codec::encode_request: Content-Length: %s", - static_cast(int2str(_ec.length + 2 /*Stand for the last CRLF*/))); - p_encoding_buffer.put_cs(static_cast(int2str(_ec.length))); - _ec.is_content_length_present = 0x01; - } else { - p_encoding_buffer.put_cs("0"); - _ec.is_content_length_present = 0x00; - } - loggers::get_instance().log("http_codec::encode_request: Content-Length: %d - %x", _ec.length, _ec.is_content_length_present); - p_encoding_buffer.put_cs("\r\n"); - - // Add message body - p_encoding_buffer.put_cs("\r\n"); - if (_ec.is_content_length_present == 0x01) { - loggers::get_instance().log_msg("http_codec::encode_request: Add body ", os); - p_encoding_buffer.put_os(os); - // p_encoding_buffer.put_cs("\r\n"); - } - - loggers::get_instance().log_to_hexa("<<< http_codec::encode_response: ", p_encoding_buffer); - return 0; -} - -int http_codec::decode_headers(TTCN_Buffer &decoding_buffer, LibHttp__TypesAndValues::Headers &headers, std::string &p_content_type) { - loggers::get_instance().log(">>> http_codec::decode_headers"); - loggers::get_instance().log_to_hexa("http_codec::decode_headers: ", decoding_buffer); - - CHARSTRING cstr; - int i = 0; - while (true) { - switch (get_line(decoding_buffer, cstr, true)) { - case 0: { - loggers::get_instance().log_msg("http_codec::decode_headers: ", cstr); - LibHttp__TypesAndValues::Header header; - if (decode_header(cstr, header) == -1) { - loggers::get_instance().warning("http_codec::decode_headers: Failed to decode header %s", static_cast(cstr)); - return -1; - } - headers[i++] = header; - if (std::string(static_cast(header.header__name())).compare("Content-Type") == 0) { - if (header.header__value().is_present() != 0) { - const PreGenRecordOf::PREGEN__RECORD__OF__CHARSTRING &l = - static_cast(*header.header__value().get_opt_value()); - p_content_type = static_cast(l[0]); - } else { - p_content_type = ""; - } - } - } break; - case 1: - if (headers.is_bound()) { - loggers::get_instance().log_msg("<<< http_codec::decode_headers: ", headers); - return 0; - } else { - loggers::get_instance().warning("http_codec::decode_headers: Failed to decode headers"); - return -1; - } - case -1: - loggers::get_instance().warning("http_codec::decode_headers: Failed to decode headers"); - return -1; - } // End of 'switch' statement - } // End of 'while' statement -} - -int http_codec::decode_header(CHARSTRING &header_line, LibHttp__TypesAndValues::Header &header) { - loggers::get_instance().log_msg(">>> http_codec::decode_header", header_line); - - try { - std::string str(static_cast(header_line)); - std::regex rgx("([0-9a-zA-Z-]+)\\:\\s+(.+)(,(.+))*"); - std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); - std::smatch m = *begin; - if (m.size() < 5) { - loggers::get_instance().warning("http_codec::decode_header: Failed to decode header %s", str.c_str()); - return -1; - } - loggers::get_instance().log("http_codec::decode_header: %d", m.size()); - header.header__name() = CHARSTRING(m[1].str().c_str()); - LibHttp__TypesAndValues::charstring__list v; - for (unsigned int j = 0; j < m.size(); j++) { - if (m[j + 2].str().length() == 0) { - break; - } - v[j] = CHARSTRING(m[j + 2].str().c_str()); - } // End of 'for' statement - header.header__value() = OPTIONAL(v); - - if (m[1].str().compare("Content-Length") == 0) { - // Save the the body length - loggers::get_instance().log("http_codec::decode_header: decoded Content-Length %s", m[2].str().c_str()); - _dc.length = std::stoi(m[2].str()); - } else if (m[1].str().compare("Transfer-Encoding") == 0) { - if (m[2].str().find("chunked") != std::string::npos) { - _dc.chunked = true; - loggers::get_instance().log("http_codec::decode_header: decoded Transfer-Encoding %x", _dc.chunked); - } - } - - return 0; - } catch (const std::logic_error &e) { - return -1; - } -} - -int http_codec::encode_body(const LibHttp__MessageBodyTypes::HttpMessageBody &p_message_body, OCTETSTRING &p_encoding_buffer, - const std::string &p_content_type) { - loggers::get_instance().log_msg(">>> http_codec::encode_body: ", (const Base_Type &)p_message_body); - - // Sanity check - if (p_content_type.empty()) { - loggers::get_instance().warning("http_codec::encode_body: Failed to select a codec for HTTP body payload"); - return -1; - } - - if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_binary__body)) { - const LibHttp__BinaryMessageBodyTypes::BinaryBody &binary_body = p_message_body.binary__body(); - if (binary_body.ischosen(LibHttp__BinaryMessageBodyTypes::BinaryBody::ALT_raw)) { - p_encoding_buffer = OCTETSTRING(binary_body.raw().lengthof(), (unsigned char *)static_cast(binary_body.raw())); - } else { - encode_body_binary(binary_body, p_encoding_buffer, p_content_type); - } - } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_json__body)) { - const LibHttp__JsonMessageBodyTypes::JsonBody& json_body = p_message_body.json__body(); - if (json_body.ischosen(LibHttp__JsonMessageBodyTypes::JsonBody::ALT_raw)) { - p_encoding_buffer = unichar2oct(json_body.raw()); - } else { - encode_body_json(json_body, p_encoding_buffer, p_content_type); - } - } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_xml__body)) { - const LibHttp__XmlMessageBodyTypes::XmlBody &xml_body = p_message_body.xml__body(); - if (xml_body.ischosen(LibHttp__XmlMessageBodyTypes::XmlBody::ALT_raw)) { - p_encoding_buffer = OCTETSTRING(xml_body.raw().lengthof(), (unsigned char *)static_cast(xml_body.raw())); - } else { - encode_body_xml(xml_body, p_encoding_buffer, p_content_type); - } - } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_html__body)) { - p_encoding_buffer = OCTETSTRING(p_message_body.html__body().lengthof(), (unsigned char *)static_cast(p_message_body.html__body())); - } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_text__body)) { - p_encoding_buffer = OCTETSTRING(p_message_body.text__body().lengthof(), (unsigned char *)static_cast(p_message_body.text__body())); - } else { - loggers::get_instance().warning("http_codec::encode_body: Failed to encode HTTP message body"); - return -1; - } - loggers::get_instance().log_msg("http_codec::encode_body: HTTP message ", p_encoding_buffer); - _ec.length = p_encoding_buffer.lengthof(); - loggers::get_instance().log("http_codec::encode_body: HTTP message length: %d", _ec.length); - - return 0; -} - -int http_codec::decode_body(TTCN_Buffer &decoding_buffer, LibHttp__MessageBodyTypes::HttpMessageBody &message_body, const std::string &p_content_type) { - loggers::get_instance().log(">>> http_codec::decode_body"); - loggers::get_instance().log_to_hexa("http_codec::decode_body", decoding_buffer); - loggers::get_instance().log("http_codec::decode_body: # of codecs=%d - %p", _codecs.size(), this); - loggers::get_instance().log("http_codec::decode_body: Content-Type=%s", p_content_type.c_str()); - - // Sanity checks - if (decoding_buffer.get_len() - decoding_buffer.get_pos() <= 0) { - return -1; - } - /* TODO Uncomment if (p_content_type.empty()) { - loggers::get_instance().warning("http_codec::encode_body: Failed to select a codec for HTTP body payload"); - return -1; - }*/ - - OCTETSTRING s(decoding_buffer.get_len() - decoding_buffer.get_pos(), decoding_buffer.get_data() + decoding_buffer.get_pos()); - loggers::get_instance().log_msg("http_codec::decode_body: raw body=", s); - - // Align the payload length with the specified Content-Lenght value - loggers::get_instance().log("http_codec::decode_body: _dc.length=%d - body length=%d", _dc.length, s.lengthof()); - OCTETSTRING body; - if (_dc.length != 0) { - const unsigned char *p = static_cast(s); - if ((unsigned int)s.lengthof() <= _dc.length) { - body = OCTETSTRING(s.lengthof(), p); - } else { - body = OCTETSTRING(_dc.length, p); - } - } else { - loggers::get_instance().warning("http_codec::decode_body: No Conten-Length header, process all remaining bytes"); - body = s; - } - loggers::get_instance().log_msg("http_codec::decode_body: Aligned body=", body); - loggers::get_instance().log("http_codec::decode_body: body length=%d", body.lengthof()); - /* TODO To be removed - // Remove CRLF if any - int counter = 0; - if ((body[body.lengthof() - 1].get_octet() == 0x0d) || (body[body.lengthof() - 1].get_octet() == 0x0a)) { - counter += 1; - if ((body[body.lengthof() - 2].get_octet() == 0x0d) || (body[body.lengthof() - 2].get_octet() == 0x0a)) { - counter += 1; - } - } - loggers::get_instance().log("http_codec::decode_body: counter=%d", counter); - body = OCTETSTRING(body.lengthof() - counter, static_cast(body)); - */ - if (_dc.chunked) { - int counter = 0; - int prev = 0; - OCTETSTRING os(0, nullptr); - do { - while (counter < body.lengthof()) { // Extract the size of the chunk \r[\n] - if ((body[counter].get_octet() == '\r') || (body[counter].get_octet() == '\n')) { - break; - } - counter += 1; - } // End of 'while' statement - loggers::get_instance().log("http_codec::decode_body: Chunked(0): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); - if (counter < body.lengthof()) { - int idx = counter - prev; - OCTETSTRING trunk(idx, static_cast(body)); - loggers::get_instance().log_msg("http_codec::decode_body: trunk: ", trunk); - std::string str((const char *)static_cast(trunk), idx); - loggers::get_instance().log("http_codec::decode_body: str: '%s'", str.c_str()); - int len = std::stoi(str, nullptr, 16); // converter::get_instance().string_to_int(str); - loggers::get_instance().log("http_codec::decode_body: Chunk len: %d", len); - while (counter < body.lengthof() && ((body[counter].get_octet() == '\r') || (body[counter].get_octet() == '\n'))) { // Skip additional \n - counter += 1; - } // End of 'while' statement - if (counter < body.lengthof()) { - loggers::get_instance().log("http_codec::decode_body: Chunked (1): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); - os += OCTETSTRING(len, counter + static_cast(body)); - loggers::get_instance().log_msg("http_codec::decode_body: os=", os); - counter += len; - loggers::get_instance().log("http_codec::decode_body: Chunked: %02x %02x %02x", body[counter].get_octet(), body[counter + 1].get_octet(), - body[counter + 2].get_octet()); - loggers::get_instance().log("http_codec::decode_body: Chunked (2): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); - while (counter < body.lengthof() && ((body[counter].get_octet() == '\r') || (body[counter].get_octet() == '\n'))) { // Skip additional \n - counter += 1; - } // End of 'while' statement - prev = counter; - loggers::get_instance().log("http_codec::decode_body: Chunked (3): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); - } - } - } while (counter < body.lengthof()); // Process next chunk if any - body = os; - loggers::get_instance().log_msg("http_codec::decode_body: Finalised body=", body); - } - // Check if HTTP message body contains binary characters - for (int i = 0; i < body.lengthof(); i++) { - unsigned char c = body[i].get_octet(); - if (!std::isprint(c) && !std::isspace(c) && !std::ispunct(c)) { - loggers::get_instance().log("http_codec::decode_body: Byte #%d is not printable: 0x%02x", i, body[i].get_octet()); - _dc.is_binary = 0x01; - break; - } - } // End of 'for' statement - loggers::get_instance().log("http_codec::decode_body: Binary mode: %x", _dc.is_binary); - LibHttp__MessageBodyTypes::HttpMessageBody v; - if (_dc.is_binary == 0x01) { - LibHttp__BinaryMessageBodyTypes::BinaryBody binary_body; - decode_body_binary(body, binary_body, p_content_type); - message_body.binary__body() = binary_body; - } else { - // Convert into string - params p; - p["decode_str"] = std::string(static_cast(body), body.lengthof() + static_cast(body)); - loggers::get_instance().log("http_codec::decode_body: decode_str: %s", p["decode_str"].c_str()); - // Try to identify xml - if (p["decode_str"].find("") != std::string::npos) { // Try to identify HTML - loggers::get_instance().log("http_codec::decode_body: Find html message"); - LibHttp__MessageBodyTypes::HtmlBody html_body; - decode_body_html(body, html_body, p_content_type, &p); - message_body.html__body() = html_body; - } else if (p_content_type.find("json") != std::string::npos) { // Try to identify JSON - loggers::get_instance().log("http_codec::decode_body: Find json message"); - LibHttp__JsonMessageBodyTypes::JsonBody json_body; - decode_body_json(body, json_body, p_content_type, &p); - message_body.json__body() = json_body; - } else { - loggers::get_instance().log("http_codec::decode_body: Use textBody as default"); - LibHttp__MessageBodyTypes::TextBody text_body; - message_body.text__body() = CHARSTRING(body.lengthof(), (char *)static_cast(body)); - } - } - - return 0; -} - -int http_codec::get_line(TTCN_Buffer &buffer, CHARSTRING &to, const bool concatenate_header_lines) { - unsigned int i = 0; - const unsigned char *cc_to = buffer.get_read_data(); - - // Sanity checks - if (buffer.get_read_len() == 0) { - return -1; - } - - while (true) { - // Skip spaces, and empty lines - for (; i < buffer.get_read_len() && cc_to[i] != '\0' && cc_to[i] != '\r' && cc_to[i] != '\n'; i++) - ; - if (i >= buffer.get_read_len()) { // No more characters to process - to = CHARSTRING(""); - return -1; - } else if (cc_to[i] == '\n') { // New line found, we don't care is '\r' is missing - if ((i > 0) && ((i + 1) < buffer.get_read_len()) && concatenate_header_lines && ((cc_to[i + 1] == ' ') || (cc_to[i + 1] == '\t'))) { - i += 1; // Skip it - } else { - to = CHARSTRING(i, (const char *)cc_to); - buffer.set_pos(buffer.get_pos() + i + 1); - return i == 0 ? 1 : 0; - } - } else { - if ((i + 1) < buffer.get_read_len() && cc_to[i + 1] != '\n') { - return -1; - } else if (i > 0 && (i + 2) < buffer.get_read_len() && concatenate_header_lines && (cc_to[i + 2] == ' ' || cc_to[i + 2] == '\t')) { - i += 2; - } else { - to = CHARSTRING(i, (const char *)cc_to); - buffer.set_pos(buffer.get_pos() + i + 2); - return i == 0 ? 1 : 0; - } - } - } // End of 'while' statement -} - -void http_codec::set_payload_codecs(const std::string &p_codecs) { - loggers::get_instance().log(">>> http_codec::set_payload_codecs: %s", p_codecs.c_str()); - - // Sanity check - if (p_codecs.length() == 0) { - return; - } - - // Extract codecs - try { - std::regex rgx("(\\w+):(\\w+)(;(\\w+):(\\w+))*"); - std::sregex_iterator begin(p_codecs.cbegin(), p_codecs.cend(), rgx); - std::sregex_iterator end = std::sregex_iterator(); - // E.g. 9 - xml - :held_codec - held_codec - ;html:html_codec - html:html_codec - html - :html_codec - html_codec - for (std::sregex_iterator it = begin; it != end; ++it) { - std::smatch m = *it; - loggers::get_instance().log("http_codec::set_payload_codecs: %d - %s - %s - %s - %s - %s - %s - %s - %s", m.size(), m[1].str().c_str(), - m[2].str().c_str(), m[3].str().c_str(), m[4].str().c_str(), m[5].str().c_str(), m[6].str().c_str(), m[7].str().c_str(), - m[8].str().c_str()); - for (unsigned int j = 1; j < m.size() - 1; j += 3) { // Exclude m[0] - loggers::get_instance().log("http_codec::set_payload_codecs: insert (%s, %s), j = %d", m[j].str().c_str(), m[j + 1].str().c_str(), j); - if (m[j].str().empty()) { - break; - } - std::string key(m[j].str()); - loggers::get_instance().log("http_codec::set_payload_codecs: Add codec %s", key.c_str()); - _codecs.insert( - std::make_pair(key, std::unique_ptr>(codec_stack_builder::get_instance()->get_codec(m[j + 1].str().c_str())))); - } // End of 'for' statement - } // End of 'for' statement - loggers::get_instance().log("http_codec::set_payload_codecs: _codecs length=%d - %p", _codecs.size(), this); - } catch (const std::logic_error &e) { - loggers::get_instance().warning("http_codec::set_payload_codecs: std::logic_error: %s", e.what()); - _codecs.clear(); - } -} - -bool http_codec::decode_body_html(const OCTETSTRING &p_data, CHARSTRING &p_html_body, const std::string &p_content_type, params* p_params) { - p_html_body = CHARSTRING(p_data.lengthof(), (char*)static_cast(p_data)); - return true; -} +#include +#include +#include + +#include "codec_stack_builder.hh" + +#include "http_codec.hh" + +#include "loggers.hh" + +#include "LibHttp_TypesAndValues.hh" +#include "LibHttp_MessageBodyTypes.hh" +#include "LibHttp_XmlMessageBodyTypes.hh" +#include "LibHttp_JsonMessageBodyTypes.hh" + +int http_codec::encode(const LibHttp__TypesAndValues::HttpMessage &msg, OCTETSTRING &data) { + loggers::get_instance().log_msg(">>> http_codec::encode: ", (const Base_Type &)msg); + loggers::get_instance().log(">>> http_codec::encode: %p", this); + + TTCN_EncDec::clear_error(); + TTCN_Buffer encoding_buffer; + + _ec.reset(); + + int result; + if (msg.ischosen(LibHttp__TypesAndValues::HttpMessage::ALT_request)) { + result = encode_request(msg.request(), encoding_buffer); + } else if (msg.ischosen(LibHttp__TypesAndValues::HttpMessage::ALT_response)) { + result = encode_response(msg.response(), encoding_buffer); + } else { + loggers::get_instance().warning("http_codec::encode: Unbound HttpMessage"); + return -1; + } + + data = OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data()); + + loggers::get_instance().log_msg("<<< http_codec::encode: data=", data); + return result; +} + +int http_codec::decode(const OCTETSTRING &data, LibHttp__TypesAndValues::HttpMessage &msg, params *params) { + loggers::get_instance().log_msg(">>> http_codec::decode: data=", data); + + TTCN_EncDec::clear_error(); + TTCN_Buffer decoding_buffer; + + if (_initial_content_length != 0) { // Check if the data is a new fragment of the response + loggers::get_instance().warning("http_codec::decode: Need to bufferize and wait for all fragments received"); + _bufferized_buffers.push_back(data); + _current_content_length += data.lengthof(); // FIXME Need to calculate the size of the header buffer, do not assume th first fragmwnt is the header buffer + loggers::get_instance().log("http_codec::decode: _bufferized_buffers size: %d - _current_content_length: %d - _initial_content_length: %d", _bufferized_buffers.size(), _current_content_length, _initial_content_length); + if (_current_content_length < _initial_content_length) { // Wait for the next fragment + loggers::get_instance().warning("http_codec::decode: Wait for the next fragment"); + return -2; + } else { // Rebuild the wall message and continue the decoding + loggers::get_instance().log("http_codec::decode: All the fragments were received, rebuild message"); + // Concatenate the fragments + loggers::get_instance().log("http_codec::decode: Concatenate bufferized datas"); + for (size_t i = 0; i < _bufferized_buffers.size(); i++) { + decoding_buffer.put_string(_bufferized_buffers[i]); + } // End of 'for' statement + _bufferized_buffers.clear(); + loggers::get_instance().log("http_codec::decode: _bufferized_buffers cleared: %d", _bufferized_buffers.size()); + // Reset counters + loggers::get_instance().log("http_codec::decode: Reset bufferization counters"); + _initial_content_length = 0; + _current_content_length = 0; + // Continue the decoding + } + } else { // It can be a full HTTP response or the first gragment of the HTTP response + decoding_buffer.put_string(data); + } + loggers::get_instance().log("http_codec::decode: decoding_buffer size: %d", decoding_buffer.get_len()); + loggers::get_instance().log_to_hexa("http_codec::decode: Before decoding_buffer Body: ", decoding_buffer); + + _dc.reset(); + + _params = params; + + if ((*decoding_buffer.get_data() & 0x80) == 0x80) { + loggers::get_instance().warning("http_codec::decode: Unicode format not supported"); + return -1; + } + + // Get the first line (e.g. HTTP/1.1 302 Found or POST / HTTP/1.1) + CHARSTRING message_id; + if (get_line(decoding_buffer, message_id) == -1) { + loggers::get_instance().warning("http_codec::decode: get_line failed, errno: %d", errno); + return -1; + } + loggers::get_instance().log_msg("http_codec::decode: message_id: ", message_id); + // Extract parameters + try { + std::string str(static_cast(message_id)); + std::regex rgx("\\s*(\\w+)/"); + std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); + std::smatch m = *begin; + loggers::get_instance().log("http_codec::decode: %d - %s", m.size(), m[0].str().c_str()); + if (m[0].str().compare("HTTP/") == 0) { // HTTP response + LibHttp__TypesAndValues::Response response; + std::regex rgx("\\s*HTTP/(\\d+)\\.(\\d+)\\s+(\\d+)\\s+([\\w\\s\\t\\v\\f]+)*"); + std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); + std::smatch m = *begin; + loggers::get_instance().log("http_codec::decode: Process response: %d", m.size()); + if (m.size() != 5) { + loggers::get_instance().warning("http_codec::decode: Unsupported tag"); + return -1; + } + response.version__major() = std::stoi(m[1].str().c_str()); + response.version__minor() = std::stoi(m[2].str().c_str()); + response.statuscode() = std::stoi(m[3].str().c_str()); + response.statustext() = CHARSTRING(m[4].str().c_str()); + LibHttp__TypesAndValues::Headers headers; + std::string content_type; + decode_headers(decoding_buffer, headers, content_type); + loggers::get_instance().log("http_codec::decode: _dc.length=%d", _dc.length); + loggers::get_instance().log("http_codec::decode: decoding_buffer.get_len()=%d", decoding_buffer.get_len()); + if (_dc.length > decoding_buffer.get_len()) { // HTTP response is fragmented + // Need to bufferize the first packet and wait for the other fragments tp be received + loggers::get_instance().warning("http_codec::decode: Need to bufferize the first packet and wait for the other fragments to be received"); + // Set counters + loggers::get_instance().log("http_codec::decode: Set bufferization counters"); + _initial_content_length = _dc.length; + _current_content_length = 0; + _bufferized_buffers.push_back(data); + _current_content_length += data.lengthof(); + loggers::get_instance().log("http_codec::decode: _bufferized_buffers size: %d - _current_content_length: %d", _bufferized_buffers.size(), _current_content_length); + return -2; + } else { + // Force reset counters + loggers::get_instance().log("http_codec::decode: Force reset bufferization counters"); + _initial_content_length = 0; + _current_content_length = 0; + } + + response.header() = headers; + loggers::get_instance().log_to_hexa("Before decoding Body: ", decoding_buffer); + loggers::get_instance().log("http_codec::decode: _initial_content_length = %d", _initial_content_length); + loggers::get_instance().log("http_codec::decode: headers().content_length (_dc.length) = %d - decoding_buffer.get_len() = %d", _dc.length, decoding_buffer.get_len()); + LibHttp__MessageBodyTypes::HttpMessageBody body; + if (decode_body(decoding_buffer, body, content_type) == -1) { + response.body().set_to_omit(); + } else { + response.body() = OPTIONAL(body); + } + // Add lower layers parameters + loggers::get_instance().log("http_codec::decode: Add lower layers parameters"); + params->log(); + params::const_iterator it = params->find(params::use_ssl); + if (it != params->cend()) { + loggers::get_instance().log("http_codec::receive_data: tls=%s", it->second.c_str()); + response.tls() = (it->second.compare("1") == 0) ? true : false; + } else { + response.tls().set_to_omit(); + } + it = params->find(params::mutual_auth); + if (it != params->cend()) { + loggers::get_instance().log("http_codec::receive_data: mutual_tls=%s", it->second.c_str()); + response.mutual__tls() = (it->second.compare("1") == 0) ? true : false; + } else { + response.mutual__tls().set_to_omit(); + } + msg.response() = response; + } else { // HTTP request + LibHttp__TypesAndValues::Request request; + std::regex rgx("\\s*(\\w+)\\s+(.+)\\s+HTTP/(\\d)\\.(\\d)"); + std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); + std::smatch m = *begin; + if (m.size() != 5) { + loggers::get_instance().error("http_codec::decode: Unsupported tag"); + return -1; + } + request.method() = CHARSTRING(m[1].str().c_str()); + request.uri() = CHARSTRING(m[2].str().c_str()); + request.version__major() = std::stoi(m[3].str().c_str()); + request.version__minor() = std::stoi(m[4].str().c_str()); + LibHttp__TypesAndValues::Headers headers; + std::string content_type; + decode_headers(decoding_buffer, headers, content_type); + loggers::get_instance().log("http_codec::decode (request): _dc.length=%d", _dc.length); + loggers::get_instance().log("http_codec::decode (request): decoding_buffer.get_len()=%d", decoding_buffer.get_len()); + if (_dc.length > decoding_buffer.get_len()) { // HTTP response is fragmented + // Need to bufferize the first packet and wait for the other fragments tp be received + loggers::get_instance().warning("http_codec::decode (request): Need to bufferize the first packet and wait for the other fragments to be received"); + // Set counters + loggers::get_instance().log("http_codec::decode (request): Set bufferization counters"); + _initial_content_length = _dc.length; + _current_content_length = 0; + _bufferized_buffers.push_back(data); + _current_content_length += data.lengthof(); + loggers::get_instance().log("http_codec::decode (request): _bufferized_buffers size: %d - _current_content_length: %d", _bufferized_buffers.size(), _current_content_length); + return -2; + } else { + // Force reset counters + loggers::get_instance().log("http_codec::decode (request): Force reset bufferization counters"); + _initial_content_length = 0; + _current_content_length = 0; + } + + request.header() = headers; + loggers::get_instance().log_to_hexa("Before decoding Body (request): ", decoding_buffer); + loggers::get_instance().log("http_codec::decode (request): _initial_content_length = %d", _initial_content_length); + loggers::get_instance().log("http_codec::decode (request): headers().content_length (_dc.length) = %d - decoding_buffer.get_len() = %d", _dc.length, decoding_buffer.get_len()); + OPTIONAL body; + body.set_to_omit(); + if (decode_body(decoding_buffer, body, content_type) == -1) { + request.body().set_to_omit(); + } else { + request.body() = body; + } + msg.request() = request; + } + + loggers::get_instance().log_msg("<<< http_codec::decode: ", (const Base_Type &)msg); + return 0; + } catch (const std::logic_error &e) { + return -1; + } +} + +int http_codec::encode_request(const LibHttp__TypesAndValues::Request &p_request, TTCN_Buffer &p_encoding_buffer) { + loggers::get_instance().log_msg(">>> http_codec::encode_request: ", (const Base_Type &)p_request); + + // Encode generic part + p_encoding_buffer.put_cs(p_request.method()); + p_encoding_buffer.put_c(' '); + p_encoding_buffer.put_cs(p_request.uri()); + p_encoding_buffer.put_cs(" HTTP/"); + p_encoding_buffer.put_cs(int2str(p_request.version__major())); + p_encoding_buffer.put_c('.'); + p_encoding_buffer.put_cs(int2str(p_request.version__minor())); + p_encoding_buffer.put_cs("\r\n"); + + // Encode headers excepeted the Content-Length + const LibHttp__TypesAndValues::Headers &headers = p_request.header(); + std::string content_type; + for (int i = 0; i < headers.size_of(); i++) { + const LibHttp__TypesAndValues::Header &header = headers[i]; + loggers::get_instance().log_msg("http_codec::encode_request: Processing header ", header.header__name()); + if (std::string(static_cast(header.header__name())).compare("Content-Length") == 0) { // Skip it, processed later + loggers::get_instance().log("http_codec::encode_request: Skip it"); + continue; + } else { + p_encoding_buffer.put_cs(header.header__name()); + p_encoding_buffer.put_cs(": "); + const OPTIONAL &o = header.header__value(); + if (o.ispresent()) { + const LibHttp__TypesAndValues::charstring__list &v = dynamic_cast &>(o); + if (v.size_of() > 0) { + loggers::get_instance().log_msg("http_codec::encode_request: Processing value ", v[0]); + if (std::string(static_cast(header.header__name())).compare("Content-Type") == 0) { // Store it for HTTP body payload encoding + loggers::get_instance().log("http_codec::encode_request: Storing Content-Type"); + int j = 0; + while (j < v.size_of()) { + content_type += v[j++]; + } // End of 'while' statement + } + p_encoding_buffer.put_cs(v[0]); + int j = 1; + while (j < v.size_of()) { + p_encoding_buffer.put_cs(", "); + loggers::get_instance().log_msg("http_codec::encode_request: Processing value ", v[j]); + p_encoding_buffer.put_cs(v[j++]); + } // End of 'while' statement + } + } // else, do not include it + } + p_encoding_buffer.put_cs("\r\n"); + } // End of 'for' statement + + // Encode message body + const OPTIONAL &v = p_request.body(); + OCTETSTRING os; + if (v.ispresent()) { + const LibHttp__MessageBodyTypes::HttpMessageBody &body = static_cast(*v.get_opt_value()); + loggers::get_instance().log_msg("http_codec::encode_request: body: ", body); + if (encode_body(body, os, content_type) == -1) { + loggers::get_instance().warning("http_codec::encode_request: Failed to encode HTTP body"); + _ec.length = 0; + _ec.is_content_length_present = 0x00; + } else { + _ec.length = os.lengthof(); + _ec.is_content_length_present = 0x01; + } + loggers::get_instance().log("http_codec::encode_request: length=%d", _ec.length); + } else { + loggers::get_instance().log("http_codec::encode_request: HTTP body field not present"); + _ec.length = 0; + _ec.is_content_length_present = 0x00; + } + + // Encode Content-Length header + p_encoding_buffer.put_cs("Content-Length: "); + if (_ec.length != 0) { + loggers::get_instance().log("http_codec::encode_request: Content-Length: '%s'", + static_cast(int2str(_ec.length + 2 /*Stand for the last CRLF*/))); + p_encoding_buffer.put_cs(static_cast(int2str(_ec.length))); + _ec.is_content_length_present = 0x01; + } else { + p_encoding_buffer.put_cs("0"); + _ec.is_content_length_present = 0x00; + } + loggers::get_instance().log("http_codec::encode_request: Content-Length: %d - %x", _ec.length, _ec.is_content_length_present); + p_encoding_buffer.put_cs("\r\n"); + + // Add message body + p_encoding_buffer.put_cs("\r\n"); + if (_ec.is_content_length_present == 0x01) { + loggers::get_instance().log_msg("http_codec::encode_request: Add body ", os); + p_encoding_buffer.put_os(os); + // p_encoding_buffer.put_cs("\r\n"); + } + + loggers::get_instance().log_to_hexa("<<< http_codec::encode_request: ", p_encoding_buffer); + return 0; +} + +int http_codec::encode_response(const LibHttp__TypesAndValues::Response &p_response, TTCN_Buffer &p_encoding_buffer) { + loggers::get_instance().log_msg(">>> http_codec::encode_response: ", (const Base_Type &)p_response); + + // Encode generic part + p_encoding_buffer.put_cs("HTTP/"); + p_encoding_buffer.put_cs(int2str(p_response.version__major())); + p_encoding_buffer.put_c('.'); + p_encoding_buffer.put_cs(int2str(p_response.version__minor())); + p_encoding_buffer.put_cs(" "); + p_encoding_buffer.put_cs(int2str(p_response.statuscode())); + p_encoding_buffer.put_cs(" "); + if (p_response.statustext().lengthof() != 0) { + p_encoding_buffer.put_cs(p_response.statustext()); + } + p_encoding_buffer.put_cs("\r\n"); + + // Encode headers excepeted the Content-Length + const LibHttp__TypesAndValues::Headers &headers = p_response.header(); + std::string content_type; + for (int i = 0; i < headers.size_of(); i++) { + const LibHttp__TypesAndValues::Header &header = headers[i]; + loggers::get_instance().log_msg("http_codec::encode_response: Processing header ", header.header__name()); + if (std::string(static_cast(header.header__name())).compare("Content-Length") == 0) { + continue; + } else { + p_encoding_buffer.put_cs(header.header__name()); + p_encoding_buffer.put_cs(": "); + const OPTIONAL &o = header.header__value(); + if (o.ispresent()) { + const LibHttp__TypesAndValues::charstring__list &v = dynamic_cast &>(o); + if (v.size_of() > 0) { + loggers::get_instance().log_msg("http_codec::encode_response: Processing value ", v[0]); + if (std::string(static_cast(header.header__name())).compare("Content-Type") == 0) { // Store it for HTTP body payload encoding + loggers::get_instance().log("http_codec::encode_response: Storing Content-Type"); + int j = 0; + while (j < v.size_of()) { + content_type += v[j++]; + } // End of 'while' statement + } + p_encoding_buffer.put_cs(v[0]); + int j = 1; + while (j < v.size_of()) { + p_encoding_buffer.put_cs(", "); + loggers::get_instance().log_msg("http_codec::encode_response: Processing value ", v[j]); + p_encoding_buffer.put_cs(v[j++]); + j += 1; + } // End of 'while' statement + } + } // else, do not include it + } + p_encoding_buffer.put_cs("\r\n"); + } // End of 'for' statement + + // Encode message body + const OPTIONAL &v = p_response.body(); + OCTETSTRING os; + if (v.ispresent()) { + const LibHttp__MessageBodyTypes::HttpMessageBody &body = static_cast(*v.get_opt_value()); + loggers::get_instance().log_msg("http_codec::encode_response: body: ", body); + if (encode_body(body, os, content_type) == -1) { + _ec.length = 0; + _ec.is_content_length_present = 0x00; + } else { + _ec.length = os.lengthof(); + _ec.is_content_length_present = 0x01; + } + loggers::get_instance().log("http_codec::encode_response: length=%d", _ec.length); + } else { + loggers::get_instance().log("http_codec::encode_response: HTTP body field not present"); + _ec.length = 0; + _ec.is_content_length_present = 0x00; + } + + // Encode Content-Length header + p_encoding_buffer.put_cs("Content-Length: "); + if (_ec.length != 0) { + loggers::get_instance().log("http_codec::encode_request: Content-Length: '%s'", + static_cast(int2str(_ec.length + 2 /*Stand for the last CRLF*/))); + p_encoding_buffer.put_cs(static_cast(int2str(_ec.length))); + _ec.is_content_length_present = 0x01; + } else { + p_encoding_buffer.put_cs("0"); + _ec.is_content_length_present = 0x00; + } + loggers::get_instance().log("http_codec::encode_request: Content-Length: %d - %x", _ec.length, _ec.is_content_length_present); + p_encoding_buffer.put_cs("\r\n"); + + // Add message body + p_encoding_buffer.put_cs("\r\n"); + if (_ec.is_content_length_present == 0x01) { + loggers::get_instance().log_msg("http_codec::encode_request: Add body ", os); + p_encoding_buffer.put_os(os); + // p_encoding_buffer.put_cs("\r\n"); + } + + loggers::get_instance().log_to_hexa("<<< http_codec::encode_response: ", p_encoding_buffer); + return 0; +} + +int http_codec::decode_headers(TTCN_Buffer &decoding_buffer, LibHttp__TypesAndValues::Headers &headers, std::string& p_content_type) { + loggers::get_instance().log(">>> http_codec::decode_headers"); + loggers::get_instance().log_to_hexa("http_codec::decode_headers: ", decoding_buffer); + + CHARSTRING cstr; + int i = 0; + while (true) { + switch (get_line(decoding_buffer, cstr, true)) { + case 0: { + loggers::get_instance().log_msg("http_codec::decode_headers: ", cstr); + LibHttp__TypesAndValues::Header header; + if (decode_header(cstr, header) == -1) { + loggers::get_instance().warning("http_codec::decode_headers: Failed to decode header %s", static_cast(cstr)); + return -1; + } + headers[i++] = header; + if (std::string(static_cast(header.header__name())).compare("Content-Type") == 0) { + if (header.header__value().is_present() != 0) { + const PreGenRecordOf::PREGEN__RECORD__OF__CHARSTRING &l = + static_cast(*header.header__value().get_opt_value()); + p_content_type = static_cast(l[0]); + } else { + p_content_type = ""; + } + } + } break; + case 1: + if (headers.is_bound()) { + if (_dc.length == -1) { // content-Length header not found, force length to 0, assuming no body is present + loggers::get_instance().log("http_codec::decode_headers: Force _dc.length to 0"); + _dc.length = 0; + } + loggers::get_instance().log_msg("<<< http_codec::decode_headers: ", headers); + return 0; + } else { + loggers::get_instance().warning("http_codec::decode_headers: Failed to decode headers"); + return -1; + } + case -1: + loggers::get_instance().warning("http_codec::decode_headers: Failed to decode headers"); + return -1; + } // End of 'switch' statement + } // End of 'while' statement +} + +int http_codec::decode_header(CHARSTRING &header_line, LibHttp__TypesAndValues::Header &header) { + loggers::get_instance().log_msg(">>> http_codec::decode_header: ", header_line); + + try { + std::string str(static_cast(header_line)); + std::regex rgx("([0-9a-zA-Z-]+)\\:\\s+(.+)(,(.+))*"); + std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); + std::smatch m = *begin; + if (m.size() < 5) { + loggers::get_instance().warning("http_codec::decode_header: Failed to decode header %s", str.c_str()); + return -1; + } + loggers::get_instance().log("http_codec::decode_header: %d", m.size()); + header.header__name() = CHARSTRING(m[1].str().c_str()); + LibHttp__TypesAndValues::charstring__list v; + for (unsigned int j = 0; j < m.size(); j++) { + if (m[j + 2].str().length() == 0) { + break; + } + v[j] = CHARSTRING(m[j + 2].str().c_str()); + } // End of 'for' statement + header.header__value() = OPTIONAL(v); + + if ((m[1].str().compare("Content-Length") == 0) || (m[1].str().compare("content-length")) == 0) { + // Save the the body length + loggers::get_instance().log("http_codec::decode_header: decoded Content-Length %s", m[2].str().c_str()); + _dc.length = std::stoi(m[2].str()); + } else if ((m[1].str().compare("Transfer-Encoding") == 0) || (m[1].str().compare("transfer-encoding"))) { + if (m[2].str().find("chunked") != std::string::npos) { + _dc.chunked = true; + loggers::get_instance().log("http_codec::decode_header: decoded Transfer-Encoding %x", _dc.chunked); + } + } + + return 0; + } catch (const std::logic_error &e) { + return -1; + } +} + +int http_codec::encode_body(const LibHttp__MessageBodyTypes::HttpMessageBody &p_message_body, OCTETSTRING &p_encoding_buffer, + const std::string& p_content_type) { + loggers::get_instance().log_msg(">>> http_codec::encode_body: ", (const Base_Type &)p_message_body); + + // Sanity check + if (p_content_type.empty()) { + loggers::get_instance().warning("http_codec::encode_body: Failed to select a codec for HTTP body payload"); + return -1; + } + + if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_binary__body)) { + const LibHttp__BinaryMessageBodyTypes::BinaryBody &binary_body = p_message_body.binary__body(); + if (binary_body.ischosen(LibHttp__BinaryMessageBodyTypes::BinaryBody::ALT_raw)) { + p_encoding_buffer = OCTETSTRING(binary_body.raw().lengthof(), (unsigned char *)static_cast(binary_body.raw())); + } else { + encode_body_binary(binary_body, p_encoding_buffer, p_content_type); + } + } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_json__body)) { + const LibHttp__JsonMessageBodyTypes::JsonBody& json_body = p_message_body.json__body(); + if (json_body.ischosen(LibHttp__JsonMessageBodyTypes::JsonBody::ALT_raw)) { + p_encoding_buffer = unichar2oct(json_body.raw()); + } else { + encode_body_json(json_body, p_encoding_buffer, p_content_type); + } + } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_xml__body)) { + const LibHttp__XmlMessageBodyTypes::XmlBody &xml_body = p_message_body.xml__body(); + if (xml_body.msg().ischosen(LibHttp__XmlMessageBodyTypes::XmlBodyMsg::ALT_raw)) { + p_encoding_buffer = OCTETSTRING(xml_body.msg().raw().lengthof(), (unsigned char *)static_cast(xml_body.msg().raw())); + } else { + encode_body_xml(xml_body, p_encoding_buffer, p_content_type); + } + } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_html__body)) { + p_encoding_buffer = OCTETSTRING(p_message_body.html__body().lengthof(), (unsigned char *)static_cast(p_message_body.html__body())); + } else if (p_message_body.ischosen(LibHttp__MessageBodyTypes::HttpMessageBody::ALT_text__body)) { + p_encoding_buffer = OCTETSTRING(p_message_body.text__body().lengthof(), (unsigned char *)static_cast(p_message_body.text__body())); + } else { + loggers::get_instance().warning("http_codec::encode_body: Failed to encode HTTP message body"); + return -1; + } + loggers::get_instance().log_msg("http_codec::encode_body: HTTP message ", p_encoding_buffer); + _ec.length = p_encoding_buffer.lengthof(); + loggers::get_instance().log("http_codec::encode_body: HTTP message length: %d", _ec.length); + + return 0; +} + +int http_codec::decode_body(TTCN_Buffer &decoding_buffer, LibHttp__MessageBodyTypes::HttpMessageBody &message_body, const std::string& p_content_type) { + loggers::get_instance().log(">>> http_codec::decode_body"); + loggers::get_instance().log_to_hexa("http_codec::decode_body", decoding_buffer); + loggers::get_instance().log("http_codec::decode_body: # of codecs=%d - %p", _codecs.size(), this); + loggers::get_instance().log("http_codec::decode_body: Content-Type=%s", p_content_type.c_str()); + + // Sanity checks + if (decoding_buffer.get_len() - decoding_buffer.get_pos() <= 0) { + return -1; + } + /* TODO Uncomment if (p_content_type.empty()) { + loggers::get_instance().warning("http_codec::encode_body: Failed to select a codec for HTTP body payload"); + return -1; + }*/ + + OCTETSTRING s(decoding_buffer.get_len() - decoding_buffer.get_pos(), decoding_buffer.get_data() + decoding_buffer.get_pos()); + loggers::get_instance().log_msg("http_codec::decode_body: raw body=", s); + + // Align the payload length with the specified Content-Lenght value + loggers::get_instance().log("http_codec::decode_body: _dc.length=%d - body length=%d", _dc.length, s.lengthof()); + OCTETSTRING body; + if (_dc.length != 0) { + const unsigned char *p = static_cast(s); + if ((unsigned int)s.lengthof() <= _dc.length) { + body = OCTETSTRING(s.lengthof(), p); + } else { + body = OCTETSTRING(_dc.length, p); + } + } else { + loggers::get_instance().warning("http_codec::decode_body: No Conten-Length header, process all remaining bytes"); + body = s; + } + loggers::get_instance().log_msg("http_codec::decode_body: Aligned body=", body); + loggers::get_instance().log("http_codec::decode_body: body length=%d", body.lengthof()); + /* TODO To be removed + // Remove CRLF if any + int counter = 0; + if ((body[body.lengthof() - 1].get_octet() == 0x0d) || (body[body.lengthof() - 1].get_octet() == 0x0a)) { + counter += 1; + if ((body[body.lengthof() - 2].get_octet() == 0x0d) || (body[body.lengthof() - 2].get_octet() == 0x0a)) { + counter += 1; + } + } + loggers::get_instance().log("http_codec::decode_body: counter=%d", counter); + body = OCTETSTRING(body.lengthof() - counter, static_cast(body)); + */ + if (_dc.chunked) { + int counter = 0; + int prev = 0; + OCTETSTRING os(0, nullptr); + do { + while (counter < body.lengthof()) { // Extract the size of the chunk \r[\n] + if ((body[counter].get_octet() == '\r') || (body[counter].get_octet() == '\n')) { + break; + } + counter += 1; + } // End of 'while' statement + loggers::get_instance().log("http_codec::decode_body: Chunked(0): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); + if (counter < body.lengthof()) { + int idx = counter - prev; + OCTETSTRING trunk(idx, static_cast(body)); + loggers::get_instance().log_msg("http_codec::decode_body: trunk: ", trunk); + std::string str((const char *)static_cast(trunk), idx); + loggers::get_instance().log("http_codec::decode_body: str: '%s'", str.c_str()); + int len = std::stoi(str, nullptr, 16); // converter::get_instance().string_to_int(str); + loggers::get_instance().log("http_codec::decode_body: Chunk len: %d", len); + while (counter < body.lengthof() && ((body[counter].get_octet() == '\r') || (body[counter].get_octet() == '\n'))) { // Skip additional \n + counter += 1; + } // End of 'while' statement + if (counter < body.lengthof()) { + loggers::get_instance().log("http_codec::decode_body: Chunked (1): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); + os += OCTETSTRING(len, counter + static_cast(body)); + loggers::get_instance().log_msg("http_codec::decode_body: os=", os); + counter += len; + loggers::get_instance().log("http_codec::decode_body: Chunked: %02x %02x %02x", body[counter].get_octet(), body[counter + 1].get_octet(), + body[counter + 2].get_octet()); + loggers::get_instance().log("http_codec::decode_body: Chunked (2): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); + while (counter < body.lengthof() && ((body[counter].get_octet() == '\r') || (body[counter].get_octet() == '\n'))) { // Skip additional \n + counter += 1; + } // End of 'while' statement + prev = counter; + loggers::get_instance().log("http_codec::decode_body: Chunked (3): prev = %d, counter=%d / %d", prev, counter, body.lengthof()); + } + } + } while (counter < body.lengthof()); // Process next chunk if any + body = os; + loggers::get_instance().log_msg("http_codec::decode_body: Finalised body=", body); + } + // Check if HTTP message body contains binary characters + for (int i = 0; i < body.lengthof(); i++) { + unsigned char c = body[i].get_octet(); + if (!std::isprint(c) && !std::isspace(c) && !std::ispunct(c)) { + loggers::get_instance().log("http_codec::decode_body: Byte #%d is not printable: 0x%02x", i, body[i].get_octet()); + _dc.is_binary = 0x01; + break; + } + } // End of 'for' statement + loggers::get_instance().log("http_codec::decode_body: Binary mode: %x", _dc.is_binary); + LibHttp__MessageBodyTypes::HttpMessageBody v; + if (_dc.is_binary == 0x01) { + LibHttp__BinaryMessageBodyTypes::BinaryBody binary_body; + decode_body_binary(body, binary_body, p_content_type); + message_body.binary__body() = binary_body; + } else { + // Convert into string + params p; + p["decode_str"] = std::string(static_cast(body), body.lengthof() + static_cast(body)); + loggers::get_instance().log("http_codec::decode_body: decode_str: '%s'", p["decode_str"].c_str()); + // Try to identify xml + if (p["decode_str"].find("") != std::string::npos) { // Try to identify HTML + loggers::get_instance().log("http_codec::decode_body: Find html message"); + LibHttp__MessageBodyTypes::HtmlBody html_body; + decode_body_html(body, html_body, p_content_type, &p); + message_body.html__body() = html_body; + } else if (p_content_type.find("json") != std::string::npos) { // Try to identify JSON + loggers::get_instance().log("http_codec::decode_body: Find json message"); + LibHttp__JsonMessageBodyTypes::JsonBody json_body; + decode_body_json(body, json_body, p_content_type, &p); + message_body.json__body() = json_body; + } else { + loggers::get_instance().log("http_codec::decode_body: Use textBody as default"); + LibHttp__MessageBodyTypes::TextBody text_body; + message_body.text__body() = CHARSTRING(body.lengthof(), (char *)static_cast(body)); + } + } + + return 0; +} + +int http_codec::get_line(TTCN_Buffer &buffer, CHARSTRING &to, const bool concatenate_header_lines) { + unsigned int i = 0; + const unsigned char *cc_to = buffer.get_read_data(); + + // Sanity checks + if (buffer.get_read_len() == 0) { + return -1; + } + + while (true) { + // Skip spaces, and empty lines + for (; i < buffer.get_read_len() && cc_to[i] != '\0' && cc_to[i] != '\r' && cc_to[i] != '\n'; i++) + ; + if (i >= buffer.get_read_len()) { // No more characters to process + to = CHARSTRING(""); + return -1; + } else if (cc_to[i] == '\n') { // New line found, we don't care is '\r' is missing + if ((i > 0) && ((i + 1) < buffer.get_read_len()) && concatenate_header_lines && ((cc_to[i + 1] == ' ') || (cc_to[i + 1] == '\t'))) { + i += 1; // Skip it + } else { + to = CHARSTRING(i, (const char *)cc_to); + buffer.set_pos(buffer.get_pos() + i + 1); + return i == 0 ? 1 : 0; + } + } else { + if ((i + 1) < buffer.get_read_len() && cc_to[i + 1] != '\n') { + return -1; + } else if (i > 0 && (i + 2) < buffer.get_read_len() && concatenate_header_lines && (cc_to[i + 2] == ' ' || cc_to[i + 2] == '\t')) { + i += 2; + } else { + to = CHARSTRING(i, (const char *)cc_to); + buffer.set_pos(buffer.get_pos() + i + 2); + return i == 0 ? 1 : 0; + } + } + } // End of 'while' statement +} + +void http_codec::set_payload_codecs(const std::string& p_codecs) { + loggers::get_instance().log(">>> http_codec::set_payload_codecs: '%s'", p_codecs.c_str()); + + // Sanity check + if (p_codecs.length() == 0) { + return; + } + + // Extract codecs + try { + std::regex rgx("(\\w+):(\\w+)(;(\\w+):(\\w+))*"); + std::sregex_iterator begin(p_codecs.cbegin(), p_codecs.cend(), rgx); + std::sregex_iterator end = std::sregex_iterator(); + // E.g. 9 - xml - :held_codec - held_codec - ;html:html_codec - html:html_codec - html - :html_codec - html_codec + for (std::sregex_iterator it = begin; it != end; ++it) { + std::smatch m = *it; + loggers::get_instance().log("http_codec::set_payload_codecs: %d - %s - %s - %s - %s - %s - %s - %s - %s", m.size(), m[1].str().c_str(), + m[2].str().c_str(), m[3].str().c_str(), m[4].str().c_str(), m[5].str().c_str(), m[6].str().c_str(), m[7].str().c_str(), + m[8].str().c_str()); + for (unsigned int j = 1; j < m.size() - 1; j += 3) { // Exclude m[0] + loggers::get_instance().log("http_codec::set_payload_codecs: insert (%s, %s), j = %d", m[j].str().c_str(), m[j + 1].str().c_str(), j); + if (m[j].str().empty()) { + break; + } + std::string key(m[j].str()); + loggers::get_instance().log("http_codec::set_payload_codecs: Add codec %s", key.c_str()); + _codecs.insert( + std::make_pair(key, std::unique_ptr>(codec_stack_builder::get_instance()->get_codec(m[j + 1].str().c_str())))); + } // End of 'for' statement + } // End of 'for' statement + loggers::get_instance().log("http_codec::set_payload_codecs: _codecs length=%d - %p", _codecs.size(), this); + } catch (const std::logic_error &e) { + loggers::get_instance().warning("http_codec::set_payload_codecs: std::logic_error: '%s'", e.what()); + _codecs.clear(); + } +} + +bool http_codec::decode_body_html(const OCTETSTRING &p_data, CHARSTRING &p_html_body, const std::string& p_content_type, params* p_params) { + p_html_body = CHARSTRING(p_data.lengthof(), (char*)static_cast(p_data)); + return true; +} diff --git a/ccsrc/Protocols/Http/http_codec.hh b/ccsrc/Protocols/Http/http_codec.hh index efcebe2ab78c5f981221ea9d9592f0372e4acb00..37f313cc9c3fccfe4e6e2544d6dc3953c509b2a1 100644 --- a/ccsrc/Protocols/Http/http_codec.hh +++ b/ccsrc/Protocols/Http/http_codec.hh @@ -9,6 +9,7 @@ class Base_Type; class Record_Type; class TTCN_Typedescriptor_t; class TTCN_Buffer; +class OCTETSTRING; namespace LibHttp__TypesAndValues { class HttpMessage; @@ -60,37 +61,40 @@ class http_codec : public codec_gen>> _codecs; + std::vector _bufferized_buffers; + unsigned int _initial_content_length; + unsigned int _current_content_length; public: - explicit http_codec() : codec_gen(), _ec(), _dc(), _codecs(){}; + explicit http_codec() : codec_gen(), _ec(), _dc(), _codecs(), _bufferized_buffers(), _initial_content_length{0}, _current_content_length{0} {}; virtual ~http_codec(){}; virtual int encode(const LibHttp__TypesAndValues::HttpMessage &, OCTETSTRING &data); virtual int decode(const OCTETSTRING &data, LibHttp__TypesAndValues::HttpMessage &, params *params = NULL); - void set_payload_codecs(const std::string &p_codecs); + void set_payload_codecs(const std::string& p_codecs); protected: //! \protectedsection - virtual bool encode_body_binary(const LibHttp__BinaryMessageBodyTypes::BinaryBody &p_binary_body, OCTETSTRING &p_encoding_buffer, const std::string &p_content_type) {return false;}; - virtual bool decode_body_binary(const OCTETSTRING &p_data, LibHttp__BinaryMessageBodyTypes::BinaryBody &p_binary_body, const std::string &p_content_type) {return false;}; + virtual bool encode_body_binary(const LibHttp__BinaryMessageBodyTypes::BinaryBody &p_binary_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;}; + virtual bool decode_body_binary(const OCTETSTRING &p_data, LibHttp__BinaryMessageBodyTypes::BinaryBody &p_binary_body, const std::string& p_content_type) {return false;}; - virtual bool encode_body_xml(const LibHttp__XmlMessageBodyTypes::XmlBody &p_xml_body, OCTETSTRING &p_encoding_buffer, const std::string &p_content_type) {return false;}; - virtual bool decode_body_xml(const OCTETSTRING &p_data, LibHttp__XmlMessageBodyTypes::XmlBody &p_body, const std::string &p_content_type, params* p_params) {return false;}; + virtual bool encode_body_xml(const LibHttp__XmlMessageBodyTypes::XmlBody &p_xml_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;}; + virtual bool decode_body_xml(const OCTETSTRING &p_data, LibHttp__XmlMessageBodyTypes::XmlBody &p_body, const std::string& p_content_type, params* p_params) {return false;}; - virtual bool encode_body_html(const CHARSTRING &p_html_body, OCTETSTRING &p_encoding_buffer, const std::string &p_content_type) {return false;}; - virtual bool decode_body_html(const OCTETSTRING &p_data, CHARSTRING &p_html_body, const std::string &p_content_type, params* p_params); + virtual bool encode_body_html(const CHARSTRING &p_html_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;}; + virtual bool decode_body_html(const OCTETSTRING &p_data, CHARSTRING &p_html_body, const std::string& p_content_type, params* p_params); - virtual bool encode_body_json(const LibHttp__JsonMessageBodyTypes::JsonBody &p_json_body, OCTETSTRING &p_encoding_buffer, const std::string &p_content_type) {return false;}; - virtual bool decode_body_json(const OCTETSTRING &p_data, LibHttp__JsonMessageBodyTypes::JsonBody &p_json_body, const std::string &p_content_type, params* p_params) {return false;}; + virtual bool encode_body_json(const LibHttp__JsonMessageBodyTypes::JsonBody &p_json_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type) {return false;}; + virtual bool decode_body_json(const OCTETSTRING &p_data, LibHttp__JsonMessageBodyTypes::JsonBody &p_json_body, const std::string& p_content_type, params* p_params) {return false;}; private: int encode_request(const LibHttp__TypesAndValues::Request &p_request, TTCN_Buffer &p_encoding_buffer); int encode_response(const LibHttp__TypesAndValues::Response &p_response, TTCN_Buffer &p_encoding_buffer); - int encode_body(const LibHttp__MessageBodyTypes::HttpMessageBody &p_message_body, OCTETSTRING &p_encoding_buffer, const std::string &p_content_type); + int encode_body(const LibHttp__MessageBodyTypes::HttpMessageBody &p_message_body, OCTETSTRING &p_encoding_buffer, const std::string& p_content_type); - int decode_headers(TTCN_Buffer &decoding_buffer, LibHttp__TypesAndValues::Headers &headers, std::string &p_content_type); + int decode_headers(TTCN_Buffer &decoding_buffer, LibHttp__TypesAndValues::Headers &headers, std::string& p_content_type); int decode_header(CHARSTRING &header_line, LibHttp__TypesAndValues::Header &header); - int decode_body(TTCN_Buffer &decoding_buffer, LibHttp__MessageBodyTypes::HttpMessageBody &message_body, const std::string &p_content_type); + int decode_body(TTCN_Buffer &decoding_buffer, LibHttp__MessageBodyTypes::HttpMessageBody &message_body, const std::string& p_content_type); int get_line(TTCN_Buffer &buffer, CHARSTRING &to, const bool concatenate_header_lines = false); }; // End of class http_codec diff --git a/ccsrc/Protocols/Http/http_layer.cc b/ccsrc/Protocols/Http/http_layer.cc index 451c7d6cf997876baa8115f07175e5dd6516662b..8d83cbc02d4d0adb75ea78486c932e1497081e6b 100644 --- a/ccsrc/Protocols/Http/http_layer.cc +++ b/ccsrc/Protocols/Http/http_layer.cc @@ -11,9 +11,9 @@ using namespace std; // Required for isnan() #include "LibHttp_TestSystem.hh" #include "LibHttp_TypesAndValues.hh" -http_layer::http_layer(const std::string &p_type, const std::string ¶m) +http_layer::http_layer(const std::string& p_type, const std::string& param) : t_layer(p_type), _params(), _codec(nullptr), _device_mode{false} { - loggers::get_instance().log(">>> http_layer::http_layer: %s, %s", to_string().c_str(), param.c_str()); + loggers::get_instance().log(">>> http_layer::http_layer: '%s', %s", to_string().c_str(), param.c_str()); // Setup parameters params::convert(_params, param); @@ -95,9 +95,14 @@ void http_layer::receive_data(OCTETSTRING &data, params ¶ms) { // Decode HTTP message LibHttp__TypesAndValues::HttpMessage http_message; - if (_codec->decode(data, http_message, ¶ms) == -1) { + int ret_code = _codec->decode(data, http_message, ¶ms); + if (ret_code == -1) { loggers::get_instance().warning("http_layer::receive_data: Failed to decode data"); return; + } else if (ret_code == -2) { // Need to wait for next data + loggers::get_instance().log("http_layer::receive_data: Set Buffurizing to 1"); + params.insert(std::make_pair("Buffurizing", "1")); + return; } if (_device_mode) { OCTETSTRING os; diff --git a/ccsrc/Protocols/Http/http_layer_factory.hh b/ccsrc/Protocols/Http/http_layer_factory.hh index 5e4e71abbc84e6265a19065017126e5f6b997a32..5668e87c8205a3d7ba5c20b97f5a21c13d573e0e 100644 --- a/ccsrc/Protocols/Http/http_layer_factory.hh +++ b/ccsrc/Protocols/Http/http_layer_factory.hh @@ -31,12 +31,12 @@ public: //! \publicsection layer_stack_builder::register_layer_factory("HTTP", this); }; /*! - * \fn layer* create_layer(const std::string & type, const std::string & param); + * \fn layer* create_layer(const std::string& type, const std::string& param); * \brief Create the layers stack based on the provided layers stack description * \param[in] p_type The provided layers stack description * \param[in] p_params Optional parameters * \return 0 on success, -1 otherwise * \inline */ - inline virtual layer *create_layer(const std::string &p_type, const std::string &p_param) { return new http_layer(p_type, p_param); }; + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new http_layer(p_type, p_param); }; }; // End of class http_layer_factory diff --git a/ccsrc/Protocols/Pcap/pcap_cygwin_layer.cc b/ccsrc/Protocols/Pcap/pcap_cygwin_layer.cc index 56f9bbc9dee95c905693ff0c45f93947f1c64527..dca0cfab7cf07580dbd4ff3c0f9f8b02dcb213f6 100644 --- a/ccsrc/Protocols/Pcap/pcap_cygwin_layer.cc +++ b/ccsrc/Protocols/Pcap/pcap_cygwin_layer.cc @@ -52,9 +52,9 @@ static char * _bin2hex(char *hex, size_t hlen, const char *bin, size_t blen return hex + blen * 2; } -pcap_layer::pcap_layer(const std::string &p_type, const std::string ¶m) +pcap_layer::pcap_layer(const std::string& p_type, const std::string& param) : layer(p_type), PORT(p_type.c_str()), _params(), _device(NULL), _running(FALSE), _time_key("pcap_layer::Handle_Fd_Event_Readable") { - loggers::get_instance().log(">>> pcap_layer::pcap_layer: %s, %s", p_type.c_str(), param.c_str()); + loggers::get_instance().log(">>> pcap_layer::pcap_layer: '%s', %s", p_type.c_str(), param.c_str()); params::convert(_params, param); char error_buffer[PCAP_ERRBUF_SIZE]; @@ -128,7 +128,7 @@ pcap_layer::pcap_layer(const std::string &p_type, const std::string ¶m) } // Log final PCAP filter - loggers::get_instance().user("pcap_layer::pcap_layer: Filter: %s", filter.c_str()); + loggers::get_instance().user("pcap_layer::pcap_layer: Filter: '%s'", filter.c_str()); // setup filter { @@ -147,7 +147,7 @@ pcap_layer::pcap_layer(const std::string &p_type, const std::string ¶m) // create pipe and run thread if (pipe2(_fd, O_NONBLOCK) == -1) { - loggers::get_instance().error("pcap_layer::pcap_layer: Failed to create a pipe: %s", ::strerror(errno)); + loggers::get_instance().error("pcap_layer::pcap_layer: Failed to create a pipe: '%s'", ::strerror(errno)); } // Pass the pipe handler to the polling procedure loggers::get_instance().log("pcap_layer::pcap_layer: Call handler with descriptor %d", _fd[0]); @@ -238,7 +238,7 @@ void *pcap_layer::thread() { void pcap_layer::send_data(OCTETSTRING &data, params ¶ms) { loggers::get_instance().log_msg(">>> pcap_layer::send_data: ", data); if (pcap_sendpacket(_device, static_cast(data), data.lengthof()) == -1) { - loggers::get_instance().error("pcap_layer::send_data: Failed to send packet: %s", pcap_geterr(_device)); + loggers::get_instance().error("pcap_layer::send_data: Failed to send packet: '%s'", pcap_geterr(_device)); } } diff --git a/ccsrc/Protocols/Pcap/pcap_cygwin_layer.hh b/ccsrc/Protocols/Pcap/pcap_cygwin_layer.hh index d7d477a871c179fba588758188722f63e8bf1712..b54cedabd95c23e0675723d353cd44235bfd0bb3 100644 --- a/ccsrc/Protocols/Pcap/pcap_cygwin_layer.hh +++ b/ccsrc/Protocols/Pcap/pcap_cygwin_layer.hh @@ -52,7 +52,7 @@ public: //! \publicsection * \param[in] p_type \todo * \param[in] p_param \todo */ - pcap_layer(const std::string &p_type, const std::string ¶m); + pcap_layer(const std::string& p_type, const std::string& param); /*! * \brief Default destructor */ diff --git a/ccsrc/Protocols/Pcap/pcap_layer.cc b/ccsrc/Protocols/Pcap/pcap_layer.cc index 8313c9f3018f9e44df87985ecb6f27cb970f9c07..94f7e8b65b4e587082eaf47dbad5726e440a80db 100644 --- a/ccsrc/Protocols/Pcap/pcap_layer.cc +++ b/ccsrc/Protocols/Pcap/pcap_layer.cc @@ -16,7 +16,7 @@ typedef struct timeval pcap_o_timeval; pcap_layer::pcap_layer(const std::string& p_type, const std::string& param) : layer(p_type), PORT(p_type.c_str()), _params(), _device(NULL), _pcap_h(-1), _thread(NULL), _running(FALSE), _resume(), _sent_file(NULL), _time_key("pcap_layer::Handle_Fd_Event_Readable") { bool online = false; - loggers::get_instance().log(">>> pcap_layer::pcap_layer: %s, %s", to_string().c_str(), param.c_str()); + loggers::get_instance().log(">>> pcap_layer::pcap_layer: '%s', %s", to_string().c_str(), param.c_str()); _fd[0] = -1; _fd[1] = -1; // Setup parameters params::convert(_params, param); @@ -42,7 +42,7 @@ pcap_layer::pcap_layer(const std::string& p_type, const std::string& param) : la } // else, continue // Set non-blocking flag for the polling procedure if (pcap_setnonblock(_device, 1, error_buffer) != 0) { - loggers::get_instance().error("pcap_layer::pcap_layer: Failed to set blocking mode: %s", error_buffer); + loggers::get_instance().error("pcap_layer::pcap_layer: Failed to set blocking mode: '%s'", error_buffer); } // Retrieve the device file handler _pcap_h = pcap_get_selectable_fd(_device); @@ -70,7 +70,7 @@ pcap_layer::pcap_layer(const std::string& p_type, const std::string& param) : la int i = _params["file"].find(".pcap"); if (i > 0) { std::string f(_params["file"].substr(0, i) + ext + ".pcap"); - loggers::get_instance().log("pcap_layer::pcap_layer: Save file name: %s", f.c_str()); + loggers::get_instance().log("pcap_layer::pcap_layer: Save file name: '%s'", f.c_str()); if ((_sent_file = pcap_dump_open(_device, f.c_str())) == NULL) { loggers::get_instance().warning("pcap_layer::pcap_layer: Failed to open save file %s", f.c_str()); } @@ -105,7 +105,7 @@ pcap_layer::pcap_layer(const std::string& p_type, const std::string& param) : la } // else nothing to do } // Log final PCAP filter - loggers::get_instance().user("pcap_layer::pcap_layer: Filter: %s", filter.c_str()); + loggers::get_instance().user("pcap_layer::pcap_layer: Filter: '%s'", filter.c_str()); if (!filter.empty()) { struct bpf_program f = {0}; if (pcap_compile(_device, &f, filter.c_str(), 1, PCAP_NETMASK_UNKNOWN) != 0) { @@ -123,7 +123,7 @@ pcap_layer::pcap_layer(const std::string& p_type, const std::string& param) : la } else { // Offline capture or cygwin // Create a pipe if (pipe2(_fd, O_NONBLOCK) == -1) { - loggers::get_instance().error("pcap_layer::pcap_layer: Failed to create a pipe: %s", ::strerror(errno)); + loggers::get_instance().error("pcap_layer::pcap_layer: Failed to create a pipe: '%s'", ::strerror(errno)); } if(online){ _pcap_h = _fd[0]; @@ -212,7 +212,7 @@ void pcap_layer::send_data(OCTETSTRING& data, params& params) { if (_pcap_h != -1) { // Check if offline mode is used if (pcap_sendpacket(_device, static_cast(data), data.lengthof()) == -1) { - loggers::get_instance().error("pcap_layer::send_data: Failed to send packet: %s", pcap_geterr(_device)); + loggers::get_instance().error("pcap_layer::send_data: Failed to send packet: '%s'", pcap_geterr(_device)); } } else if (_sent_file != NULL) { struct pcap_pkthdr hdr; diff --git a/ccsrc/Protocols/Pcap/pcap_layer_factory.hh b/ccsrc/Protocols/Pcap/pcap_layer_factory.hh index 0125e1946cb3359295bac349039fef518c70ce52..79f2b6d1a5792b6401448c0448803b446f41e709 100644 --- a/ccsrc/Protocols/Pcap/pcap_layer_factory.hh +++ b/ccsrc/Protocols/Pcap/pcap_layer_factory.hh @@ -31,12 +31,12 @@ public: //! \publicsection layer_stack_builder::register_layer_factory("PCAP", this); }; /*! - * \fn layer* create_layer(const std::string & type, const std::string & param); + * \fn layer* create_layer(const std::string& type, const std::string& param); * \brief Create the layers stack based on the provided layers stack description * \param[in] p_type The provided layers stack description * \param[in] p_params Optional parameters * \return 0 on success, -1 otherwise * \inline */ - inline virtual layer *create_layer(const std::string &p_type, const std::string &p_param) { return new pcap_layer(p_type, p_param); }; + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new pcap_layer(p_type, p_param); }; }; // End of class pcap_layer_factory diff --git a/ccsrc/Protocols/Pcap/pcap_linux_layer.cc b/ccsrc/Protocols/Pcap/pcap_linux_layer.cc index fecb2b34c78e683e9939fe1c6e5744cc029b99ca..27ce633d9d040a21730d4855b48338de7205a042 100644 --- a/ccsrc/Protocols/Pcap/pcap_linux_layer.cc +++ b/ccsrc/Protocols/Pcap/pcap_linux_layer.cc @@ -36,13 +36,13 @@ static char * _bin2hex(char *hex, size_t hlen, const char *bin, size_t blen return hex + blen * 2; } -pcap_layer::pcap_layer(const std::string &p_type, const std::string ¶m) +pcap_layer::pcap_layer(const std::string& p_type, const std::string& param) : layer(p_type), PORT(p_type.c_str()), _params(), _device(NULL), _pcap_h(-1), _time_key("pcap_layer::Handle_Fd_Event_Readable") { char error_buffer[PCAP_ERRBUF_SIZE]; params::const_iterator it; std::string nic; - loggers::get_instance().log(">>> pcap_layer::pcap_layer: %s, %s", to_string().c_str(), param.c_str()); + loggers::get_instance().log(">>> pcap_layer::pcap_layer: '%s', %s", to_string().c_str(), param.c_str()); // Setup parameters params::convert(_params, param); // Prepare capture processing @@ -69,7 +69,7 @@ pcap_layer::pcap_layer(const std::string &p_type, const std::string ¶m) } // else, continue // Set non-blocking flag for the polling procedure if (pcap_setnonblock(_device, 1, error_buffer) != 0) { - loggers::get_instance().error("pcap_layer::pcap_layer: Failed to set blocking mode: %s", error_buffer); + loggers::get_instance().error("pcap_layer::pcap_layer: Failed to set blocking mode: '%s'", error_buffer); } // Retrieve the device file handler _pcap_h = pcap_get_selectable_fd(_device); @@ -125,7 +125,7 @@ pcap_layer::pcap_layer(const std::string &p_type, const std::string ¶m) filter += std::string(" ") + it->second; } // Log final PCAP filter - loggers::get_instance().user("pcap_layer::pcap_layer: Filter: %s", filter.c_str()); + loggers::get_instance().user("pcap_layer::pcap_layer: Filter: '%s'", filter.c_str()); { struct bpf_program f = {0}; @@ -155,7 +155,7 @@ void pcap_layer::send_data(OCTETSTRING &data, params ¶ms) { loggers::get_instance().log_msg(">>> pcap_layer::send_data: ", data); if (pcap_sendpacket(_device, static_cast(data), data.lengthof()) == -1) { - loggers::get_instance().error("pcap_layer::send_data: Failed to send packet: %s", pcap_geterr(_device)); + loggers::get_instance().error("pcap_layer::send_data: Failed to send packet: '%s'", pcap_geterr(_device)); } } diff --git a/ccsrc/Protocols/Pcap/pcap_linux_layer.hh b/ccsrc/Protocols/Pcap/pcap_linux_layer.hh index 82efc4b5857fd29cb944cdbcc775f98719ec3570..90c45dd7c8b32b32d2554755001002175093cb80 100644 --- a/ccsrc/Protocols/Pcap/pcap_linux_layer.hh +++ b/ccsrc/Protocols/Pcap/pcap_linux_layer.hh @@ -35,7 +35,7 @@ public: //! \publicsection * \param[in] p_type \todo * \param[in] p_param \todo */ - pcap_layer(const std::string &p_type, const std::string ¶m); + pcap_layer(const std::string& p_type, const std::string& param); /*! * \brief Default destructor */ diff --git a/ccsrc/Protocols/Pcap/pcap_offline_layer.cc b/ccsrc/Protocols/Pcap/pcap_offline_layer.cc index d8afc3a19c4415a02065eb8cf146bee1f8bc2911..0f8808c5ad138fa6fe8a509752c81f37e0ba92d2 100644 --- a/ccsrc/Protocols/Pcap/pcap_offline_layer.cc +++ b/ccsrc/Protocols/Pcap/pcap_offline_layer.cc @@ -31,9 +31,9 @@ typedef struct pcap_pkthdr pcap_o_pkthdr; typedef struct timeval pcap_o_timeval; #endif -pcap_offline_layer::pcap_offline_layer(const std::string &p_type, const std::string ¶m) +pcap_offline_layer::pcap_offline_layer(const std::string& p_type, const std::string& param) : layer(p_type), PORT(p_type.c_str()), _params(), _device(NULL), _running(FALSE), _time_key("pcap_offline_layer::Handle_Fd_Event_Readable") { - loggers::get_instance().log(">>> pcap_offline_layer::pcap_offline_layer: %s, %s", p_type.c_str(), param.c_str()); + loggers::get_instance().log(">>> pcap_offline_layer::pcap_offline_layer: '%s', %s", p_type.c_str(), param.c_str()); params::convert(_params, param); _o_params.insert(std::pair(std::string("timestamp"), std::string())); @@ -49,16 +49,16 @@ pcap_offline_layer::pcap_offline_layer(const std::string &p_type, const std::str it = _params.find(std::string("file")); if ((it != _params.end()) && !it->second.empty()) { - const std::string &file = it->second; + const std::string& file = it->second; _device = pcap_open_offline(file.c_str(), error_buffer); if (_device) { // Add user defined filter it = _params.find(params::filter); if ((it != _params.end()) && !it->second.empty()) { - const std::string &filter = it->second; + const std::string& filter = it->second; // Log final PCAP filter - loggers::get_instance().user("pcap_offline_layer::pcap_offline_layer: Filter: %s", filter.c_str()); + loggers::get_instance().user("pcap_offline_layer::pcap_offline_layer: Filter: '%s'", filter.c_str()); struct bpf_program f = {0}; if (pcap_compile(_device, &f, filter.c_str(), 1, PCAP_NETMASK_UNKNOWN) != 0) { loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to compile PCAP filter"); @@ -72,7 +72,7 @@ pcap_offline_layer::pcap_offline_layer(const std::string &p_type, const std::str // create pipe and run thread if (pipe2(_fd, O_NONBLOCK) == -1) { - loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to create a pipe: %s", ::strerror(errno)); + loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to create a pipe: '%s'", ::strerror(errno)); } // Pass the pipe handler to the polling procedure loggers::get_instance().log("pcap_offline_layer::pcap_offline_layer: Call handler with descriptor %d", _fd[0]); diff --git a/ccsrc/Protocols/Pcap/pcap_offline_layer.hh b/ccsrc/Protocols/Pcap/pcap_offline_layer.hh index 0c1993e4118aef4c6977bcde7896f2d1efdfaa63..f4abd9485e468e2c05d1f957eaabd9904fb94a5f 100644 --- a/ccsrc/Protocols/Pcap/pcap_offline_layer.hh +++ b/ccsrc/Protocols/Pcap/pcap_offline_layer.hh @@ -53,7 +53,7 @@ public: //! \publicsection * \param[in] p_type \todo * \param[in] p_param \todo */ - pcap_offline_layer(const std::string &p_type, const std::string ¶m); + pcap_offline_layer(const std::string& p_type, const std::string& param); /*! * \brief Default destructor */ diff --git a/ccsrc/Protocols/Pcap/pcap_offline_layer_factory.hh b/ccsrc/Protocols/Pcap/pcap_offline_layer_factory.hh index 23cd1d0d28f84386a20a1bdb2b35a0716f010fc9..3c3d6659d1f72da2d1d0312d6a1c6f7d63f3ecd0 100644 --- a/ccsrc/Protocols/Pcap/pcap_offline_layer_factory.hh +++ b/ccsrc/Protocols/Pcap/pcap_offline_layer_factory.hh @@ -31,12 +31,12 @@ public: //! \publicsection layer_stack_builder::register_layer_factory("PCAP_FILE", this); }; /*! - * \fn layer* create_layer(const std::string & type, const std::string & param); + * \fn layer* create_layer(const std::string& type, const std::string& param); * \brief Create the layers stack based on the provided layers stack description * \param[in] p_type The provided layers stack description * \param[in] p_params Optional parameters * \return 0 on success, -1 otherwise * \inline */ - inline virtual layer *create_layer(const std::string &p_type, const std::string &p_param) { return new pcap_offline_layer(p_type, p_param); }; + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new pcap_offline_layer(p_type, p_param); }; }; // End of class pcap_offline_layer_factory diff --git a/ccsrc/Protocols/Tcp/tcp_layer.cc b/ccsrc/Protocols/Tcp/tcp_layer.cc index e134867c554fae716ac54fb1563fb664f0206598..632ec3bd79f21f044a7fd24c250d85a6f45510af 100644 --- a/ccsrc/Protocols/Tcp/tcp_layer.cc +++ b/ccsrc/Protocols/Tcp/tcp_layer.cc @@ -8,16 +8,16 @@ #include "loggers.hh" -tcp_layer::tcp_layer(const std::string & p_type, const std::string & param) : layer(p_type), SSL_Socket(), PORT(p_type.c_str()), _params(), _client_id{-1}, _time_key("tcp_layer::Handle_Fd_Event_Readable"), _reconnect_on_send{false} { - loggers::get_instance().log(">>> tcp_layer::tcp_layer (1): %s, %s", to_string().c_str(), param.c_str()); +tcp_layer::tcp_layer(const std::string& p_type, const std::string& param) : layer(p_type), SSL_Socket(), PORT(p_type.c_str()), _params(), _client_id{-1}, _time_key("tcp_layer::Handle_Fd_Event_Readable"), _reconnect_on_send{false} { + loggers::get_instance().log(">>> tcp_layer::tcp_layer (1): '%s', %s", to_string().c_str(), param.c_str()); // Setup parameters params::convert(_params, param); _params.log(); init(); } -tcp_layer::tcp_layer(const std::string & p_type, const params & param) : layer(p_type), SSL_Socket(), PORT(p_type.c_str()), _params(), _client_id{-1}, _time_key("tcp_layer::Handle_Fd_Event_Readable"), _reconnect_on_send{false} { - loggers::get_instance().log(">>> tcp_layer::tcp_layer (2): %s", to_string().c_str()); +tcp_layer::tcp_layer(const std::string& p_type, const params & param) : layer(p_type), SSL_Socket(), PORT(p_type.c_str()), _params(), _client_id{-1}, _time_key("tcp_layer::Handle_Fd_Event_Readable"), _reconnect_on_send{false} { + loggers::get_instance().log(">>> tcp_layer::tcp_layer (2): '%s'", to_string().c_str()); // Setup parameters _params = param; @@ -37,6 +37,8 @@ void tcp_layer::init() { it = _params.find(std::string("tcp_fragmented")); if (it == _params.cend()) { _params.insert(std::pair(std::string("tcp_fragmented"), "0")); + } else { + _params.insert(std::pair(std::string("tcp_fragmented"), "1")); } bool server_mode = false; it = _params.find(params::server_mode); @@ -49,8 +51,8 @@ void tcp_layer::init() { if (it == _params.cend()) { _params.insert(std::pair(std::string("server"), "127.0.0.1")); // TODO Try using params::server instead of std::string("server") } - if (!parameter_set(params::server.c_str(), _params[params::server].c_str())) { - loggers::get_instance().warning("tcp_layer::set_parameter: Unprocessed parameter: %s", params::server.c_str()); + if (!parameter_set(remote_address_name(), _params[params::server].c_str())) { + loggers::get_instance().warning("tcp_layer::set_parameter: Unprocessed parameter: 'remote_address_name()'"); } bool ssl_mode = false; it = _params.find(params::use_ssl); @@ -70,7 +72,7 @@ void tcp_layer::init() { } } if (!parameter_set(remote_port_name(), _params[params::port].c_str())) { - loggers::get_instance().warning("tcp_layer::set_parameter: Unprocessed parameter: %s", params::port.c_str()); + loggers::get_instance().warning("tcp_layer::set_parameter: Unprocessed parameter: '%s'", params::port.c_str()); } it = _params.find(params::local_port); if (it == _params.cend()) { @@ -81,16 +83,25 @@ void tcp_layer::init() { } } if (!parameter_set(local_port_name(), _params[params::local_port].c_str())) { - loggers::get_instance().warning("tcp_layer::set_parameter: Unprocessed parameter: %s", params::local_port.c_str()); + loggers::get_instance().warning("tcp_layer::set_parameter: Unprocessed parameter: '%s'", params::local_port.c_str()); + } + + it = _params.find(params::local_server); + if (it == _params.cend()) { + _params.insert(std::pair(std::string("local_server"), "0.0.0.0")); + } + if (!parameter_set(local_address_name(), _params[params::local_server].c_str())) { + loggers::get_instance().warning("tcp_layer::set_parameter: Unprocessed parameter: '%s'", params::local_server.c_str()); } parameter_set(use_connection_ASPs_name(), (!server_mode) ? "yes" : "no"); - loggers::get_instance().warning("tcp_layer::set_parameter: Limit to one simultanneous accepted connection (server_backlog == 1"); + loggers::get_instance().warning("tcp_layer::set_parameter: Limit to one simultanneous accepted connection (server_backlog == 1)"); parameter_set(server_backlog_name(), "1"); // Limit to one simultanneous accepted connection loggers::get_instance().log("tcp_layer::init: server_mode=%x", server_mode); set_server_mode(server_mode); - if (server_mode) { - parameter_set("serverPort", _params[params::local_port].c_str()); + if (server_mode) { // Apply default values or specified ones + parameter_set(local_port_name(), _params[params::local_port].c_str()); + parameter_set(local_address_name(), _params[params::local_server].c_str()); } if (ssl_mode) { // Add certificate bundle // Check mutual authentication param @@ -108,20 +119,26 @@ void tcp_layer::init() { if (it != _params.cend()) { parameter_set(ssl_trustedCAlist_file_name(), it->second.c_str()); } else { - parameter_set(ssl_trustedCAlist_file_name(), "/home/yann/var/ssl/archive/yanngarcia.ddns.net/fullchain1.pem"); + // Use Let's Encrypt to generate your certificates + // https://manpages.ubuntu.com/manpages/impish/en/man1/certbot.1.html + loggers::get_instance().error("tcp_layer::set_parameter: Trusted CA list is required for TLS"); } // Set additional certificates it = _params.find(params::privkey); if (it != _params.cend()) { parameter_set(ssl_private_key_file_name(), it->second.c_str()); } else { - parameter_set(ssl_private_key_file_name(), "/home/yann/var/ssl/archive/yanngarcia.ddns.net/privkey1.pem"); + // Use Let's Encrypt to generate your certificates + // https://manpages.ubuntu.com/manpages/impish/en/man1/certbot.1.html + loggers::get_instance().error("tcp_layer::set_parameter: Certificate private key is required for TLS"); } it = _params.find(params::certificate); if (it != _params.cend()) { parameter_set(ssl_certificate_file_name(), it->second.c_str()); } else { - parameter_set(ssl_certificate_file_name(), "/home/yann/var/ssl/archive/yanngarcia.ddns.net/fullchain1.pem"); + // Use Let's Encrypt to generate your certificates + // https://manpages.ubuntu.com/manpages/impish/en/man1/certbot.1.html + loggers::get_instance().error("tcp_layer::set_parameter: Certificate is required for TLS"); } } set_ttcn_buffer_usercontrol(false); @@ -132,7 +149,7 @@ void tcp_layer::init() { parameter_set(client_TCP_reconnect_name(), "yes"); if (server_mode == 0) { - loggers::get_instance().log("tcp_layer::init: Establish connection: %s/%s", _params[params::server].c_str(), _params[params::port].c_str()); + loggers::get_instance().log("tcp_layer::init: Establish connection: '%s'/%s", _params[params::server].c_str(), _params[params::port].c_str()); open_client_connection(_params[params::server].c_str(), _params[params::port].c_str(), NULL, NULL); } } @@ -164,12 +181,12 @@ void tcp_layer::send_data(OCTETSTRING& data, params& params) { loggers::get_instance().log_msg(">>> tcp_layer::send_data: ", data); loggers::get_instance().log("tcp_layer::send_data: SSL mode: %x", get_ssl_use_ssl()); - loggers::get_instance().log("tcp_layer::send_data: server_mode: %s", _params[params::server_mode].c_str()); + loggers::get_instance().log("tcp_layer::send_data: server_mode: '%s'", _params[params::server_mode].c_str()); loggers::get_instance().log("tcp_layer::send_data: peer_list_get_nr_of_peers: %d", peer_list_get_nr_of_peers()); if ((_params[params::server_mode].compare("0") == 0) && (peer_list_get_nr_of_peers() == 0)) { // Reconnect (e.g. HTTP connection lost - loggers::get_instance().log("tcp_layer::send_data: Re-establish connection: %s/%s", _params[params::server].c_str(), _params[params::port].c_str()); + loggers::get_instance().log("tcp_layer::send_data: Re-establish connection: '%s'/%s", _params[params::server].c_str(), _params[params::port].c_str()); open_client_connection(_params[params::server].c_str(), _params[params::port].c_str(), NULL, NULL); } send_outgoing(static_cast(data), data.lengthof(), _client_id); @@ -193,6 +210,10 @@ void tcp_layer::message_incoming(const unsigned char* message_buffer, int length std::string("timestamp"), std::to_string(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()))); this->receive_data(data, params); // TODO Check execution time for decoding operation + params::const_iterator it = params.find(std::string("Buffurizing")); + if (it != params.end()) { + loggers::get_instance().log("tcp_layer::message_incoming: Buffurizing requested"); + } loggers::get_instance().set_stop_time(_time_key, duration); } @@ -251,7 +272,7 @@ int tcp_layer::receive_message_on_fd(int p_client_id) loggers::get_instance().log("tcp_layer::receive_message_on_fd: Non secured mode"); if (_params[std::string("tcp_fragmented")].compare("1") == 0) { - sleep(5); // FIXME When HTTP paquet is fragmented into several TCP packets, a timer is required. This is a Q&D solution + sleep(4); // FIXME When HTTP paquet is fragmented into several TCP packets, a timer is required. This is a Q&D solution } return Abstract_Socket::receive_message_on_fd(p_client_id); } diff --git a/ccsrc/Protocols/Tcp/tcp_layer.hh b/ccsrc/Protocols/Tcp/tcp_layer.hh index 3dbcba7a6c13b824a3f8683b383eaabec5c8c3fd..8db788c5b003f15665dbcc19cbc8400f368991fe 100644 --- a/ccsrc/Protocols/Tcp/tcp_layer.hh +++ b/ccsrc/Protocols/Tcp/tcp_layer.hh @@ -35,14 +35,14 @@ public: //! \publicsection * \param[in] p_type \todo * \param[in] p_param \todo */ - tcp_layer(const std::string &p_type, const std::string &p_param); + tcp_layer(const std::string& p_type, const std::string& p_param); /*! * \brief Specialised constructor * Create a new instance of the tcp_layer class * \param[in] p_type \todo * \param[in] p_param \todo */ - tcp_layer(const std::string &p_type, const params &p_param); + tcp_layer(const std::string& p_type, const params &p_param); /*! * \brief Default destructor * \remark If \see _reconnect_on_send is set to false, the disconnection is done by the destructor diff --git a/ccsrc/Protocols/Tcp/tcp_layer_factory.hh b/ccsrc/Protocols/Tcp/tcp_layer_factory.hh index 4fe20098388966ef95bf6a77288a5b97974be92b..017f3ec8ac331886cb40c015e192abdf9456782e 100644 --- a/ccsrc/Protocols/Tcp/tcp_layer_factory.hh +++ b/ccsrc/Protocols/Tcp/tcp_layer_factory.hh @@ -31,11 +31,11 @@ public: //! \publicsection layer_stack_builder::register_layer_factory("TCP", this); }; /*! - * \fn layer* create_layer(const std::string & type, const std::string & param); + * \fn layer* create_layer(const std::string& type, const std::string& param); * \brief Create the layers stack based on the provided layers stack description * \param[in] p_type The provided layers stack description * \param[in] p_params Optional parameters * \return 0 on success, -1 otherwise */ - inline virtual layer *create_layer(const std::string &p_type, const std::string &p_param) { return new tcp_layer(p_type, p_param); }; + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new tcp_layer(p_type, p_param); }; }; // End of class tcp_layer_factory diff --git a/ccsrc/Protocols/UDP/udp_layer.cc b/ccsrc/Protocols/UDP/udp_layer.cc index 04a673715bbcd915cb00b0b786c99dc13d9ef40c..e17c530dfe6f87ee18dc4f7396d12de144a27537 100644 --- a/ccsrc/Protocols/UDP/udp_layer.cc +++ b/ccsrc/Protocols/UDP/udp_layer.cc @@ -11,10 +11,10 @@ #include #include -udp_layer::udp_layer(const std::string &p_type, const std::string ¶m) +udp_layer::udp_layer(const std::string& p_type, const std::string& param) : layer(p_type), PORT(p_type.c_str()), _params(), _saddr{0}, _daddr{0}, _reuse_incoming_source_adddress(false), _fd(-1), _time_key("udp_layer::Handle_Fd_Event_Readable") { - loggers::get_instance().log(">>> udp_layer::udp_layer (1): %s, %s, %p", to_string().c_str(), param.c_str(), (void*)this); + loggers::get_instance().log(">>> udp_layer::udp_layer (1): '%s', %s, %p", to_string().c_str(), param.c_str(), (void*)this); // Setup parameters params::convert(_params, param); @@ -22,10 +22,10 @@ udp_layer::udp_layer(const std::string &p_type, const std::string ¶m) init(); } -udp_layer::udp_layer(const std::string &p_type, const params ¶m) +udp_layer::udp_layer(const std::string& p_type, const params ¶m) : layer(p_type), PORT(p_type.c_str()), _params(), _saddr{0}, _daddr{0}, _reuse_incoming_source_adddress(false), _fd(-1), _time_key("udp_layer::Handle_Fd_Event_Readable") { - loggers::get_instance().log(">>> udp_layer::udp_layer (2): %s", to_string().c_str()); + loggers::get_instance().log(">>> udp_layer::udp_layer (2): '%s'", to_string().c_str()); // Setup parameters _params = param; @@ -148,7 +148,7 @@ void udp_layer::Handle_Fd_Event_Readable(int fd) { std::copy((unsigned char *)buffer, (unsigned char *)((unsigned char *)buffer + result), std::back_inserter(acc)); if (_reuse_incoming_source_adddress) { // Reuse the incoming address/port for sending memcpy((void *)&_daddr, (const void *)&from, sizeof(struct sockaddr_in)); - loggers::get_instance().log("udp_layer::Handle_Fd_Event_Readable: New _daddr: %s:%d", ::inet_ntoa(_daddr.sin_addr), ntohs(_daddr.sin_port)); + loggers::get_instance().log("udp_layer::Handle_Fd_Event_Readable: New _daddr: '%s':%d", ::inet_ntoa(_daddr.sin_addr), ntohs(_daddr.sin_port)); } } params.insert(std::pair( @@ -162,7 +162,7 @@ void udp_layer::Handle_Fd_Event_Readable(int fd) { loggers::get_instance().set_stop_time(_time_key, duration); } -unsigned long udp_layer::get_host_id(const std::string &p_host_name) { +unsigned long udp_layer::get_host_id(const std::string& p_host_name) { loggers::get_instance().log(">>> udp_layer::get_host_id"); if (p_host_name.empty()) { @@ -182,13 +182,13 @@ unsigned long udp_layer::get_host_id(const std::string &p_host_name) { struct hostent *hptr; if ((hptr = ::gethostbyname(p_host_name.c_str())) == 0) { close(); - loggers::get_instance().error("udp_layer::get_host_id: Invalid host name: %s", p_host_name.c_str()); + loggers::get_instance().error("udp_layer::get_host_id: Invalid host name: '%s'", p_host_name.c_str()); } ip_addr = *((unsigned long *)hptr->h_addr_list[0]); } } - loggers::get_instance().log("udp_layer::get_host_id: Host name: %s, Host address: %u", p_host_name.c_str(), ip_addr); + loggers::get_instance().log("udp_layer::get_host_id: Host name: '%s', Host address: %u", p_host_name.c_str(), ip_addr); return htonl(ip_addr); } diff --git a/ccsrc/Protocols/UDP/udp_layer.hh b/ccsrc/Protocols/UDP/udp_layer.hh index c24d833568cb364c6b01bed39de5e42d52bfe0f2..4a212e8a231de5ca143dcd75585ba6bb30a1f1be 100644 --- a/ccsrc/Protocols/UDP/udp_layer.hh +++ b/ccsrc/Protocols/UDP/udp_layer.hh @@ -43,14 +43,14 @@ public: //! \publicsection * \param[in] p_type \todo * \param[in] p_param \todo */ - udp_layer(const std::string &p_type, const std::string &p_param); + udp_layer(const std::string& p_type, const std::string& p_param); /*! * \brief Specialised constructor * Create a new instance of the udp_layer class * \param[in] p_type \todo * \param[in] p_param \todo */ - udp_layer(const std::string &p_type, const params &p_param); + udp_layer(const std::string& p_type, const params &p_param); /*! * \brief Default destructor */ @@ -79,6 +79,6 @@ protected: void init(); private: - unsigned long get_host_id(const std::string &p_host_name); + unsigned long get_host_id(const std::string& p_host_name); void close(); }; // End of class udp_layer diff --git a/ccsrc/Protocols/UDP/udp_layer_factory.hh b/ccsrc/Protocols/UDP/udp_layer_factory.hh index d08c50332e6b8fbc9a80d2f0153efaa8223292f9..2c6f7abdbb763ccf07351546abbefa94b780a43f 100644 --- a/ccsrc/Protocols/UDP/udp_layer_factory.hh +++ b/ccsrc/Protocols/UDP/udp_layer_factory.hh @@ -31,12 +31,12 @@ public: //! \publicsection layer_stack_builder::register_layer_factory("UDP", this); }; /*! - * \fn layer* create_layer(const std::string & type, const std::string & param); + * \fn layer* create_layer(const std::string& type, const std::string& param); * \brief Create the layers stack based on the provided layers stack description * \param[in] p_type The provided layers stack description * \param[in] p_params Optional parameters * \return 0 on success, -1 otherwise * \inline */ - inline virtual layer *create_layer(const std::string &p_type, const std::string &p_param) { return new udp_layer(p_type, p_param); }; + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new udp_layer(p_type, p_param); }; }; // End of class udp_layer_factory diff --git a/ccsrc/Protocols/Xml/include/xml_converters.hh b/ccsrc/Protocols/Xml/include/xml_converters.hh new file mode 100644 index 0000000000000000000000000000000000000000..ed1599595f69c97066d51e7c7abb28164a646aaa --- /dev/null +++ b/ccsrc/Protocols/Xml/include/xml_converters.hh @@ -0,0 +1,44 @@ +/*! + * \file xml_converters.hh + * \brief Header file for xml_converters functionality. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include + +#include + +/** + * \class xml_converters + * \brief This class provides XML converters such as canonicalization of XML documents before signature f encryption + */ +class xml_converters { + + static xml_converters *_instance; + +private: + xml_converters() {}; //! Can not be created manually + static int xml_node_set_contains_callback(void* user_data, xmlNodePtr node, xmlNodePtr parent); +public: + static inline xml_converters &get_instance(); + + virtual ~xml_converters() { + if (_instance != nullptr) + delete _instance; + }; + +public: + int xml_canonicalization(const std::string& p_to_canonical, std::string& p_canonicalized) const; + int xml_transform(const std::string& p_to_transform, std::string& p_transformed) const; + +}; // End of class xml_converters + +// static functions +xml_converters &xml_converters::get_instance() { return (_instance != nullptr) ? *_instance : *(_instance = new xml_converters()); } + diff --git a/ccsrc/Protocols/Xml/module.mk b/ccsrc/Protocols/Xml/module.mk new file mode 100644 index 0000000000000000000000000000000000000000..f530e70b89780e96a903940b6a7ebdabb6a62681 --- /dev/null +++ b/ccsrc/Protocols/Xml/module.mk @@ -0,0 +1,4 @@ +sources := \ + src/xml_converters.cc + +includes += ./include diff --git a/ccsrc/Protocols/Xml/src/xml_converters.cc b/ccsrc/Protocols/Xml/src/xml_converters.cc new file mode 100644 index 0000000000000000000000000000000000000000..ef9823303a43849418ecde14332f7279cce74d5e --- /dev/null +++ b/ccsrc/Protocols/Xml/src/xml_converters.cc @@ -0,0 +1,178 @@ +/*! + * \file xml_converters.cc + * \brief Source file for the xml_converters functionality. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#include "xml_converters.hh" + +#include "loggers.hh" + +#include +#include +#include +#include +//#include +//#include + +xml_converters* xml_converters::_instance = nullptr; + +// FIXME Use libxslt +int xml_converters::xml_transform(const std::string& p_to_transform, std::string& p_transformed) const { + loggers::get_instance().log(">>> xml_converters::xml_transform: '%s'", p_to_transform.c_str()); + + + xmlDocPtr doc = xmlReadMemory(p_to_transform.c_str(), p_to_transform.length(), "noname.xml", NULL, 0); + xmlChar *xmlbuff; + int buffersize; + xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); + loggers::get_instance().log("xml_converters::xml_transform: tree dump: '%s'", (char *) xmlbuff); + //"\\n\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\n\\t" + + //xsltApplyStylesheet(cur, doc, params); + xmlFree(xmlbuff); + xmlFreeDoc(doc); + + + int first = p_to_transform.find('>'); + int next = 0; + while ((first != -1) && (first < p_to_transform.length())) { + //loggers::get_instance().log("xml_converters::xml_transform: first: '%d'", first); + //loggers::get_instance().log("xml_converters::xml_transform: next: '%d'", next); + p_transformed += p_to_transform.substr(next, first - next + 1); + //loggers::get_instance().log("xml_converters::xml_transform: p_to_transform: '%s'", p_to_transform.c_str()); + //loggers::get_instance().log("xml_converters::xml_transform: p_transformed: '%s'", p_transformed.c_str()); + next = first + 1; + while ( + (p_to_transform[next] == '\r') || + (p_to_transform[next] == '\n') || + (p_to_transform[next] == '\t') || + (p_to_transform[next] == ' ') + ) { // Skip CR, LF, TAG and SPACE + next += 1; + } // End of 'while'statement + first = p_to_transform.find('>', next); + } // End of 'while'statement + + // + first = p_transformed.find("ns4:"); + while ((first != -1) && (first < p_to_transform.length())) { + p_transformed = p_transformed.substr(0, first) + p_transformed.substr(first + 4, p_transformed.length() - 4 - 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (1): '%s'", p_transformed.c_str()); + first = p_transformed.find("ns4:"); + } // End of 'while'statement + + first = p_transformed.find("xmlns:ns4"); + while ((first != -1) && (first < p_to_transform.length())) { + next = p_transformed.find("\">", first + 1); + p_transformed = p_transformed.substr(0, first - 1) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (2): '%s'", p_transformed.c_str()); + first = p_transformed.find("xmlns:ns4"); + } // End of 'while'statement + + // + first = p_transformed.find("", first + l + 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (3): '%s'", p_transformed.c_str()); + p_transformed = p_transformed.substr(0, first + l) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + } + // + first = p_transformed.find("", first + l + 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (4): '%s'", p_transformed.c_str()); + p_transformed = p_transformed.substr(0, first + l) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + } + // + first = p_transformed.find("", first + l + 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (5): '%s'", p_transformed.c_str()); + p_transformed = p_transformed.substr(0, first + l) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + } + // + first = p_transformed.find("", first + l + 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (6): '%s'", p_transformed.c_str()); + p_transformed = p_transformed.substr(0, first + l) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + } + // + first = p_transformed.find("", first + l + 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (7): '%s'", p_transformed.c_str()); + p_transformed = p_transformed.substr(0, first + l) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + } + // + first = p_transformed.find("", first + l + 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (8): '%s'", p_transformed.c_str()); + p_transformed = p_transformed.substr(0, first + l) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + } + // + first = p_transformed.find("", first + l + 1); + loggers::get_instance().log("xml_converters::xml_transform: New p_transformed (8): '%s'", p_transformed.c_str()); + p_transformed = p_transformed.substr(0, first + l) + p_transformed.substr(next + 1, p_transformed.length() - next - 1); + } + + loggers::get_instance().log("<<< xml_converters::xml_transform: '%s'", p_transformed.c_str()); + return 0; +} + +int xml_converters::xml_canonicalization(const std::string& p_to_canonical, std::string& p_canonicalized) const { + loggers::get_instance().log(">>> xml_converters::xml_canonicalization: '%s'", p_to_canonical.c_str()); + + xmlDocPtr doc = xmlParseMemory(p_to_canonical.c_str(), p_to_canonical.length()); + if (doc == nullptr) { + loggers::get_instance().log("xml_converters::xml_canonicalization: Failed to read XML input"); + return -1; + } + + xmlOutputBufferPtr buffer = xmlAllocOutputBuffer(nullptr); + if (buffer == nullptr) { + loggers::get_instance().log("xml_converters::xml_canonicalization: Failed to read XML input"); + xmlFreeDoc(doc); + return -1; + } + + // Do canonicalization + if (xmlC14NExecute(doc, nullptr/*(xmlC14NIsVisibleCallback)&xml_converters::xml_node_set_contains_callback*/, nullptr, XML_C14N_EXCLUSIVE_1_0, nullptr, 1, buffer) == -1) { + loggers::get_instance().log("xml_converters::xml_canonicalization: Failed to read XML input"); + xmlFreeDoc(doc); + xmlOutputBufferClose(buffer); + return -1; + } + + // Retrieve the canonicalization XML document + const char* data = (const char*)xmlOutputBufferGetContent(buffer); + size_t size = xmlOutputBufferGetSize(buffer); + p_canonicalized.assign(data, data + size); + + // Free resources + xmlOutputBufferClose(buffer); + xmlFreeDoc(doc); + + loggers::get_instance().log("<<< xml_converters::xml_canonicalization: '%s'", p_canonicalized.c_str()); + return 0; +} + +int xml_converters::xml_node_set_contains_callback(void* p_user_data, xmlNodePtr p_node, xmlNodePtr p_parent) { + //loggers::get_instance().log("xml_converters::xml_node_set_contains_callback"); + return 1; +} diff --git a/ccsrc/loggers/loggers.hh b/ccsrc/loggers/loggers.hh index 36f73449dee9fa01d1b96b3f5cc18ffa1119c557..035f2d12d5d4244748cf99b962e397e92a7bff2f 100644 --- a/ccsrc/loggers/loggers.hh +++ b/ccsrc/loggers/loggers.hh @@ -157,7 +157,7 @@ public: //! \publicsection * \param[in] p_time_key A timer identifier (any string) * \inline */ - inline void set_start_time(std::string &p_time_key); + inline void set_start_time(std::string& p_time_key); /*! * \fn void set_stop_time(std::string& p_time_key, float& p_time); * \brief Stop execution time measurement @@ -165,7 +165,7 @@ public: //! \publicsection * \param[out] p_time The execution time measured in milliseconds * \inline */ - inline void set_stop_time(std::string &p_time_key, float &p_time); + inline void set_stop_time(std::string& p_time_key, float &p_time); }; // End of class loggers void loggers::log_to_hexa(const char *p_prompt, const TTCN_Buffer &buffer) { @@ -252,9 +252,9 @@ void loggers::error(const char *p_fmt, ...) { va_end(args); } -void loggers::set_start_time(std::string &p_time_key) { _times[p_time_key] = std::clock(); } +void loggers::set_start_time(std::string& p_time_key) { _times[p_time_key] = std::clock(); } -void loggers::set_stop_time(std::string &p_time_key, float &p_time) { +void loggers::set_stop_time(std::string& p_time_key, float &p_time) { std::map::iterator it = _times.find(p_time_key); if (it != loggers::_times.end()) { p_time = (std::clock() - _times[p_time_key]) * 1000.0 / CLOCKS_PER_SEC; // in milliseconds diff --git a/ccsrc/security/include/certs_cache.hh b/ccsrc/security/include/certs_cache.hh new file mode 100644 index 0000000000000000000000000000000000000000..5e55c713bcc435230fcdbe11caa0bee71056070a --- /dev/null +++ b/ccsrc/security/include/certs_cache.hh @@ -0,0 +1,113 @@ +/*! + * \file certs_cache.hh + * \brief Header file for a certificates caching storage mechanism. + * It is used to store certificates received from neighbors and not present in the data base + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include +#include +#include +#include + +#include + +#include "certs_db_record.hh" + +/*! + * \class certs_cache + * \brief This class provides security record description for in memory security database. In memory mens there is no disk load/save mechanism + */ +class certs_cache { + static bool fill_vector(std::string& p_vector, const std::string& p_org); + +protected: /*! \protectedsection */ + // TODO Enforce with const security_cache_record, and const std::string + std::map _certificates_idx; //! List of the certificate names indexed by the certificate identifier, i.e. the SH1 of the certificate name + std::map _certificates_subject; //! List of the certificates indexed by the certificate subject name + std::map> _certificates; //! List of the certificates indexed by the certificate identifier + +public: /*! \publicsection */ + /*! + * \brief Default ctor + */ + certs_cache(); + /*! + * \brief Default private dtor + */ + virtual ~certs_cache(); + + int get_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, const X509** p_certificate); + /*! + * \fn int get_certificate(const std::string& p_hashed_id8, const X509** p_certificate); + * \brief Retrive the specified certificate either from memory + * \param[in] p_certificate_id The certificate name + * \param[out] p_certificate The X509 certificate + * \return 0 on success, -1 otherwise + */ + int get_certificate(const std::string& p_certificate_id, const X509** p_certificate); + + int get_certificate_by_subject_name(const std::string& p_certificate_subject_name, const X509** p_certificate); +/*! + * \fn int get_private_key(const std::string& p_certificate_id, const EVP_PKEY** p_private_key); + * \brief Retrive the private key of the specified certificate + * \param[in] p_certificate_id The certificate name + * \param[out] p_private_key The private key + * \return 0 on success, -1 otherwise + */ + int get_private_key(const std::string& p_certificate_id, const EVP_PKEY** p_private_key); + /*! + * \fn int get_public_keys(const std::string& p_certificate_id, const EVP_PKEY** p_public_key); + * \brief Retrive the public keys (in uncompressed format) of the specified certificate + * \param[in] p_certificate_id The certificate name + * \param[out] p_public_key The public key + * \return 0 on success, -1 otherwise + */ + int get_public_keys(const std::string& p_certificate_id, const EVP_PKEY** p_public_key); + + int get_certificate_pem(const std::string& p_certificate_id, std::string& p_certificate_pem); + + int store_certificate(const std::string& p_certificate_name, const std::string& p_certificate, std::string& p_certificate_id, const certs_db_record** p_record); + + /*! + * \fn int int clear(); + * \brief Cleanup the cache + * \return 0 on success, -1 otherwise + * \virtual + */ + virtual int clear(); + + void dump() const; // For debug purpose. To be removed + + const std::string cert_to_string(const std::string& p_certificate_id); // For debug purpose. To be removed + + int publickey_to_string(const EVP_PKEY* p_public_kep, std::vector& p_buffer); // For debug purpose. To be removed + + +private: /*! \privatesection */ + /*! + * \fn int load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, const certs_db_record** p_record); + * \brief Retrive the specified certificate either from memory of from storage location + * \param[in] p_certificate_name The certificate name + * \param[in] p_private_key_name The certificate's private key name, in PKCS#8 format + * \param[in] p_private_key_passwd The certificate's private key password for PKCS#8 format encryption. Empty if no encryption + * \param[out] p_record A reference to the certificate record + * \return 0 on success, -1 otherwise + */ + int load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, const certs_db_record** p_record); + /*! + * \fn int load_certificate(const std::string& p_certificate_id, const certs_db_record** p_record); + * \brief Retrive the specified certificate either from memory of from storage location + * \param[in] p_certificate_id The certificate identifier + * \param[out] p_record A reference to the certificate record + * \return 0 on success, -1 otherwise + */ + int load_certificate(const std::string& p_certificate_id, const certs_db_record** p_record); + +}; // End of class certs_cache diff --git a/ccsrc/security/include/certs_db.hh b/ccsrc/security/include/certs_db.hh new file mode 100644 index 0000000000000000000000000000000000000000..609ae4f6f0cd8cbff33adc809e6e536d11ca31cc --- /dev/null +++ b/ccsrc/security/include/certs_db.hh @@ -0,0 +1,41 @@ +/*! + * \file certs_db.hh + * \brief Header file for a list of certificates storage mechanism. + * It is used to store certificates received from neighbors and not present in the data base + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include "certs_cache.hh" + +/*! + * \class certs_db + * \brief This class provides security record description for security database + */ +class certs_db : public certs_cache { + +public: /*! \publicsection */ + /*! + * \brief Ctor with full path to the certificates storage + * \param[in] p_db_path The full path to the certificates storage + */ + certs_db(const std::string& p_db_path); + /*! + * \brief Default dtor + */ + ~certs_db(); + +private: /*! \privatesection */ + /*! + * \fn int initialize_cache(const std::string& p_db_path); + * \brief Initialise the storage of certificates mechanism + * \param[in] p_db_path The full path to the certificates storage + * \return 0 on success, -1 otherwise + */ + int initialize_cache(const std::string& p_db_path); +}; // End of class certs_db diff --git a/ccsrc/security/include/certs_db_record.hh b/ccsrc/security/include/certs_db_record.hh new file mode 100644 index 0000000000000000000000000000000000000000..772493ad5036dfc67b1795af403826151fa08f08 --- /dev/null +++ b/ccsrc/security/include/certs_db_record.hh @@ -0,0 +1,67 @@ +/*! + * \file certs_db_record.hh + * \brief Header file for a storage of certificates mechanism. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include + +#include + +/*! + * \class certs_db_record + * \brief This class provides security record description for security database + */ +class certs_db_record { + + std::string _certificate_id; /*!< Certificate name */ + X509* _certificate; /*!< X509 Certificate */ + EVP_PKEY* _private_key; /*!< Private key */ + std::string _pem; /*!< Certificate PEM format */ + +public: /*! \publicsection */ + /*! + * \brief Default ctor + */ + explicit certs_db_record() + : _certificate_id(nullptr), _certificate(nullptr), _private_key(nullptr), _pem{} {}; + /*! + * \brief Specialised ctor + * \param[in] p_certificate_id The certificate identifier + * \param[in] p_certificate The X509 certificate in openssl format + * \param[in] p_private_key The certificate's private key in openssl format + * \param[in] p_certificate_pem The certificate's PEM format + */ + certs_db_record(const std::string& p_certificate_id, X509* p_certificate, EVP_PKEY* p_private_key, const std::string& p_certificate_pem); + + /*! + * \brief Default dtor + */ + ~certs_db_record(); + + /*! + * \inline + * \fn const std::string& certificate_id() const; + * \brief Retrieve the certificate identifier value + * \return The certificate identifier + */ + inline const std::string& certificate_id() const { return _certificate_id; }; + /*! + * \inline + * \fn const X509* certificate() const; + * \brief Retrieve the COER encoded certificate + * \return The COER encoded certificate + */ + inline const X509* certificate() const { return _certificate; }; + inline const EVP_PKEY* private_key() const { return _private_key; }; + inline const EVP_PKEY* public_key() const { return ::X509_get_pubkey(_certificate); }; + inline const X509_NAME* subject_name() const { return ::X509_get_subject_name(_certificate); }; + inline const X509_NAME* issuer() const { return ::X509_get_issuer_name(_certificate); }; + inline const std::string& pem() const { return _pem; }; +}; // End of class certs_db_record diff --git a/ccsrc/security/include/certs_loader.hh b/ccsrc/security/include/certs_loader.hh new file mode 100644 index 0000000000000000000000000000000000000000..ef7de835558334e0918434e8f78b33d24eadb75a --- /dev/null +++ b/ccsrc/security/include/certs_loader.hh @@ -0,0 +1,99 @@ +/*! + * \file certs_loader.hh + * \brief Header file for X506 PEM certificates loader definition. + * \author ETSI STF625 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + * \remark Use `openssl x509 -in -noout -text` to view the certficate content + * Use `openssl [rsa|dsa|...] -inform PEM -in -text -noout` to view the private key content + * Use `openssl x509 -in -out ` to convert a DER certificate into a PEM certificate + */ +#pragma once + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "certs_db_record.hh" + +/*! + * \class certs_loader + * \brief This class provides mechanism to load the certificates from the filesystem according the struecture defined in ETSI TS 103 099 + * \remark Singleton pattern + */ +class certs_loader { + std::experimental::filesystem::path _db_path; //! Path of the certificates storage + bool _is_cache_initialized; //! Set to true when certificates are successfully loaded from file system + static certs_loader* instance; //! Unique static object reference of this class + + /*! + * \brief Default private ctor + */ + certs_loader(); + /*! + * \brief Default private dtor + */ + ~certs_loader() { + if (instance != NULL) { + delete instance; + instance = NULL; + } + }; + +public: /*! \publicsection */ + /*! + * \brief Public accessor to the single object reference + */ + inline static certs_loader &get_instance() { + if (instance == NULL) + instance = new certs_loader(); + return *instance; + }; + + /*! + * \fn int build_path(const std::string& p_root_directory); + * \brief Set the pass of the certificate storage + * \param[in] p_db_path The pass of the certificate storage + */ + int build_path(const std::string& p_root_directory); + /*! + * \fn int get_certificate_id(const std::string& p_certificate_name, std::string& p_certificate_id); + * \brief Compute the SHA-1 hash of the certificate name to provide the certificate identifier + * \param[in] p_certificate_name The certificate name + * \param[out] p_certificate_id The certificate identifier + * \return 0 on success, -1 otherwise + */ + int get_certificate_id(const std::string& p_certificate_name, std::string& p_certificate_id); + /*! + * \fn int load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, std::map> & p_certificates); + * \brief Store in memory the specified certificate + * \param[in] p_certificate_name The certificate full path bame + * \param[in] p_private_key_name The certificate's private key full path name, in PKCS#8 format + * \param[in] p_private_key_passwd The certificate's private key password for PKCS#8 format encryption. Empty if no encryption + * \param[out] p_certificate_id The certificate identifier + * \param[inout] p_certificates The map of the loaded in memory certificates + * \return 0 on success, -1 otherwise + */ + int load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, std::string& p_certificate_id, std::map> & p_certificates); + /*! + * \fn int store_certificate(const std::string& p_certificate_name, const std::string& p_certificate_pem, std::string& p_certificate_id, std::map> & p_certificates); + * \brief Save the specified certificate and update the internal maps + * \param[in] p_certificate_name The certificate neame + * \param[in] p_certificate_pem The certificate to save in PEM format + * \param[out] p_certificate_id The certificate identifier + * \return 0 on success, -1 otherwise + */ + int store_certificate(const std::string& p_certificate_name, const std::string& p_certificate_pem, std::string& p_certificate_id, std::map> & p_certificates); +}; // End of class certs_loader + diff --git a/ccsrc/security/include/hmac.hh b/ccsrc/security/include/hmac.hh new file mode 100644 index 0000000000000000000000000000000000000000..cbd1ccd985edbb18026279ecf9e186a3cd290cbe --- /dev/null +++ b/ccsrc/security/include/hmac.hh @@ -0,0 +1,69 @@ +/*! + * \file hmac.hh + * \brief Header file for HMAC helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include + +#include + +class OCTETSTRING; //! TITAN forward declaration + +/*! + * \enum Supported hash algorithms + */ +enum class hash_algorithms : unsigned char { + sha_256, /*!< HMAC with SHA-256 */ + sha_384 /*!< HMAC with SHA-384 */ +}; // End of class hash_algorithms + +/*! + * \class hmac + * \brief This class provides description of HMAC helper methods + */ +class hmac { + HMAC_CTX * _ctx; //! HMAC context + hash_algorithms _hash_algorithms; //! HMAC hash algorithm to use +public: + /*! + * \brief Default constructor + * Create a new instance of the hmac class + * \param[in] p_hash_algorithms The hash algorithm to be used to compute the HMAC. Default: sha_256 + */ + hmac(const hash_algorithms p_hash_algorithms = hash_algorithms::sha_256) : _ctx{::HMAC_CTX_new()}, _hash_algorithms(p_hash_algorithms){}; + /*! + * \brief Default destructor + */ + virtual ~hmac() { + if (_ctx != nullptr) { + ::HMAC_CTX_free(_ctx); + }; + }; + + /*! + * \fn int generate(const OCTETSTRING p_buffer, const OCTETSTRING p_secret_key, OCTETSTRING& p_hmac); + * \brief Generate the HMAC of data using a secret key + * \Param[in] p_buffer The data tobe hashed + * \param[in] p_secret_key The secret key to be used to generate the HMAC + * \param[out] p_hmac The HMAC value based of the provided data + * \return 0 on success, -1 otherwise + */ + int generate(const OCTETSTRING p_buffer, const OCTETSTRING p_secret_key, OCTETSTRING &p_hmac); // TODO Use reference & + + /*! + * \fn int generate(const unsigned char* p_buffer, const size_t p_buffer_length, const unsigned char* p_secret_key, const size_t p_secret_key_length, + * OCTETSTRING& p_hmac); \brief Generate the HMAC of data using a secret key \param[in] p_buffer The data to be hashed \param[in] p_buffer_length The size of + * the data \param[in] p_secret_key The secret key to be used to generate the HMAC \param[in] p_secret_key_length The size of the secret key \param[out] + * p_hmac The HMAC value based of the provided data \return 0 on success, -1 otherwise + */ + int generate(const unsigned char *p_buffer, const size_t p_buffer_length, const unsigned char *p_secret_key, const size_t p_secret_key_length, + OCTETSTRING &p_hmac); + +}; // End of class hmac diff --git a/ccsrc/security/include/security_services.hh b/ccsrc/security/include/security_services.hh new file mode 100644 index 0000000000000000000000000000000000000000..7c32f0579df4d148139617275be1ec6e447d5bc9 --- /dev/null +++ b/ccsrc/security/include/security_services.hh @@ -0,0 +1,60 @@ +#pragma once + +#include + +#include +#include +#include + +#include "certs_db.hh" + +class CHARSTRING; +class OCTETSTRING; + + +class security_services { + /*std::unique_ptr _certs_db*/; + static certs_db* _certs_db; + +public: /*! \publicsection */ + /*! + * \brief Default private ctor + */ + security_services()/* : _certs_db{nullptr}*/ {}; + /*! + * \brief Default private dtor + */ + ~security_services() { + //_certs_db.reset(); + delete _certs_db; + }; + + int initialize(const std::string& p_certs_db_path); + /*! + * \fn int load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, std::map> & p_certificates); + * \brief Store in memory the specified certificate + * \param[in] p_certificate_name The certificate full path bame + * \param[in] p_private_key_name The certificate's private key full path name, in PKCS#8 format + * \param[in] p_private_key_passwd The certificate's private key password for PKCS#8 format encryption. Empty if no encryption + * \param[out] p_certificate_id The certificate identifier + * \param[inout] p_certificates The map of the loaded in memory certificates + * \return 0 on success, -1 otherwise + */ + int load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, const X509** p_certificate); + /*! + * \fn int do_sign(const OCTETSTRING& p_encoded_message, const CHARSTRING& p_certificate_name, const CHARSTRING& p_private_key_name, const CHARSTRING& p_private_key_passwd, OCTETSTRING& p_signature, OCTETSTRING& p_digest, CHARSTRING& p_x509_certificate_subject, CHARSTRING& p_x509_certificate_pem); + * \brief Sign message + * \param[in] p_encoded_message The raw message to be signed + * \param[in] TODO The raw message to be signed + * \return 0 on success, -1 otherwise + */ + int do_sign(const OCTETSTRING& p_encoded_message, const OCTETSTRING& p_empty_signature, const CHARSTRING& p_certificate_name, const CHARSTRING& p_private_key_name, const CHARSTRING& p_private_key_passwd, OCTETSTRING& p_signature, OCTETSTRING& p_digest, CHARSTRING& p_x509_certificate_subject, CHARSTRING& p_x509_certificate_pem, CHARSTRING& p_pull_request_canonicalized); + /*! + * \fn int build_path(const std::string& p_root_directory); + * \brief Verify message signature + * \param[in] p_message The raw message to be verified + * \param[in] TODO + * \return true on success, false otherwise + */ + bool do_sign_verify(const CHARSTRING& p_message, const OCTETSTRING& p_empty_signature, const UNIVERSAL_CHARSTRING& p_canonicalization_method, const UNIVERSAL_CHARSTRING& p_signature_method, const UNIVERSAL_CHARSTRING& p_digest_method, const UNIVERSAL_CHARSTRING& p_digest_value, const UNIVERSAL_CHARSTRING& p_signature_value, const UNIVERSAL_CHARSTRING& p_subject_name, const UNIVERSAL_CHARSTRING& p_certificate, CHARSTRING& p_debug_message); +}; \ No newline at end of file diff --git a/ccsrc/security/include/sha1.hh b/ccsrc/security/include/sha1.hh new file mode 100644 index 0000000000000000000000000000000000000000..e053544a88354affce96dc3a2e028a012df946ee --- /dev/null +++ b/ccsrc/security/include/sha1.hh @@ -0,0 +1,66 @@ +/*! + * \file sha1.hh + * \brief Header file for SHA-1 helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include +#include + +class OCTETSTRING; //! TITAN forward declaration + +/*! + * \class sha1 + * \brief This class provides description of SHA-1 helper methods + */ +class sha1 { + SHA_CTX _ctx; //! SHA context +public: + /*! + * \brief Default constructor + * Create a new instance of the sha1 class + */ + explicit sha1() : _ctx{} {}; + /*! + * \brief Default destructor + */ + virtual ~sha1(){}; + + /*! + * \fn int generate(const OCTETSTRING& p_buffer, OCTETSTRING& p_hash); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_buffer The data used to generate the SHA-1 hash + * \param[out] p_hash The SHA-1 hash value based of the provided data + * \return 0 on success, -1 otherwise + */ + int generate(const OCTETSTRING &p_buffer, OCTETSTRING &p_hash); + + /*! + * \fn int generate(const unsigned char* p_buffer, OCTETSTRING& p_hash); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_buffer The data used to generate the SHA-1 hash + * \param[in] The length of the data buffer + * \param[out] p_hash The SHA-1 hash value based of the provided data + * \return 0 on success, -1 otherwise + */ + int generate(const unsigned char *p_buffer, const size_t p_length, OCTETSTRING &p_hash); + + /*! + * \fn const OCTETSTRING get_sha1_empty_string() const; + * \brief Return the SHA-1 of an empty string + * \return The SHA-1 of an empty string + */ + inline const OCTETSTRING get_sha1_empty_string() const { + static unsigned char sha1_empty_string[] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09}; //! SHA-1 of an empty string + return OCTETSTRING(20, sha1_empty_string); + }; + +}; // End of class sha1 diff --git a/ccsrc/security/include/sha256.hh b/ccsrc/security/include/sha256.hh new file mode 100644 index 0000000000000000000000000000000000000000..4973a2efd1f9c73d8bbab1b073e2d8d095cb453a --- /dev/null +++ b/ccsrc/security/include/sha256.hh @@ -0,0 +1,66 @@ +/*! + * \file sha256.hh + * \brief Header file for SHA-256 helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include +#include + +class OCTETSTRING; //! TITAN forward declaration + +/*! + * \class sha256 + * \brief This class provides description of SHA-256 helper methods + */ +class sha256 { + SHA256_CTX _ctx; //! SHA context +public: + /*! + * \brief Default constructor + * Create a new instance of the sha256 class + */ + explicit sha256() : _ctx{} {}; + /*! + * \brief Default destructor + */ + virtual ~sha256(){}; + + /*! + * \fn int generate(const OCTETSTRING& p_buffer, OCTETSTRING& p_hash); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_buffer The data used to generate the SHA-256 hash + * \param[out] p_hash The SHA-256 hash value based of the provided data + * \return 0 on success, -1 otherwise + */ + int generate(const OCTETSTRING &p_buffer, OCTETSTRING &p_hash); + + /*! + * \fn int generate(const unsigned char* p_buffer, OCTETSTRING& p_hash); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_buffer The data used to generate the SHA-256 hash + * \param[in] The length of the data buffer + * \param[out] p_hash The SHA-256 hash value based of the provided data + * \return 0 on success, -1 otherwise + */ + int generate(const unsigned char *p_buffer, const size_t p_length, OCTETSTRING &p_hash); + + /*! + * \fn const OCTETSTRING get_sha256_empty_string() const; + * \brief Return the SHA-256 of an empty string + * \return The SHA-256 of an empty string + */ + inline const OCTETSTRING get_sha256_empty_string() const { + static unsigned char sha256_empty_string[] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; //! SHA-256 of an empty string + return OCTETSTRING(32, sha256_empty_string); + }; + +}; // End of class sha256 diff --git a/ccsrc/security/include/sha384.hh b/ccsrc/security/include/sha384.hh new file mode 100644 index 0000000000000000000000000000000000000000..67f2d19ad643aa114d08f0c343723c8f56682e22 --- /dev/null +++ b/ccsrc/security/include/sha384.hh @@ -0,0 +1,60 @@ +/*! + * \file sha384.hh + * \brief Header file for SHA-384 helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include +#include + +class OCTETSTRING; //! TITAN forward declaration + +/*! + * \class sha384 + * \brief This class provides description of SHA-384 helper methods + */ +class sha384 { + SHA512_CTX _ctx; //! SHA context +public: //! \publicsection + /*! + * \brief Default constructor + * Create a new instance of the sha384 class + */ + explicit sha384() : _ctx{} {}; + /*! + * \brief Default destructor + */ + virtual ~sha384(){}; + + /*! + * \fn int generate(const OCTETSTRING& p_buffer, OCTETSTRING& p_hash); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_buffer The data used to generate the SHA-384 hash + * \param[out] p_hash The SHA-384 hash value based of the provided data + * \return 0 on success, -1 otherwise + */ + int generate(const OCTETSTRING &p_buffer, OCTETSTRING &p_hash); + + /*! + * \fn int generate(const OCTETSTRING p_buffer, OCTETSTRING& p_hash); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_buffer The data used to generate the SHA-384 hash + * \param[in] The length of the data buffer + * \param[out] p_hash The SHA-384 hash value based of the provided data + * \return 0 on success, -1 otherwise + */ + int generate(const unsigned char *p_buffer, const size_t p_length, OCTETSTRING &p_hash); + + /*! + * \fn const OCTETSTRING get_sha384_empty_string() const; + * \brief Return the SHA-384 of an empty string + * \return The SHA-384 of an empty string + */ + const OCTETSTRING get_sha384_empty_string() const; +}; // End of class sha384 diff --git a/ccsrc/security/module.mk b/ccsrc/security/module.mk new file mode 100644 index 0000000000000000000000000000000000000000..114a8ab6b83f1cd54db0a5abb17bd9b8f0a50ac2 --- /dev/null +++ b/ccsrc/security/module.mk @@ -0,0 +1,14 @@ +sources := \ + src/security_externals.cc \ + src/certs_db_record.cc \ + src/certs_db.cc \ + src/certs_cache.cc \ + src/certs_loader.cc \ + src/securty_services.cc \ + src/sha1.cc \ + src/sha256.cc \ + src/sha384.cc \ + src/hmac.cc \ + # src/sm3.cc \ + +includes := ./include diff --git a/ccsrc/security/src/certs_cache.cc b/ccsrc/security/src/certs_cache.cc new file mode 100644 index 0000000000000000000000000000000000000000..1d7bcf7fd066357456d83c5e480a6fb447cbba87 --- /dev/null +++ b/ccsrc/security/src/certs_cache.cc @@ -0,0 +1,264 @@ +/*! + * \file certs_cache.cc + * \brief Source file for a certificates caching storage mechanism. + * It is used to store certificates received from neighbors and not present in the data base + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#include "certs_cache.hh" +#include "certs_loader.hh" + +#include "TTCN3.hh" +#include "sha1.hh" + +#include "converter.hh" + +#include "loggers.hh" + +certs_cache::certs_cache() : _certificates_idx(), _certificates_subject(), _certificates() { loggers::get_instance().log(">>> certs_cache::certs_cache"); } // End of ctor + +certs_cache::~certs_cache() { + loggers::get_instance().log(">>> certs_cache::~certs_cache"); + clear(); +} // End of dtor + +int certs_cache::clear() { + loggers::get_instance().log(">>> certs_cache::clear"); + _certificates.clear(); // Smart pointers will do the job + _certificates_idx.clear(); + _certificates_subject.clear(); + + return 0; +} // End of clear method + +int certs_cache::load_certificate(const std::string& p_certificate_id, const certs_db_record** p_record) { + loggers::get_instance().log(">>> certs_cache::load_certificate (1): '%s'", p_certificate_id.c_str()); + + // Sanity check + std::map>::const_iterator it = _certificates.find(p_certificate_id); + if (it == _certificates.cend()) { + loggers::get_instance().warning("certs_cache::load_certificate: Failed to load certificate"); + return -1; + } + + *p_record = it->second.get(); + + return 0; +} + +int certs_cache::load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, const certs_db_record** p_record) { + loggers::get_instance().log(">>> certs_cache::load_certificate (2): '%s'", p_certificate_name.c_str()); + + std::string certificate_id; + if (certs_loader::get_instance().get_certificate_id(p_certificate_name, certificate_id) != 0) { + loggers::get_instance().warning("certs_cache::load_certificate: Failed to retrieve certificate identifier"); + return -1; + } + loggers::get_instance().log("certs_cache::load_certificate (2): certificate_id: '%s'", certificate_id.c_str()); + + std::map::const_iterator s = _certificates_idx.find(certificate_id); + if (s == _certificates_idx.cend()) { // Certificate is not in the DB + loggers::get_instance().log("certs_cache::load_certificate (2): Record not found"); + if (certs_loader::get_instance().load_certificate(p_certificate_name, p_private_key_name, p_private_key_passwd, certificate_id, _certificates) == -1) { + loggers::get_instance().warning("certs_cache::load_certificate: Failed to load certificate"); + return -1; + } + // Certificate is on the DB, load it + std::map>::const_iterator it = _certificates.find(certificate_id); + *p_record = it->second.get(); + // Mapping certificate id/certificate name + _certificates_idx.insert(std::pair(certificate_id, p_certificate_name)); + std::string sn(256, (char)0x00); + const X509_NAME* subject = (*p_record)->subject_name(); + ::X509_NAME_oneline(subject, sn.data(), sn.length()); + loggers::get_instance().log("certs_cache::load_certificate: sn: '%s'", sn.c_str()); + _certificates_subject.insert(std::pair(sn, certificate_id)); + } else { + // Certificate is on the DB, load it + std::map>::const_iterator it = _certificates.find(certificate_id); + *p_record = it->second.get(); + } + + return 0; +} + +int certs_cache::get_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, const X509** p_certificate) { + loggers::get_instance().log(">>> certs_cache::get_certificate (1): '%s'", p_certificate_name.c_str()); + + const certs_db_record* record; + if (load_certificate(p_certificate_name, p_private_key_name, p_private_key_passwd, &record) == -1) { + loggers::get_instance().warning("certs_cache::get_certificate (1): Failed to load certificate"); + return -1; + } + + *p_certificate = record->certificate(); + loggers::get_instance().log("certs_cache::get_certificate (1): p_certificate: '%p'", *p_certificate); + + return 0; +} + +int certs_cache::get_certificate(const std::string& p_certificate_id, const X509** p_certificate) { + loggers::get_instance().log(">>> certs_cache::get_certificate (2): '%s'", p_certificate_id.c_str()); + + const certs_db_record* record; + if (load_certificate(p_certificate_id, &record) == -1) { + loggers::get_instance().warning("certs_cache::get_certificate (2): Failed to load certificate"); + return -1; + } + + *p_certificate = record->certificate(); + loggers::get_instance().log("certs_cache::get_certificate (2): p_certificate: '%p'", *p_certificate); + + return 0; +} + +int certs_cache::get_certificate_by_subject_name(const std::string& p_certificate_subject_name, const X509** p_certificate) { + loggers::get_instance().log(">>> certs_cache::get_certificate_by_subject_name: '%s'", p_certificate_subject_name.c_str()); + + std::map::const_iterator s = _certificates_subject.find(p_certificate_subject_name); + if (s == _certificates_subject.cend()) { // Certificate is not in the DB + loggers::get_instance().warning("certs_cache::get_certificate_by_subject_name: Record not found"); + return -1; + } + + if (get_certificate(s->second, p_certificate) == -1) { + loggers::get_instance().error("certs_cache::get_certificate_by_subject_name: DB corrupted: '%s'", s->second.c_str()); + return -1; + } + loggers::get_instance().log("certs_cache::get_certificate_by_subject_name: p_certificate: '%p'", *p_certificate); + + return 0; +} + +int certs_cache::get_private_key(const std::string& p_certificate_id, const EVP_PKEY** p_private_key) { + loggers::get_instance().log(">>> certs_cache::get_private_key: '%s'", p_certificate_id.c_str()); + + const certs_db_record *record; + if (load_certificate(p_certificate_id, &record) == -1) { + loggers::get_instance().warning("certs_cache::get_private_key: Failed to load certificate"); + return -1; + } + + *p_private_key = record->private_key(); + loggers::get_instance().log("certs_cache::get_private_key: p_private_key: '%p'", *p_private_key); + + return 0; +} + +int certs_cache::get_public_keys(const std::string& p_certificate_id, const EVP_PKEY** p_public_key) { + loggers::get_instance().log(">>> certs_cache::get_public_keys: '%s'", p_certificate_id.c_str()); + + const certs_db_record* record; + if (load_certificate(p_certificate_id, &record) == -1) { + loggers::get_instance().warning("certs_cache::get_public_keys: Failed to load certificate"); + return -1; + } + + *p_public_key = record->public_key(); + loggers::get_instance().log("certs_cache::p_public_key: p_public_key: '%p'", *p_public_key); + + return 0; +} + +int certs_cache::get_certificate_pem(const std::string& p_certificate_id, std::string& p_certificate_pem) { + loggers::get_instance().log(">>> certs_cache::get_certificate_pem: '%s'", p_certificate_id.c_str()); + + const certs_db_record* record; + if (load_certificate(p_certificate_id, &record) == -1) { + loggers::get_instance().warning("certs_cache::get_certificate_pem: Failed to load certificate"); + return -1; + } + + p_certificate_pem = record->pem(); + loggers::get_instance().log("certs_cache::get_certificate_pem: p_certificate_pem: '%s'", p_certificate_pem.c_str()); + + return 0; +} + +int certs_cache::store_certificate(const std::string& p_certificate_name, const std::string& p_certificate_pem, std::string& p_certificate_id, const certs_db_record** p_record) { + loggers::get_instance().log(">>> certs_cache::store_certificate: '%s'", p_certificate_name.c_str()); + + if (certs_loader::get_instance().store_certificate(p_certificate_name, p_certificate_pem, p_certificate_id, _certificates) == -1) { + loggers::get_instance().warning("certs_cache::store_certificate: Failed to load certificate"); + return -1; + } + + loggers::get_instance().log("certs_cache::store_certificate: Dump of current certificates: "); + dump(); + + // Certificate is on the DB, load it + std::map>::const_iterator it = _certificates.find(p_certificate_id); + *p_record = it->second.get(); + // Mapping certificate id/certificate name + _certificates_idx.insert(std::pair(p_certificate_id, p_certificate_name)); + std::string sn(256, (char)0x00); + const X509_NAME* subject = (*p_record)->subject_name(); + ::X509_NAME_oneline(subject, sn.data(), sn.length()); + loggers::get_instance().log("certs_cache::store_certificate: sn: '%s'", sn.c_str()); + _certificates_subject.insert(std::pair(sn, p_certificate_id)); + + return 0; +} + +void certs_cache::dump() const { + loggers::get_instance().log(">>> certs_cache::dump_certificates: # items = %d", _certificates.size()); + + for (std::map>::const_iterator it = _certificates.cbegin(); it != _certificates.cend(); ++it) { + const certs_db_record *p = it->second.get(); + loggers::get_instance().log("certs_cache::dump_certificates: certificate_id: '%s'", p->certificate_id().c_str()); + } // End of 'for' statement +} // End of method dump + +const std::string certs_cache::cert_to_string(const std::string& p_certificate_id) { + loggers::get_instance().log(">>> certs_cache::cert_to_string: '%s'", p_certificate_id.c_str()); + + const certs_db_record* record; + if (load_certificate(p_certificate_id, &record) == -1) { + loggers::get_instance().warning("certs_cache::cert_to_string: Failed to load certificate"); + return std::string(::ERR_error_string(::ERR_get_error(), nullptr));; + } + + BIO* bio = ::BIO_new(::BIO_s_mem()); + if (bio == nullptr) { + loggers::get_instance().warning("certs_cache::cert_to_string: Failed to dunp certificate"); + return std::string(::ERR_error_string(::ERR_get_error(), nullptr)); + } + + if (::PEM_write_bio_X509(bio, (X509*)record->certificate()) == 0) { + ::BIO_free(bio); + loggers::get_instance().warning("certs_cache::cert_to_string: Failed to dunp certificate"); + return std::string(::ERR_error_string(::ERR_get_error(), nullptr)); + } + + size_t len = ::BIO_get_mem_data(bio, nullptr); + std::string s(len, 0x00); + ::BIO_read(bio, s.data(), len); + ::BIO_free(bio); + loggers::get_instance().log("certs_cache::cert_to_string: dump: '%s'", s.c_str()); + + return s; +} + +int certs_cache::publickey_to_string(const EVP_PKEY* p_public_kep, std::vector& p_buffer) { + loggers::get_instance().log(">>> certs_cache::publickey_to_string: '%p'", p_public_kep); + + unsigned char* buffer = nullptr; + int ret = ::i2d_PublicKey((EVP_PKEY*)p_public_kep, &buffer); + loggers::get_instance().log("certs_cache::publickey_to_string: ret: '%d'", ret); + if (ret < 0) { + loggers::get_instance().warning("certs_cache::publickey_to_string: Failed to dunp certificate"); + p_buffer.clear(); + return -1; + } + + p_buffer.assign((unsigned char*)buffer, (unsigned char*)(buffer + ret)); + ::OPENSSL_free(buffer); + loggers::get_instance().log("certs_cache::publickey_to_string: p_buffer len: '%d'", p_buffer.size()); + loggers::get_instance().log("certs_cache::publickey_to_string: dump: '%s'", converter::get_instance().bytes_to_hexa(p_buffer).c_str()); + + return 0; +} \ No newline at end of file diff --git a/ccsrc/security/src/certs_db.cc b/ccsrc/security/src/certs_db.cc new file mode 100644 index 0000000000000000000000000000000000000000..4bc3193c9ae2eed4631c13a86ae04000e91b944d --- /dev/null +++ b/ccsrc/security/src/certs_db.cc @@ -0,0 +1,26 @@ +#include "certs_db.hh" + +#include "params.hh" +#include "loggers.hh" +#include "converter.hh" + +using namespace std; // Required for isnan() +#include "certs_loader.hh" + +certs_db::certs_db(const std::string& p_db_path) { + loggers::get_instance().log(">>> certs_db::certs_db: '%s'", p_db_path.c_str()); + + initialize_cache(p_db_path); + loggers::get_instance().log("<<< certs_db::certs_db"); +} // End of ctor + +certs_db::~certs_db() { loggers::get_instance().log(">>> certs_db::~certs_db"); } // End of dtor + +int certs_db::initialize_cache(const std::string& p_db_path) { + loggers::get_instance().log(">>> certs_db::initialize_cache: '%s'", p_db_path.c_str()); + + certs_loader::get_instance().build_path(p_db_path); + + loggers::get_instance().log("<<< certs_db::initialize_cache"); + return 0; +} diff --git a/ccsrc/security/src/certs_db_record.cc b/ccsrc/security/src/certs_db_record.cc new file mode 100644 index 0000000000000000000000000000000000000000..2439e4afbd27a25e00cfccea0a071331ad806146 --- /dev/null +++ b/ccsrc/security/src/certs_db_record.cc @@ -0,0 +1,32 @@ +/*! + * \file certs_db_record.cc + * \brief Source file for a storage of certificates mechanism. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ + +#include + +#include "loggers.hh" + +#include "certs_db_record.hh" + +certs_db_record::certs_db_record(const std::string& p_certificate_id, X509* p_certificate, EVP_PKEY* p_private_key, const std::string& p_certificate_pem) : _certificate_id(p_certificate_id), _certificate(p_certificate), _private_key(p_private_key), _pem(p_certificate_pem) { + loggers::get_instance().log(">>> certs_db_record::certs_db_record: p_certificate_id: '%s'", _certificate_id.c_str()); + // loggers::get_instance().log(">>> certs_db_record::certs_db_record: p_certificate: '%p'", _certificate_id); + // loggers::get_instance().log(">>> certs_db_record::certs_db_record: p_private_key: '%p'", _private_key); + //loggers::get_instance().log(">>> certs_db_record::certs_db_record: p_private_key: '%s'", _pem.c_str()); +} + +certs_db_record::~certs_db_record() { + if (_certificate != nullptr) { + ::X509_free(_certificate); + if (_private_key != nullptr) { + ::EVP_PKEY_free(_private_key); + } + } +} diff --git a/ccsrc/security/src/certs_loader.cc b/ccsrc/security/src/certs_loader.cc new file mode 100644 index 0000000000000000000000000000000000000000..306e6a5417dee83d7388f6a4e2055f3a87509e61 --- /dev/null +++ b/ccsrc/security/src/certs_loader.cc @@ -0,0 +1,227 @@ +#include +#include + +#include +#include +#include +#include + +#include + +#include "sha1.hh" +#include "certs_loader.hh" + +#include "loggers.hh" + +certs_loader *certs_loader::instance = nullptr; + +certs_loader::certs_loader() : _db_path(), _is_cache_initialized{false} { + loggers::get_instance().log(">>> certs_loader::certs_loader"); +} // End of ctor + +int certs_loader::build_path(const std::string& p_root_directory) { + loggers::get_instance().log(">>> certs_loader::build_path: '%s'", p_root_directory.c_str()); + + // Sanity check + if (_is_cache_initialized) { + return 0; + } + + // Build full path + if (!p_root_directory.empty()) { + _db_path = p_root_directory; + if (!std::experimental::filesystem::exists(_db_path) || + !std::experimental::filesystem::is_directory(_db_path)) { // FIXME Coredump when app hasn't the rights to create the directory!!!! + // Create directory + if (!std::experimental::filesystem::create_directory(_db_path)) { + _db_path = "./"; + } else { // Set rights for all users + std::experimental::filesystem::permissions(_db_path, + std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | + std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); + } + } + } else { + _db_path = "./"; + } + std::experimental::filesystem::canonical(_db_path); + loggers::get_instance().log("certs_loader::build_path: full path: %s", _db_path.string().c_str()); + if (!std::experimental::filesystem::exists(_db_path)) { + loggers::get_instance().warning("certificates_loader::build_path: Invalid path"); + _db_path.clear(); + return -1; + } + + + loggers::get_instance().log("<<< certs_loader::build_path"); + return 0; +} + +int certs_loader::get_certificate_id(const std::string& p_certificate_name, std::string& p_certificate_id) { + loggers::get_instance().log(">>> certs_loader::get_certificate_id: '%s'", p_certificate_name.c_str()); + + // Build the certificate identifier + sha1 s; + const OCTETSTRING buffer = OCTETSTRING(p_certificate_name.length(), (unsigned char*)p_certificate_name.c_str()); + OCTETSTRING hash; + if (s.generate(buffer, hash) != 0) { + loggers::get_instance().warning("certs_cache::load_certificate: Failed to build the certificate identifier"); + return -1; + } + loggers::get_instance().log_msg("certs_loader::get_certificate_id: hash: ", hash); + CHARSTRING hash_str = oct2str(hash); + p_certificate_id.assign(static_cast(hash_str), static_cast(hash_str) + hash_str.lengthof()); + + loggers::get_instance().log("<<< certs_loader::get_certificate_id: '%s'", p_certificate_id.c_str()); + return 0; +} + +int certs_loader::load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, std::string& p_certificate_id, std::map> & p_certificates) { + loggers::get_instance().log(">>> certs_loader::load_certificate: '%s'", p_certificate_name.c_str()); + loggers::get_instance().log(">>> certs_loader::load_certificate: '%s'", p_private_key_name.c_str()); + + // Load certificate file + BIO* certbio = ::BIO_new(::BIO_s_file()); + if (certbio == nullptr) { + loggers::get_instance().warning("certs_loader::load_certificate: Error creating BIO"); + return -1; + } + std::experimental::filesystem::path p = _db_path.string() + "/" + p_certificate_name; + loggers::get_instance().log("certs_loader::load_certificate: p='%s'", p.string().c_str()); + int ret = BIO_read_filename(certbio, p.string().c_str()); + + X509* cert = ::PEM_read_bio_X509(certbio, NULL, 0, NULL); + if (cert == nullptr) { + loggers::get_instance().warning("certs_loader::load_certificate: Error loading cert into memory"); + ::BIO_free_all(certbio); + return -1; + } + + std::unique_ptr bio(BIO_new(BIO_s_mem()), ::BIO_free); + ret = ::PEM_write_bio_X509(bio.get(), cert); + if (ret != 1) { + loggers::get_instance().warning("certs_loader::load_certificate: PEM_write_bio_X509 failed, error %s", ::ERR_get_error()); + ::X509_free(cert); + ::BIO_free_all(certbio); + return -1; + } + BUF_MEM *mem = NULL; + ::BIO_get_mem_ptr(bio.get(), &mem); + if (!mem || !mem->data || !mem->length) { + loggers::get_instance().warning("certs_loader::load_certificate: BIO_get_mem_ptr failed, error %s", ::ERR_get_error()); + ::X509_free(cert); + ::BIO_free_all(certbio); + return -1; + } + std::string pem(mem->data, mem->length); + // Remove labels + loggers::get_instance().log("certs_loader::load_certificate: certificate pem (1): '%s'", pem.c_str()); + std::string s("-----BEGIN CERTIFICATE-----\n"); + std::string::size_type idx = pem.find_first_of(s); + pem = pem.substr(s.length()); + s = "\n-----END CERTIFICATE-----\n"; + idx = pem.rfind(s); + pem = pem.substr(0, pem.length() - s.length()); + //loggers::get_instance().log("certs_loader::load_certificate: certificate pem (2): '%s'", pem.c_str()); + + ::BIO_free_all(certbio); + + // Load private key file + certbio = ::BIO_new(::BIO_s_file()); + if (certbio == nullptr) { + loggers::get_instance().warning("certs_loader::load_certificate: Error creating BIO"); + ::X509_free(cert); + return -1; + } + p = _db_path.string() + "/" + p_private_key_name; + ret = BIO_read_filename(certbio, p.string().c_str()); + pem_password_cb* cb = NULL; + if (!p_private_key_passwd.empty() > 0) { + // TODO + } + EVP_PKEY* private_key = ::PEM_read_bio_PrivateKey(certbio, NULL, cb, NULL); + if (private_key == nullptr) { + loggers::get_instance().warning("certs_loader::load_certificate: Error loading cert into memory"); + ::X509_free(cert); + ::BIO_free_all(certbio); + return -1; + } + ::BIO_free_all(certbio); + + // Build the certificate identifier + if (get_certificate_id(p_certificate_name, p_certificate_id) != 0) { + loggers::get_instance().warning("certs_cache::load_certificate: Failed to build the certificate identifier"); + return -1; + } + loggers::get_instance().log("certs_loader::load_certificate: p_certificate_name: '%s'", p_certificate_name.c_str()); + loggers::get_instance().log("certs_loader::load_certificate: p_certificate_id: '%s'", p_certificate_id.c_str()); + loggers::get_instance().log("certs_loader::load_certificate: cert: '%p'", cert); + loggers::get_instance().log("certs_loader::load_certificate: private_key: '%p'", private_key); + //loggers::get_instance().log("certs_loader::load_certificate: certificate pem: '%s'", pem.c_str()); + + // Create new record + certs_db_record *r = new certs_db_record(p_certificate_name, cert, private_key, pem); + std::pair>::iterator, bool> result = p_certificates.insert(std::pair>(p_certificate_id, std::unique_ptr(r))); + if (result.second == false) { + loggers::get_instance().warning("certs_loader::build_certificates_cache: Failed to insert new record '%s'", p_certificate_name.c_str()); + delete r; + return -1; + } + + return 0; +} + +int certs_loader::store_certificate(const std::string& p_certificate_name, const std::string& p_certificate_pem, std::string& p_certificate_id, std::map> & p_certificates) { + loggers::get_instance().log(">>> certs_loader::store_certificate '%s'", p_certificate_name.c_str()); + loggers::get_instance().log(">>> certs_loader::store_certificate: '%s'", p_certificate_pem.c_str()); + + // Build the certificate identifier + if (get_certificate_id(p_certificate_name, p_certificate_id) != 0) { + loggers::get_instance().warning("certs_cache::store_certificate: Failed to build the certificate identifier"); + return -1; + } + + // Load certificate file + std::string s("-----BEGIN CERTIFICATE-----\n"); + if (p_certificate_pem.find(s) == std::string::npos) { // Add delimeters + loggers::get_instance().log("certs_loader::store_certificate: Add delimeters"); + s = s.append(p_certificate_pem); + s = s.append("\n-----END CERTIFICATE-----\n"); + } else { + loggers::get_instance().log("certs_loader::store_certificate: Do not add delimeters"); + s = p_certificate_pem; + } + loggers::get_instance().log("certs_loader::store_certificate: pem: '%s'", s.c_str()); + BIO* certbio = ::BIO_new_mem_buf(s.c_str(), -1); + if (certbio == nullptr) { + loggers::get_instance().warning("certs_loader::store_certificate: Error creating in memory BIO"); + return -1; + } + + X509* cert = ::PEM_read_bio_X509(certbio, NULL, 0, NULL); + if (cert == nullptr) { + loggers::get_instance().warning("certs_loader::store_certificate: Error loading cert into memory"); + ::BIO_free_all(certbio); + return -1; + } + ::BIO_free(certbio); + + loggers::get_instance().log("certs_loader::store_certificate: p_certificate_name: '%s'", p_certificate_name.c_str()); + loggers::get_instance().log("certs_loader::store_certificate: p_certificate_id: '%s'", p_certificate_id.c_str()); + loggers::get_instance().log("certs_loader::store_certificate: cert: '%p'", cert); + + + // FIXME Dump certificate + + + // Create new record + certs_db_record *r = new certs_db_record(p_certificate_name, cert, nullptr, p_certificate_pem); + std::pair>::iterator, bool> result = p_certificates.insert(std::pair>(p_certificate_id, std::unique_ptr(r))); + if (result.second == false) { + loggers::get_instance().warning("certs_loader::store_certificate: Failed to insert new record '%s'", p_certificate_name.c_str()); + delete r; + return -1; + } + + return 0; +} // End of method store_certificate diff --git a/ccsrc/security/src/hmac.cc b/ccsrc/security/src/hmac.cc new file mode 100644 index 0000000000000000000000000000000000000000..ab5c2485b268a0f97e52d4e75c6d08f39e8c9017 --- /dev/null +++ b/ccsrc/security/src/hmac.cc @@ -0,0 +1,54 @@ +/*! + * \file hmac.cc + * \brief Source file for HMAC helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#include + +#include "hmac.hh" + +#include "loggers.hh" + +int hmac::generate(const OCTETSTRING p_buffer, const OCTETSTRING p_secret_key, OCTETSTRING &p_hmac) { + // Sanity check + if (p_buffer.lengthof() == 0) { + return -1; + } + + return generate(static_cast(p_buffer), p_buffer.lengthof(), static_cast(p_secret_key), p_secret_key.lengthof(), + p_hmac); +} + +int hmac::generate(const unsigned char *p_buffer, const size_t p_buffer_length, const unsigned char *p_secret_key, const size_t p_secret_key_length, + OCTETSTRING &p_hmac) { + // Sanity check + if ((p_buffer == nullptr) || (p_secret_key == nullptr)) { + return -1; + } + ::HMAC_CTX_reset(_ctx); + + p_hmac = int2oct(0, EVP_MAX_MD_SIZE); + if (_hash_algorithms == hash_algorithms::sha_256) { + ::HMAC_Init_ex(_ctx, (const void *)p_secret_key, (long unsigned int)p_secret_key_length, EVP_sha256(), NULL); + } else if (_hash_algorithms == hash_algorithms::sha_384) { + ::HMAC_Init_ex(_ctx, (const void *)p_secret_key, (long unsigned int)p_secret_key_length, EVP_sha384(), NULL); + } else { // TODO To be continued + return -1; + } + // Compute the hash value + ::HMAC_Update(_ctx, p_buffer, p_buffer_length); + unsigned int length = p_hmac.lengthof(); + ::HMAC_Final(_ctx, (unsigned char *)static_cast(p_hmac), &length); + loggers::get_instance().log_to_hexa("hmac::generate: ", (unsigned char *)static_cast(p_hmac), length); + // Resize the hmac + if (_hash_algorithms == hash_algorithms::sha_256) { + p_hmac = OCTETSTRING(16, static_cast(p_hmac)); + } // FIXME Check length for the other hash algorithm + + return 0; +} diff --git a/ccsrc/security/src/security_externals.cc b/ccsrc/security/src/security_externals.cc new file mode 100644 index 0000000000000000000000000000000000000000..641c9f538c66c0b566f4d91f93352098c6499a81 --- /dev/null +++ b/ccsrc/security/src/security_externals.cc @@ -0,0 +1,222 @@ +#include "LibSecurity_Hash.hh" +#include "LibSecurity_Signature.hh" +#include "LibSecurity_Certificates.hh" + +#include "loggers.hh" + +#include "sha1.hh" +#include "sha256.hh" +#include "sha384.hh" +#include "certs_db.hh" +#include "security_services.hh" + +static std::unique_ptr _security_services; + +static int transform_signature_workaround(std::string& str) { + loggers::get_instance().log(">>> transform_signature_workaround: '%s'", str.c_str()); + int first = str.find("<"); + while ((first != -1) && (first < str.length())) { + str = str.substr(0, first) + "<" + str.substr(first + 4, str.length() - 4); + //loggers::get_instance().log("transform_signature_workaround: New str (1): '%s'", str.c_str()); + first = str.find("<"); + } // End of 'while'statement + first = str.find(">"); + while ((first != -1) && (first < str.length())) { + str = str.substr(0, first) + ">" + str.substr(first + 4, str.length() - 4); + //loggers::get_instance().log("transform_signature_workaround: New str (2): '%s'", str.c_str()); + first = str.find(">"); + } // End of 'while'statement + first = str.find("""); + while ((first != -1) && (first < str.length())) { + str = str.substr(0, first) + "'" + str.substr(first + 6, str.length() - 6); + //loggers::get_instance().log("transform_signature_workaround: New str (3): '%s'", str.c_str()); + first = str.find("""); + } // End of 'while'statement + first = str.find(" "); + while ((first != -1) && (first < str.length())) { + str = str.substr(0, first) + "\r" + str.substr(first + 5, str.length() - 5); + //loggers::get_instance().log("transform_signature_workaround: New str (4): '%s'", str.c_str()); + first = str.find(" "); + } // End of 'while'statement + + std::replace(str.begin(), str.end(), '\'', '\"'); + + loggers::get_instance().log("<<< transform_signature_workaround: '%s'", str.c_str()); + return 0; +} + +static int transform_xslt_workaround(std::string& str) { + loggers::get_instance().log(">>> transform_xslt_workaround: '%s'", str.c_str()); + + int start = str.find(""); + //loggers::get_instance().log("transform_xslt_workaround: stop='%d' ", stop); + int first = str.find("<", start); + while ((first != -1) && (first < stop)) { + //loggers::get_instance().log("transform_xslt_workaround: first='%d' ", first); + str = str.substr(0, first) + "<" + str.substr(first + 1, str.length() - 1); + //loggers::get_instance().log("transform_xslt_workaround: New str (1): '%s'", str.c_str()); + first = str.find("<", first); + stop = str.find(""); + } // End of 'while'statement + first = str.find(">", start); + while ((first != -1) && (first < stop)) { + //loggers::get_instance().log("transform_xslt_workaround: first='%d' ", first); + str = str.substr(0, first) + ">" + str.substr(first + 1, str.length() - 1); + //loggers::get_instance().log("transform_xslt_workaround: New str (1): '%s'", str.c_str()); + first = str.find(">", first); + stop = str.find(""); + } // End of 'while'statement + first = str.find("\"", start); + while ((first != -1) && (first < stop)) { + //loggers::get_instance().log("transform_xslt_workaround: first='%d' ", first); + str = str.substr(0, first) + """ + str.substr(first + 1, str.length() - 1); + //loggers::get_instance().log("transform_xslt_workaround: New str (1): '%s'", str.c_str()); + first = str.find("\"", first); + stop = str.find(""); + } // End of 'while'statement + + loggers::get_instance().log("<<< transform_xslt_workaround: '%s'", str.c_str()); + return 0; +} + +INTEGER LibSecurity__Certificates::fx__init__certs__db(const CHARSTRING& p_certs_db_path) { + loggers::get_instance().log_msg(">>> fx__init__certs__db: ", p_certs_db_path); + + int ret = _security_services->initialize(std::string(static_cast(p_certs_db_path))); + + loggers::get_instance().log("<<< fx__init__certs__db."); + return ret; +} + +INTEGER LibSecurity__Certificates::fx__load__certificate(const CHARSTRING& p_certificate_name, const CHARSTRING& p_private_key_name, const CHARSTRING& p_private_key_passwd) { + loggers::get_instance().log_msg(">>> fx__load__certificate: ", p_certificate_name); + loggers::get_instance().log_msg(">>> fx__load__certificate: ", p_private_key_name); + + const X509* certificate; + int ret = _security_services->load_certificate(std::string(static_cast(p_certificate_name)), std::string(static_cast(p_private_key_name)), std::string(static_cast(p_private_key_passwd)), &certificate); + loggers::get_instance().log("fx__load__certificate: certificate: '%p'", certificate); + if (ret == 0) { + ASN1_INTEGER* asn1_serial = ::X509_get_serialNumber((X509*)certificate); + if (asn1_serial == nullptr) { + loggers::get_instance().log("fx__load__certificate: Failed to retrieve X509 serial number"); + return -1; + } + uint64_t v; + ASN1_INTEGER_get_uint64(&v, asn1_serial); + loggers::get_instance().log("fx__load__certificate: Loaded certificate: serial number: %ld", v); + } + + loggers::get_instance().log("<<< fx__load__certificate"); + return ret; +} + +OCTETSTRING LibSecurity__Hash::fx__hash(const OCTETSTRING& p_to_be_hashed, const LibSecurity__Hash::HashAlgorithm& p_hash_algorithm) { + loggers::get_instance().log_msg(">>> fx__hash: ", p_to_be_hashed); + + OCTETSTRING hash; + switch (p_hash_algorithm) { + case LibSecurity__Hash::HashAlgorithm::e__sha1: { + sha1 s; + s.generate(p_to_be_hashed, hash); + } + break; + case LibSecurity__Hash::HashAlgorithm::e__sha256: { + sha256 s; + s.generate(p_to_be_hashed, hash); + } + break; + case LibSecurity__Hash::HashAlgorithm::e__sha384: { + sha384 s; + s.generate(p_to_be_hashed, hash); + } + break; + } // End of 'switch' statement + + loggers::get_instance().log_msg("<<< fx__hash: ", hash); + return hash; +} + +BITSTRING LibSecurity__Signature::fx__enc__xmldsig__signed__info(const http__www__w3__org__2000__09__xmldsig::Signature_signedInfo& s) { // FIXME Use enc/dec TITAN function external function f_enc_value(in Value x) return bitstring with { extension "prototype(convert) encode(abc)" } + loggers::get_instance().log(">>> fx__enc__xmldsig__signed__info"); + + TTCN_EncDec::clear_error(); + TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT); + TTCN_Buffer encoding_buffer; + + s.encode(http__www__w3__org__2000__09__xmldsig::Signature_signedInfo_descr_, encoding_buffer, TTCN_EncDec::CT_XER, XER_EXTENDED); + + // FIXME Update + std::string str(static_cast((const char*)encoding_buffer.get_data()), encoding_buffer.get_len() + static_cast((const char*)encoding_buffer.get_data())); + loggers::get_instance().log("fx__enc__xmldsig__signed__info: Before str: '%s'", str.c_str()); + transform_signature_workaround(str); + loggers::get_instance().log("fx__enc__xmldsig__signed__info: Afer str: '%s'", str.c_str()); + + OCTETSTRING os = char2oct(CHARSTRING(str.c_str())); + loggers::get_instance().log_msg("fx__enc__xmldsig__signed__info: os: ", os); + + return oct2bit(os); +} + +BITSTRING LibSecurity__Signature::fx__enc__xmldsig(const http__www__w3__org__2000__09__xmldsig::Signature& s) { // FIXME Use enc/dec TITAN function external function f_enc_value(in Value x) return bitstring with { extension "prototype(convert) encode(abc)" } + loggers::get_instance().log(">>> fx__enc__xmldsig"); + + TTCN_EncDec::clear_error(); + TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT); + TTCN_Buffer encoding_buffer; + + s.encode(http__www__w3__org__2000__09__xmldsig::Signature_descr_, encoding_buffer, TTCN_EncDec::CT_XER, XER_EXTENDED); + + // FIXME Update + std::string str(static_cast((const char*)encoding_buffer.get_data()), encoding_buffer.get_len() + static_cast((const char*)encoding_buffer.get_data())); + loggers::get_instance().log("fx__enc__xmldsig: Before str: '%s'", str.c_str()); + transform_signature_workaround(str); + loggers::get_instance().log("fx__enc__xmldsig: Afer str: '%s'", str.c_str()); + + OCTETSTRING os = char2oct(CHARSTRING(str.c_str())); + loggers::get_instance().log_msg("fx__enc__xmldsig: os: ", os); + + return oct2bit(os); +} + +INTEGER LibSecurity__Signature::fx__dec__xmldsig(BITSTRING& bs, http__www__w3__org__2000__09__xmldsig::Signature& s) { // FIXME Use enc/dec TITAN function external function f_enc_value(in Value x) return bitstring with { extension "prototype(convert) encode(abc)" } + loggers::get_instance().log(">>> fx__dec__xmldsig"); + + std::string str(static_cast(oct2char(bit2oct(bs)))); + loggers::get_instance().log("fx__dec__xmldsig: Before str: '%s'", str.c_str()); + transform_signature_workaround(str); + transform_xslt_workaround(str); + loggers::get_instance().log("fx__dec__xmldsig: Afer str: '%s'", str.c_str()); + + TTCN_EncDec::clear_error(); + TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_DEFAULT); + TTCN_Buffer decoding_buffer(OCTETSTRING(str.length(), (const unsigned char*)str.c_str())); + + s.decode(http__www__w3__org__2000__09__xmldsig::Signature_descr_, decoding_buffer, TTCN_EncDec::CT_XER, XER_EXTENDED); + + loggers::get_instance().log_msg("<<< fx__dec__xmldsig: ", s); + return 0; +} + +INTEGER LibSecurity__Signature::fx__sign(const OCTETSTRING& p_encoded_message, const OCTETSTRING& p_empty_signature, const CHARSTRING& p_certificate_name, const CHARSTRING& p_private_key_name, const CHARSTRING& p_private_key_passwd, OCTETSTRING& p_signature, OCTETSTRING& p_digest, CHARSTRING& p_x509_certificate_subject, CHARSTRING& p_x509_certificate_pem, CHARSTRING& p_pull_request_canonicalized) { + loggers::get_instance().log_msg(">>> fx__sign: ", p_encoded_message); + + if (_security_services->do_sign(p_encoded_message, p_empty_signature, p_certificate_name, p_private_key_name, p_private_key_passwd, p_signature, p_digest, p_x509_certificate_subject, p_x509_certificate_pem, p_pull_request_canonicalized) == -1) { + loggers::get_instance().log("fx__sign: Failed to signed message"); + return -1; + } + + return 0; +} + +BOOLEAN LibSecurity__Signature::fx__do__sign__verify(const CHARSTRING& p_message, const OCTETSTRING& p_empty_signature, const UNIVERSAL_CHARSTRING& p_canonicalization_method, const UNIVERSAL_CHARSTRING& p_signature_method, const UNIVERSAL_CHARSTRING& p_digest_method, const UNIVERSAL_CHARSTRING& p_digest_value, const UNIVERSAL_CHARSTRING& p_signature_value, const UNIVERSAL_CHARSTRING& p_subject_name, const UNIVERSAL_CHARSTRING& p_certificate, CHARSTRING& p_debug_message) { + loggers::get_instance().log(">>> fx__do__sign__verify"); + + if (!_security_services->do_sign_verify(p_message, p_empty_signature, p_canonicalization_method, p_signature_method, p_digest_method, p_digest_value, p_signature_value, p_subject_name, p_certificate, p_debug_message)) { + loggers::get_instance().log("fx__do__sign__verify: Failed to verify message signature"); + return false; + } + + return true; +} diff --git a/ccsrc/security/src/securty_services.cc b/ccsrc/security/src/securty_services.cc new file mode 100644 index 0000000000000000000000000000000000000000..eb459f6986850b9ae0a0aa6bf5d09daf96310f5d --- /dev/null +++ b/ccsrc/security/src/securty_services.cc @@ -0,0 +1,373 @@ +#include +#include +#include + +#include "converter.hh" + +#include "loggers.hh" + +#include "xml_converters.hh" + +#include "TTCN3.hh" + +#include "sha1.hh" +#include "sha256.hh" +#include "sha384.hh" +#include "certs_loader.hh" +#include "security_services.hh" + +certs_db* security_services::_certs_db = nullptr; + +int security_services::initialize(const std::string& p_certs_db_path) { + loggers::get_instance().log(">>> security_services::initialize: '%s'", p_certs_db_path.c_str()); + + security_services::_certs_db = new certs_db(p_certs_db_path); + if (security_services::_certs_db == nullptr) { // Memory allocation issue + loggers::get_instance().warning("security_services::initialize: _security_db pointer is NULL"); + return -1; + } + + loggers::get_instance().log("<<< security_services::initialize"); + return 0; +} + +int security_services::load_certificate(const std::string& p_certificate_name, const std::string& p_private_key_name, const std::string& p_private_key_passwd, const X509** p_certificate) { + loggers::get_instance().log("security_services::load_certificate: '%s'", p_certificate_name.c_str()); + loggers::get_instance().log("security_services::load_certificate: '%s'", p_private_key_name.c_str()); + loggers::get_instance().log("security_services::load_certificate: '%s'", p_private_key_passwd.c_str()); + + return _certs_db->get_certificate(p_certificate_name, p_private_key_name, p_private_key_passwd, p_certificate); +} + +int security_services::do_sign(const OCTETSTRING& p_encoded_message, const OCTETSTRING& p_empty_signature, const CHARSTRING& p_certificate_name, const CHARSTRING& p_private_key_name, const CHARSTRING& p_private_key_passwd, OCTETSTRING& p_signature, OCTETSTRING& p_digest, CHARSTRING& p_x509_certificate_subject, CHARSTRING& p_x509_certificate_pem, CHARSTRING& p_pull_request_canonicalized) { + loggers::get_instance().log_msg(">>> security_services::do_sign: ", p_encoded_message); + loggers::get_instance().log_msg(">>> security_services::do_sign: ", p_empty_signature); + loggers::get_instance().log_msg(">>> security_services::do_sign: ", p_certificate_name); + loggers::get_instance().log_msg(">>> security_services::do_sign: ", p_private_key_name); + loggers::get_instance().log_msg(">>> security_services::do_sign: ", p_private_key_passwd); + + // Transform and canonicalize the message + // Transform: Remove all CR, LS, TAB and SPACE outside of the tags + std::string transformed; + xml_converters::get_instance().xml_transform(std::string((const char*)(static_cast(p_encoded_message)), p_encoded_message.lengthof()), transformed); + loggers::get_instance().log("security_services::do_sign: p_pull_request_transormed: '%s'", transformed.c_str()); + // Canonicalization + std::string canonicalized; + xml_converters::get_instance().xml_canonicalization(transformed, canonicalized); + loggers::get_instance().log("security_services::do_sign: canonicalized: '%s'", canonicalized.c_str()); + p_pull_request_canonicalized = CHARSTRING(canonicalized.c_str()); + OCTETSTRING encoded_message(char2oct(p_pull_request_canonicalized)); + loggers::get_instance().log_msg("security_services::do_sign: p_pull_request_canonicalized: ", p_pull_request_canonicalized); + + // Transform and canonicalize the empty signature + // Transform: Remove all CR, LS, TAB and SPACE outside of the tags + transformed.clear(); + xml_converters::get_instance().xml_transform(std::string((const char*)(static_cast(p_empty_signature)), p_empty_signature.lengthof()), transformed); + loggers::get_instance().log("security_services::do_sign: p_empty_signature transormed: '%s'", transformed.c_str()); + // Canonicalization + canonicalized.clear(); + xml_converters::get_instance().xml_canonicalization(transformed, canonicalized); + loggers::get_instance().log("security_services::do_sign: p_empty_signature canonicalized: '%s'", canonicalized.c_str()); + + // Compute the digest of the transformed/canonicalized message + loggers::get_instance().log_msg("security_services::do_sign: compute digest for ", p_pull_request_canonicalized); + int first = canonicalized.find("xmldsig#sha1"); + loggers::get_instance().log("security_services::do_sign: p_empty_signature first: '%d'", first); + const EVP_MD* sign_digest; + if (first != -1) { + sha1 digest; + digest.generate(char2oct(p_pull_request_canonicalized), p_digest); + sign_digest = EVP_sha1(); + } else { + first = canonicalized.find("xmldsig#sha256"); + loggers::get_instance().log("security_services::do_sign: p_empty_signature first: '%d'", first); + if (first != -1) { + sha256 digest; + digest.generate(char2oct(p_pull_request_canonicalized), p_digest); + sign_digest = EVP_sha256(); + } else { + first = canonicalized.find("xmldsig#sha384"); + loggers::get_instance().log("security_services::do_sign: p_empty_signature first: '%d'", first); + if (first != -1) { + sha384 digest; + digest.generate(char2oct(p_pull_request_canonicalized), p_digest); + sign_digest = EVP_sha384(); + } else { + loggers::get_instance().error("security_services::do_sign: Unsupported digest"); + } + } + } + loggers::get_instance().log_msg("security_services::do_sign: digest: ", p_digest); + std::vector to64 = converter::get_instance().buffer_to_base64(std::vector(static_cast(p_digest), p_digest.lengthof() + static_cast(p_digest))); + p_digest = OCTETSTRING(to64.size(), to64.data()); + loggers::get_instance().log_msg("security_services::do_sign: digest (64): ", p_digest); + + // Retrieve certificate + std::string certificate_id; + if (certs_loader::get_instance().get_certificate_id(std::string(static_cast(p_certificate_name)), certificate_id) != 0) { + loggers::get_instance().warning("security_services::do_sign: Failed to retrieve certificate identifier"); + return -1; + } + loggers::get_instance().log("security_services::do_sign: certificate_id: '%s'", certificate_id.c_str()); + const X509* certificate; + if (_certs_db->get_certificate(certificate_id, &certificate) != 0) { + loggers::get_instance().warning("security_services::do_sign: Failed to retrieve certificate"); + return -1; + } + loggers::get_instance().log("security_services::do_sign: certificate dump: '%s'", _certs_db->cert_to_string(certificate_id).c_str()); + X509_NAME* sn = X509_get_subject_name((X509*)certificate); + std::string subject(512, (char)0x00); + ::X509_NAME_oneline(sn, (char*)subject.c_str(), subject.length()); + loggers::get_instance().log("security_services::do_sign: X509_NAME_oneline: '%s'", subject.c_str()); + p_x509_certificate_subject = CHARSTRING(subject.c_str()); + + std::string str; + if (_certs_db->get_certificate_pem(certificate_id, str) != 0) { + loggers::get_instance().warning("security_services::do_sign: Failed to retrieve certificate PEM"); + return -1; + } + p_x509_certificate_pem = CHARSTRING(str.c_str()); + + // Update the signature + int i = canonicalized.find(""); + canonicalized = canonicalized.substr(0, i + 13) + std::string(to64.cbegin(), to64.cend()) + canonicalized.substr(i + 13, canonicalized.length() - i - 13); + OCTETSTRING to_be_signed(char2oct(CHARSTRING(canonicalized.c_str()))); + loggers::get_instance().log_msg("security_services::do_sign: to_be_signed: ", to_be_signed); + to64 = converter::get_instance().buffer_to_base64(std::vector(static_cast(to_be_signed), to_be_signed.lengthof() + static_cast(to_be_signed))); + loggers::get_instance().log("security_services::do_sign: Data to be signed/verified: '%s'", converter::get_instance().bytes_to_string(to64).c_str()); + + // Retrieve the private key + const EVP_PKEY* private_key; + int ret = _certs_db->get_private_key(certificate_id, &private_key); + if (ret == 1) { + loggers::get_instance().warning("security_services::do_sign: Failed to retrieve private key"); + return -1; + } + loggers::get_instance().log("security_services::do_sign: private_key: '%p'", private_key); + + // Create signing context to sign the updated signature + EVP_MD_CTX* ctx = ::EVP_MD_CTX_new(); + if (ctx == NULL) { + loggers::get_instance().warning("security_services::do_sign: EVP_MD_CTX_create failed, error 0x%lx", ::ERR_get_error()); + return -1; + } + if (::EVP_DigestSignInit(ctx, NULL, sign_digest, NULL, (EVP_PKEY*)private_key) != 1) { // FIXME Add parameter to chose the digest algorithm + loggers::get_instance().warning("security_services::do_sign: EVP_DigestSignInit failed, error 0x%lx", ::ERR_get_error()); + ::EVP_MD_CTX_free(ctx); + return -1; + } + if (::EVP_DigestSignUpdate(ctx, (const unsigned char*)canonicalized.c_str(), canonicalized.length()) != 1) { + loggers::get_instance().warning("security_services::do_sign: EVP_DigestSignUpdate failed, error 0x%lx", ::ERR_get_error()); + ::EVP_MD_CTX_free(ctx); + return -1; + } + // Get signature lengthof + size_t signature_length = 0; + if (::EVP_DigestSignFinal(ctx, NULL, &signature_length) != 1) { + loggers::get_instance().warning("security_services::do_sign: EVP_DigestSignUpdate failed, error 0x%lx", ::ERR_get_error()); + ::EVP_MD_CTX_free(ctx); + return -1; + } + if (signature_length != ::EVP_PKEY_size(private_key)) { + loggers::get_instance().warning("security_services::do_sign: Wrong signature length"); + ::EVP_MD_CTX_free(ctx); + return -1; + } + loggers::get_instance().log("security_services::do_sign: signature_length: %d", signature_length); + std::vector s(signature_length, 0x00); + if (::EVP_DigestSignFinal(ctx, s.data(), &signature_length) != 1) { + loggers::get_instance().warning("security_services::do_sign: EVP_DigestSignUpdate failed, error 0x%lx", ::ERR_get_error()); + ::EVP_MD_CTX_free(ctx); + s.clear(); + return -1; + } + ::EVP_MD_CTX_free(ctx); + + // // Ensure that the signature round-trips + // // Retrieve the public key + // const EVP_PKEY* public_key; + // if (_certs_db->get_private_key(certificate_id, &public_key) == 1) { + // loggers::get_instance().warning("security_services::do_sign: Failed to retrieve private key"); + // return -1; + // } + // loggers::get_instance().log("security_services::do_sign: public_key: '%p'", public_key); + // std::vector buffer; + // _certs_db->publickey_to_string(public_key, buffer); + // ctx = ::EVP_MD_CTX_new(); + // if (!::EVP_DigestVerifyInit(ctx, NULL, sign_digest, NULL, (EVP_PKEY*)public_key) || + // !::EVP_DigestVerifyUpdate(ctx, (const unsigned char*)canonicalized.c_str(), canonicalized.length()) || + // !::EVP_DigestVerifyFinal(ctx, s.data(), s.size())) { + // loggers::get_instance().warning("security_services::do_sign: Failed to verify signature, error 0x%lx", ::ERR_get_error()); + // ::EVP_MD_CTX_free(ctx); + // s.clear(); + // return -1; + // } + //::EVP_MD_CTX_free(ctx); + //loggers::get_instance().log("security_services::do_sign: signature was verified with public key"); + + p_signature = OCTETSTRING(signature_length, s.data()); + loggers::get_instance().log_msg("security_services::do_sign: signature: ", p_signature); + to64 = converter::get_instance().buffer_to_base64(std::vector(static_cast(p_signature), p_signature.lengthof() + static_cast(p_signature))); + p_signature = OCTETSTRING(to64.size(), to64.data()); + loggers::get_instance().log_msg("security_services::do_sign: signature (64): ", p_signature); + + loggers::get_instance().log_msg("<<< security_services::do_sign: signature: ", p_signature); + + return 0; +} + +bool security_services::do_sign_verify(const CHARSTRING& p_message, const OCTETSTRING& p_empty_signature, const UNIVERSAL_CHARSTRING& p_canonicalization_method, const UNIVERSAL_CHARSTRING& p_signature_method, const UNIVERSAL_CHARSTRING& p_digest_method, const UNIVERSAL_CHARSTRING& p_digest_value, const UNIVERSAL_CHARSTRING& p_signature_value, const UNIVERSAL_CHARSTRING& p_subject_name, const UNIVERSAL_CHARSTRING& p_certificate, CHARSTRING& p_debug_message) { + loggers::get_instance().log_msg(">>> security_services::do_sign_verify: p_message: ", p_message); + loggers::get_instance().log_msg(">>> security_services::do_sign_verify: p_debug_message: ", p_debug_message); + loggers::get_instance().log_msg(">>> security_services::do_sign_verify: p_canonicalization_method: ", p_canonicalization_method); + loggers::get_instance().log_msg(">>> security_services::do_sign_verify: p_subject_name: ", p_subject_name); + loggers::get_instance().log_msg(">>> security_services::do_sign_verify: p_signature_method: ", p_signature_method); + + // Transform and canonicalize the message + // Transform: Remove all CR, LS, TAB and SPACE outside of the tags + std::string transformed; + xml_converters::get_instance().xml_transform(std::string(static_cast(p_message)), transformed); + loggers::get_instance().log("security_services::do_sign_verify: p_message_transormed: ", transformed.c_str()); + // Canonicalization + std::string canonicalized; + xml_converters::get_instance().xml_canonicalization(transformed, canonicalized); + CHARSTRING v_pull_request_canonicalized(canonicalized.c_str()); + p_debug_message = v_pull_request_canonicalized; + //OCTETSTRING v_pull_request_canonicalized(char2oct(p_debug_message)); + loggers::get_instance().log_msg("security_services::do_sign_verify: p_debug_message: ", p_debug_message); + + // Transform and canonicalize the empty signature + // Transform: Remove all CR, LS, TAB and SPACE outside of the tags + transformed.clear(); + xml_converters::get_instance().xml_transform(std::string((const char*)(static_cast(p_empty_signature)), p_empty_signature.lengthof()), transformed); + loggers::get_instance().log("security_services::do_sign_verify: p_empty_signature transormed: '%s'", transformed.c_str()); + // Canonicalization + canonicalized.clear(); + xml_converters::get_instance().xml_canonicalization(transformed, canonicalized); + loggers::get_instance().log("security_services::do_sign_verify: p_empty_signature canonicalized: '%s'", canonicalized.c_str()); + + // Compute the digest of the transformed/canonicalized message + loggers::get_instance().log_msg("security_services::do_sign_verify: compute digest for ", v_pull_request_canonicalized); + int first = canonicalized.find("xmldsig#sha1"); + loggers::get_instance().log("security_services::do_sign_verify: p_empty_signature first: '%d'", first); + OCTETSTRING dg; + const EVP_MD* sign_digest; + if (first != -1) { + sha1 digest; + digest.generate(char2oct(v_pull_request_canonicalized), dg); + sign_digest = EVP_sha1(); + } else { + first = canonicalized.find("xmldsig#sha256"); + loggers::get_instance().log("security_services::do_sign_verify: p_empty_signature first: '%d'", first); + if (first != -1) { + sha256 digest; + digest.generate(char2oct(v_pull_request_canonicalized), dg); + sign_digest = EVP_sha256(); + } else { + first = canonicalized.find("xmldsig#sha384"); + loggers::get_instance().log("security_services::do_sign_verify: p_empty_signature first: '%d'", first); + if (first != -1) { + sha384 digest; + digest.generate(char2oct(v_pull_request_canonicalized), dg); + sign_digest = EVP_sha384(); + } else { + loggers::get_instance().error("security_services::do_sign_verify: Unsupported digest"); + } + } + } + loggers::get_instance().log_msg("security_services::do_sign_verify: digest: ", dg); + std::vector to64 = converter::get_instance().buffer_to_base64(std::vector(static_cast(dg), dg.lengthof() + static_cast(dg))); + loggers::get_instance().log_msg("security_services::do_sign_verify: digest (64): ", OCTETSTRING(to64.size(), to64.data())); + + // Retrieve certificate + std::string sn(static_cast(unichar2char(p_subject_name))); + std::string certificate_id; + const X509* certificate; + if (_certs_db->get_certificate_by_subject_name(sn, &certificate) != 0) { + loggers::get_instance().warning("security_services::do_sign_verify: Failed to retrieve certificate"); + // Use provided certificate if any + loggers::get_instance().log("security_services::do_sign_verify: sn='%s'", sn.c_str()); + size_t i = sn.find("CN="); + if (i == std::string::npos) { + loggers::get_instance().warning("security_services::do_sign_verify: Failed to extract certificate name"); + return false; + } + size_t j = sn.find(",", i + 3); + std::string certificate_name; + if (j == std::string::npos) { + certificate_name = sn.substr(i + 3); + } else { + certificate_name = sn.substr(i + 3, j - i - 3); + } + certificate_name = converter::get_instance().replace(certificate_name, "-", "_"); + loggers::get_instance().log("security_services::do_sign_verify: certificate name: '%s'", certificate_name.c_str()); + const certs_db_record* record; + if (_certs_db->store_certificate(certificate_name, std::string(static_cast(unichar2char(p_certificate))), certificate_id, &record) == -1) { + loggers::get_instance().warning("security_services::do_sign_verify: Failed to store certificate"); + return false; + } + loggers::get_instance().log("security_services::do_sign_verify: certificate id: '%s'", record->certificate_id().c_str()); + } + loggers::get_instance().log("security_services::do_sign_verify: certificate dump: '%s'", _certs_db->cert_to_string(certificate_id).c_str()); + + // Retrieve the public key + const EVP_PKEY* public_key; + int ret = _certs_db->get_public_keys(certificate_id, &public_key); + if (ret == 1) { + loggers::get_instance().warning("security_services::do_sign_verify: Failed to retrieve public key"); + return false; + } + loggers::get_instance().log("security_services::do_sign_verify: public_key: '%p'", public_key); + std::vector buffer; + ret = _certs_db->publickey_to_string(public_key, buffer); + if (ret == 1) { + loggers::get_instance().warning("security_services::do_sign_verify: Failed to convert public key into string"); + return false; + } + + // Update the DigestValue + loggers::get_instance().log("security_services::do_sign_verify: canonicalized: '%s'", canonicalized.c_str()); + int i = canonicalized.find(""); + if (i == std::string::npos) { + loggers::get_instance().warning("security_services::do_sign_verify: DigestValue entry not found"); + return false; + } + loggers::get_instance().log("security_services::do_sign_verify: i='%d'", i); + canonicalized = canonicalized.substr(0, i + 13) + std::string(to64.cbegin(), to64.cend()) + canonicalized.substr(i + 13, canonicalized.length() - i - 13); + OCTETSTRING to_be_signed(char2oct(CHARSTRING(canonicalized.c_str()))); + loggers::get_instance().log_msg("security_services::do_sign_verify: to_be_signed: ", to_be_signed); + to64 = converter::get_instance().buffer_to_base64(std::vector(static_cast(to_be_signed), to_be_signed.lengthof() + static_cast(to_be_signed))); + loggers::get_instance().log("security_services::do_sign_verify: Data to be signed/verified: '%s'", converter::get_instance().bytes_to_string(to64).c_str()); + + // Convert signature + std::string signature_value(static_cast(unichar2char(p_signature_value))); + // Remove CR/LF if any + //signature_value.erase(std::remove(signature_value.begin(), signature_value.end(), '\r'), signature_value.end()); + //signature_value.erase(std::remove(signature_value.begin(), signature_value.end(), '\n'), signature_value.end()); + loggers::get_instance().log("security_services::do_sign_verify: Before B64 decoded: '%s'", signature_value.c_str()); + // Convert into bytes buffer + const std::vector to_decode((const unsigned char*)signature_value.c_str(), static_cast((const unsigned char*)signature_value.c_str() + signature_value.length())); + std::vector s = converter::get_instance().base64_to_buffer(to_decode); + loggers::get_instance().log("security_services::do_sign_verify: B64 decoded: '%s'", converter::get_instance().bytes_to_hexa(s, true).c_str()); + loggers::get_instance().log("security_services::do_sign_verify: B64 decoded len: '%d'", s.size()); + + // Create signing context + EVP_MD_CTX* ctx = ::EVP_MD_CTX_new(); + if (ctx == NULL) { + loggers::get_instance().warning("security_services::do_sign_verify: EVP_MD_CTX_create failed, error 0x%lx", ::ERR_get_error()); + return false; + } + // Check signature + if (!::EVP_DigestVerifyInit(ctx, NULL, sign_digest, NULL, (EVP_PKEY*)public_key) || + !::EVP_DigestVerifyUpdate(ctx, (const unsigned char*)canonicalized.c_str(), canonicalized.length()) || + !::EVP_DigestVerifyFinal(ctx, s.data(), s.size())) { + loggers::get_instance().warning("security_services::do_sign_verify: Failed to verify signature, error 0x%lx", ::ERR_get_error()); + ::EVP_MD_CTX_free(ctx); + s.clear(); + return false; + } + ::EVP_MD_CTX_free(ctx); + loggers::get_instance().log("security_services::do_sign_verify: signature was verified with public key"); + + return true; +} diff --git a/ccsrc/security/src/sha1.cc b/ccsrc/security/src/sha1.cc new file mode 100644 index 0000000000000000000000000000000000000000..21b051410669f6463093ef418ef8ba85915be1d0 --- /dev/null +++ b/ccsrc/security/src/sha1.cc @@ -0,0 +1,39 @@ +/*! + * \file sha1.cc + * \brief Source file for SHA-1 helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#include + +#include "sha1.hh" + +int sha1::generate(const OCTETSTRING& p_buffer, OCTETSTRING& p_hash) { + // Sanity check + if (p_buffer.lengthof() == 0) { + p_hash = get_sha1_empty_string(); + return 0; + } + + return generate(static_cast(p_buffer), p_buffer.lengthof(), p_hash); +} + +int sha1::generate(const unsigned char* p_buffer, const size_t p_length, OCTETSTRING& p_hash) { + // Sanity check + if ((p_buffer == nullptr) || (p_length == 0)) { + p_hash = get_sha1_empty_string(); + return 0; + } + + // Resize data buffer + p_hash = int2oct(0, SHA_DIGEST_LENGTH); + // Compute the hash value + ::SHA1_Init(&_ctx); + ::SHA1_Update(&_ctx, p_buffer, p_length); + ::SHA1_Final((unsigned char*)static_cast(p_hash), &_ctx); + return 0; +}; diff --git a/ccsrc/security/src/sha256.cc b/ccsrc/security/src/sha256.cc new file mode 100644 index 0000000000000000000000000000000000000000..2238f0973236d5f43ddd9c53cc1a4213adf9c19b --- /dev/null +++ b/ccsrc/security/src/sha256.cc @@ -0,0 +1,39 @@ +/*! + * \file sha256.cc + * \brief Source file for SHA-256 helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#include + +#include "sha256.hh" + +int sha256::generate(const OCTETSTRING& p_buffer, OCTETSTRING& p_hash) { + // Sanity check + if (p_buffer.lengthof() == 0) { + p_hash = get_sha256_empty_string(); + return 0; + } + + return generate(static_cast(p_buffer), p_buffer.lengthof(), p_hash); +} + +int sha256::generate(const unsigned char* p_buffer, const size_t p_length, OCTETSTRING& p_hash) { + // Sanity check + if ((p_buffer == nullptr) || (p_length == 0)) { + p_hash = get_sha256_empty_string(); + return 0; + } + + // Resize data buffer + p_hash = int2oct(0, SHA256_DIGEST_LENGTH); + // Compute the hash value + ::SHA256_Init(&_ctx); + ::SHA256_Update(&_ctx, p_buffer, p_length); + ::SHA256_Final((unsigned char*)static_cast(p_hash), &_ctx); + return 0; +}; diff --git a/ccsrc/security/src/sha384.cc b/ccsrc/security/src/sha384.cc new file mode 100644 index 0000000000000000000000000000000000000000..b32e4c252555d3044c10d45a3f30291939bdceca --- /dev/null +++ b/ccsrc/security/src/sha384.cc @@ -0,0 +1,47 @@ +/*! + * \file sha384.cc + * \brief Sorce file for SHA-384 helper methods. + * \author ETSI STF637 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#include + +#include "sha384.hh" + +int sha384::generate(const OCTETSTRING &p_buffer, OCTETSTRING &p_hash) { + // Sanity check + if (p_buffer.lengthof() == 0) { + p_hash = get_sha384_empty_string(); + return 0; + } + + return generate(static_cast(p_buffer), p_buffer.lengthof(), p_hash); +} + +int sha384::generate(const unsigned char *p_buffer, const size_t p_length, OCTETSTRING &p_hash) { + // Sanity check + if ((p_buffer == nullptr) || (p_length == 0)) { + p_hash = get_sha384_empty_string(); + return 0; + } + + // Resize data buffer + p_hash = int2oct(0, SHA384_DIGEST_LENGTH); + // Compute the hash value + ::SHA384_Init(&_ctx); + ::SHA384_Update(&_ctx, p_buffer, p_length); + ::SHA384_Final((unsigned char *)static_cast(p_hash), &_ctx); + return 0; +} + +const OCTETSTRING sha384::get_sha384_empty_string() const { + static unsigned char + sha384_empty_string[] = {0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, + 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, + 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b}; //! SHA-384 of an empty string + return OCTETSTRING(48, sha384_empty_string); +} diff --git a/ttcn/LibHelpers/module.mk b/ttcn/LibHelpers/module.mk index f56baa1fef8bb060de060807beb7eaabbfe06155..3012e9ec294564dc8a314708af657cc350d8f19f 100644 --- a/ttcn/LibHelpers/module.mk +++ b/ttcn/LibHelpers/module.mk @@ -1,3 +1,2 @@ sources := \ ttcn/LibHelpers_Functions.ttcn - diff --git a/ttcn/LibHelpers/ttcn/LibHelpers_Functions.ttcn b/ttcn/LibHelpers/ttcn/LibHelpers_Functions.ttcn index 0ee138ba7330f79285f3b52f0369820f0780d73c..b5c6bd5f6c21a4cd4206ee5176f6c42ff75be37c 100644 --- a/ttcn/LibHelpers/ttcn/LibHelpers_Functions.ttcn +++ b/ttcn/LibHelpers/ttcn/LibHelpers_Functions.ttcn @@ -9,14 +9,14 @@ * All rights reserved. * */ - + module LibHelpers_Functions { // LibCommon import from LibCommon_BasicTypesAndValues all; - + group math { - + /** * @desc function to generate integer random values * @see ttcn-3 - rnd() @@ -25,16 +25,17 @@ module LibHelpers_Functions { * @return random integer * */ - function f_random( in integer p_lowerbound, - in integer p_upperbound ) - return integer { + function f_random( + in integer p_lowerbound, + in integer p_upperbound + ) return integer { //Variables var integer v_random := 0; - v_random := float2int(int2float(p_upperbound - p_lowerbound +1)*rnd()) + p_lowerbound; - + v_random := float2int(int2float(p_upperbound - p_lowerbound + 1) * rnd()) + p_lowerbound; + log("*** f_random: INFO: OK - random value = " & int2str(v_random) & " ***"); return v_random; - + } // End of function f_random /** @@ -44,7 +45,7 @@ module LibHelpers_Functions { */ function f_abs(in integer p_number) return integer { - + if(p_number < 0) { return 0 - p_number; } @@ -58,7 +59,7 @@ module LibHelpers_Functions { */ function ff_abs(in float p_number) return float { - + if(p_number < 0.0) { return 0.0 - p_number; } @@ -73,7 +74,7 @@ module LibHelpers_Functions { */ function f_min(in integer p_a, in integer p_b) return integer { - + if(p_a < p_b) { return p_a; } @@ -90,7 +91,7 @@ module LibHelpers_Functions { function f_removeUnsignificantBits(in bitstring p_bitstring) return bitstring { var integer i, len; - + len := lengthof(p_bitstring); for(i:=len-1; i >=0 and p_bitstring[i] == '0'B; i:=i-1) {} return substr(p_bitstring, 0, i + 1); @@ -105,61 +106,86 @@ module LibHelpers_Functions { */ function f_getCurrentTimeUtc() return UInt64 { var UInt64 v_time := 0; - + // log("*** f_getCurrentTimeUtc: INFO: calling fx_getCurrentTimeUtc() ***"); v_time := fx_getCurrentTimeUtc(); - + return v_time; } - + /** * @desc Gets the Minute of current UTC year * @return MinuteOfTheYear - tenths of a second in the current or next hour in units of 1/10th second from UTC time */ function f_getMinuteOfTheYear() return UInt16 { var UInt16 v_minuteOfTheYear := 0; - + // log("*** f_getMinuteOfTheYear: INFO: calling fx_getMinuteOfTheYear() ***"); v_minuteOfTheYear := fx_getMinuteOfTheYear(); - + return v_minuteOfTheYear; } - + /** * @desc Gets the milliseconds point in the current UTC minute * @return DSecond - The milliseconds point in the current UTC minute (0..60000) */ function f_getDSecond() return UInt16 { var UInt16 v_dSecond := 0; - + // log("*** f_getDSecond: INFO: calling fx_getDSecond() ***"); v_dSecond := fx_getDSecond(); - + return v_dSecond; } - + } // End of group datetime - + group externals { - + /** * @desc Gets the current time since 01/01/1970 in UTC format * @return The current time since 01/01/1970 in UTC format */ external function fx_getCurrentTimeUtc() return UInt64; - + /** * @desc Gets the minutes of current UTC year * @return MinuteOfTheYear - minutes of current UTC year */ external function fx_getMinuteOfTheYear() return UInt16; - + /** * @desc Gets the milliseconds point in the current UTC minute * @return DSecond - the milliseconds point in the current UTC minute */ external function fx_getDSecond() return UInt16; - + + /** + * @desc Encode into Base64 + * @return p_to_encode - The buffer to be encoded + */ + external function fx_enc_base64(in octetstring p_to_encode) return octetstring; + + /** + * @desc Decode from Base64 + * @return p_to_decode - The buffer to be decoded + */ + external function fx_dec_base64(in octetstring p_to_decode) return octetstring; + + /** + * @desc Generate a new UUID + * @return The UUID in string format on success, a null string otherwise + */ + external function fx_generate_uuid() return charstring; + + /** + * @brief Retrieve the current local date/time formatted as yyyy-mm-ddThh:mm:ss.lll+nn:00 + * @param p_shift_time The algebric number of seconds to add to the current time + * @return The the current date/time on success, a null string otherwise + */ + external function fx_get_current_date_time(in integer p_shift_time) return charstring; + } // End of externals } // End of module LibHelpers_Functions diff --git a/ttcn/LibHttp/module_cise.mk b/ttcn/LibHttp/module_cise.mk new file mode 100644 index 0000000000000000000000000000000000000000..481167566d517f742fcbcc71ec74d52f17edc14a --- /dev/null +++ b/ttcn/LibHttp/module_cise.mk @@ -0,0 +1,19 @@ +sources := \ + ttcn/LibHttp_BinaryMessageBodyTypes.ttcn \ + ttcn/LibHttp_EncdecDeclarations.ttcn \ + ttcn/LibHttp_Functions.ttcn \ + ttcn/LibHttp_JSONTypes.ttcn \ + ttcn/LibHttp_MessageBodyTypes.ttcn \ + ttcn/LibHttp_Pics.ttcn \ + ttcn/LibHttp_Pixits.ttcn \ + ttcn/LibHttp_Templates.ttcn \ + ttcn/LibHttp_TestSystem.ttcn \ + ttcn/LibHttp_TypesAndValues.ttcn \ + ttcn/LibHttp_XMLTypes.ttcn \ + + +# Please, move and comment the module you need to overwrite tofit your project +# ttcn/LibHttp_XmlMessageBodyTypes.ttcn \ +# ttcn/LibHttp_XmlTemplates.ttcn +# ttcn/LibHttp_JsonMessageBodyTypes.ttcn \ +# ttcn/LibHttp_JsonTemplates.ttcn \ diff --git a/ttcn/LibHttp/ttcn/LibHttp_BinaryMessageBodyTypes.ttcn b/ttcn/LibHttp/ttcn/LibHttp_BinaryMessageBodyTypes.ttcn index 76a8b86351c0530da11b2b131dc7bb514891012f..a8dd96a16522b539d4432743d0ace39b4e2292c1 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_BinaryMessageBodyTypes.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_BinaryMessageBodyTypes.ttcn @@ -22,7 +22,7 @@ module LibHttp_BinaryMessageBodyTypes { } with { variant "" } - + } with { variant "" } // End of LibHttp_BinaryMessageBodyTypes diff --git a/ttcn/LibHttp/ttcn/LibHttp_BinaryTypes.ttcn b/ttcn/LibHttp/ttcn/LibHttp_BinaryTypes.ttcn index 2606857d40c3b09600e1282c90f35bb9023fa213..761a9b1956c6e8e5ddd7c62457d57b0b3e42c82d 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_BinaryTypes.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_BinaryTypes.ttcn @@ -1,9 +1,9 @@ module LibHttp_BinaryTypes { // FIXME To be removed - + /** * This file is volontary empry. You have to declare all XSD files required by your project * In addition, the TTCN-3 module LibHttp_XmlMessageBodyTypes have to be updated too. */ // TODO Add here your custom binary import - + } // End of module LibHttp_BinaryTypes diff --git a/ttcn/LibHttp/ttcn/LibHttp_EncdecDeclarations.ttcn b/ttcn/LibHttp/ttcn/LibHttp_EncdecDeclarations.ttcn index e7eb077242973b7d058950f47d9b18d86dc905a8..23ea56a393b09994edc59c5c4d58ac3f37f54500 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_EncdecDeclarations.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_EncdecDeclarations.ttcn @@ -1,11 +1,11 @@ module LibHttp_EncdecDeclarations { // LibHttp import from LibHttp_TypesAndValues all; - + external function fx_enc_http_message (HttpMessage p) return bitstring with {extension "prototype(convert) encode(HttpCodec)"} - + external function fx_dec_http_message (inout bitstring b, out HttpMessage p) return integer with {extension "prototype(sliding) decode(HttpCodec)"} - + } // End of module LibHttp_EncdecDeclarations diff --git a/ttcn/LibHttp/ttcn/LibHttp_Functions.ttcn b/ttcn/LibHttp/ttcn/LibHttp_Functions.ttcn index 3a4e457fbbf46362cf3a19008e71359a0863d286..b329dca8cd2eb256ab57984f247ed1ff2c838cb3 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_Functions.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_Functions.ttcn @@ -1,87 +1,87 @@ module LibHttp_Functions { - + // LibCommon import from LibCommon_Time all; import from LibCommon_VerdictControl all; import from LibCommon_Sync all; - + // LibHttp import from LibHttp_TypesAndValues all; import from LibHttp_Templates all; import from LibHttp_Pics all; import from LibHttp_Pixits all; import from LibHttp_TestSystem all; - + group preambles { - + /** * @desc Setup HTTP pprotocol port */ function f_cf_01_http_up() runs on HttpComponent { - + // Map ports map(self:httpPort, system:httpPort); - + // Connect f_connect4SelfOrClientSync(); - + activate(a_cf_01_http_down()); activate(a_default_requests()); activate(a_default_responses()); - + } // End of function f_cf_01_http_up - + /** * @desc Setup HTTP pprotocol port */ function f_cf_01_http_notif_up() runs on HttpComponent { - + // Map ports map(self:httpPort, system:httpPort); map(self:httpPort_notif, system:httpPort_notif); - + // Connect f_connect4SelfOrClientSync(); - + activate(a_cf_01_http_notif_down()); activate(a_default_requests()); activate(a_default_responses()); - + } // End of function f_cf_01_http_notif_up - + } // End of group preambles - + group postambles { - + /** * @desc Shutdown HTTP pprotocol port */ function f_cf_01_http_down() runs on HttpComponent { - + // Unmap ports unmap(self:httpPort, system:httpPort); - + // Disconnect ports f_disconnect4SelfOrClientSync(); - + deactivate; } // End of function f_cf_01_http_down - + /** * @desc Shutdown HTTP pprotocol port */ function f_cf_01_http_notif_down() runs on HttpComponent { - + // Unmap ports unmap(self:httpPort, system:httpPort); unmap(self:httpPort_notif, system:httpPort_notif); - + // Disconnect ports f_disconnect4SelfOrClientSync(); - + deactivate; } // End of function f_cf_01_http_notif_down - + /** * @desc Default handling cf01 de-initialisation. */ @@ -92,7 +92,7 @@ module LibHttp_Functions { stop; } } // End of altstep a_cf_01_http_down - + /** * @desc Default handling cf01 de-initialisation. */ @@ -103,18 +103,18 @@ module LibHttp_Functions { stop; } } // End of altstep a_cf_01_http_notif_down - + } // End of group postambles - + group http_headers { - + function f_init_default_headers_list( in charstring p_header_content_type := PICS_HEADER_CONTENT_TYPE, in charstring p_header_content_text := "", out Headers p_headers ) { var integer v_i := 0; - + p_headers[v_i] := { c_header_host, { PICS_HEADER_HOST } }; v_i := v_i + 1; p_headers[v_i] := { c_header_content_type, { p_header_content_type } }; @@ -140,7 +140,7 @@ module LibHttp_Functions { f_set_headers_list(PX_ADDITIONAL_HTTP_HEADERS_KEYS, PX_ADDITIONAL_HTTP_HEADERS_VALUES, p_headers); } } // End of function f_init_default_headers_list - + function f_set_headers_list( in charstring_list p_headers_to_set, in charstring_list p_headers_value, @@ -152,7 +152,7 @@ module LibHttp_Functions { } else if (lengthof(p_headers) == 0) { return; } - + for (var integer v_idx := 0; v_idx < lengthof(p_headers_to_set); v_idx := v_idx + 1) { var integer v_jdx; for (v_jdx := 0; v_jdx < lengthof(p_headers); v_jdx := v_jdx + 1) { @@ -167,7 +167,7 @@ module LibHttp_Functions { } } // End of 'for' statement } // End of function f_set_headers_list - + function f_remove_headers_list( in charstring_list p_headers_to_remove, inout Headers p_headers @@ -178,7 +178,7 @@ module LibHttp_Functions { } else if (lengthof(p_headers) == 0) { return; } - + for (var integer v_idx := 0; v_idx < lengthof(p_headers_to_remove); v_idx := v_idx + 1) { for (var integer v_jdx := 0; v_jdx < lengthof(p_headers); v_jdx := v_jdx + 1) { if (p_headers[v_jdx].header_name == p_headers_to_remove[v_idx]) { @@ -188,19 +188,19 @@ module LibHttp_Functions { } // End of 'for' statement } // End of 'for' statement } // End of function f_remove_headers_list - + function f_get_header( in Headers p_headers, in charstring p_header_name := c_header_content_text, out charstring_list p_header_value - ) { + ) { // Sanity checks if (lengthof(p_header_name) == 0) { return; } else if (lengthof(p_headers) == 0) { return; } - + for (var integer v_jdx := 0; v_jdx < lengthof(p_headers); v_jdx := v_jdx + 1) { if (p_headers[v_jdx].header_name == p_header_name) { p_header_value := p_headers[v_jdx].header_value; // NOTE Codec won't encode it @@ -208,7 +208,7 @@ module LibHttp_Functions { } } // End of 'for' statement } // End of function f_get_header - + /** * @desc Check HTTP response headers * @param p_headers The HTTP headers @@ -216,13 +216,13 @@ module LibHttp_Functions { * @return true on success, false otherwise */ function f_check_headers( - in Headers p_headers, - in charstring p_header_name := "Location", - in template (present) charstring p_value := ? - ) return boolean { + in Headers p_headers, + in charstring p_header_name := "Location", + in template (present) charstring p_value := ? + ) return boolean { // Local variables var boolean v_header_matched := false; - + for (var integer v_idx := 0; v_idx < lengthof(p_headers); v_idx := v_idx + 1) { if (p_headers[v_idx].header_name == p_header_name) { if (match(p_headers[v_idx].header_value[0], p_value) == true) { @@ -231,12 +231,12 @@ module LibHttp_Functions { break; } } // End of 'for' statement - + return v_header_matched; } // End of function f_check_headers } // End of group http_headers - + group altsteps { altstep a_default_requests() runs on HttpComponent { @@ -251,10 +251,10 @@ module LibHttp_Functions { f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error); } } // End of altstep a_default_requests - + altstep a_default_responses() runs on HttpComponent { var HttpMessage v_response; - + [] httpPort.receive( mw_http_response( mw_http_response_ok( @@ -320,7 +320,7 @@ module LibHttp_Functions { f_selfOrClientSyncAndVerdictTestBody(c_tbDone, e_error); } } // End of altstep a_default_responses - + } // end of group altsteps - + } // End of module LibHttp_Functions diff --git a/ttcn/LibHttp/ttcn/LibHttp_JSONTypes.ttcn b/ttcn/LibHttp/ttcn/LibHttp_JSONTypes.ttcn index e4a7ec30910f16f44030f4c39593c0e78f5dcfc2..ad0dacef3870880e08b96b530db84ae2ff658f06 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_JSONTypes.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_JSONTypes.ttcn @@ -1,9 +1,9 @@ module LibHttp_JSONTypes { // FIXME To be removed - + /** * This file is volontary empry. You have to declare all XSD files required by your project * In addition, the TTCN-3 module LibHttp_XmlMessageBodyTypes have to be updated too. */ // TODO Add here your custom RFCs import - + } // End of module LibHttp_JSONTypes diff --git a/ttcn/LibHttp/ttcn/LibHttp_JsonMessageBodyTypes.ttcn b/ttcn/LibHttp/ttcn/LibHttp_JsonMessageBodyTypes.ttcn index ef31c51abda465536e3671c9765bf2f8666c3c6e..7c6be9271beea3f32e293e8d7ae321557040bc00 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_JsonMessageBodyTypes.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_JsonMessageBodyTypes.ttcn @@ -1,18 +1,18 @@ module LibHttp_JsonMessageBodyTypes { - + /** * This file volontary contains a trivial declaration of the type JsonBody. * In accordance with your TTCN-3 module LibHttp_JSONTypes, you have to change the JsonBody typing. */ // TODO Add here your custom RFCs import - + type union JsonBody { // TODO Add here your custom variants universal charstring raw } with { variant "" } - + } with { encode "JSON"; variant "" diff --git a/ttcn/LibHttp/ttcn/LibHttp_JsonTemplates.ttcn b/ttcn/LibHttp/ttcn/LibHttp_JsonTemplates.ttcn index a7aa7f0160dbd366155fe4bd9237ab433859b65d..b3907587a306f52fce3fde90102a32a8426df7e5 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_JsonTemplates.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_JsonTemplates.ttcn @@ -9,13 +9,13 @@ * All rights reserved. */ module LibHttp_JsonTemplates { - + // TODO Add here your custom RFCs import - + // LibHttp import from LibHttp_JsonMessageBodyTypes all; import from LibHttp_XMLTypes all; - + template (value) JsonBody m_json_body_raw( in template (value) charstring p_raw ) := { @@ -27,5 +27,5 @@ module LibHttp_JsonTemplates { ) := { raw := p_raw } // End of template mw_json_body_raw - + } // End of module LibHttp_JsonTemplates diff --git a/ttcn/LibHttp/ttcn/LibHttp_MessageBodyTypes.ttcn b/ttcn/LibHttp/ttcn/LibHttp_MessageBodyTypes.ttcn index ed1d5498d780a375db2fe97caaec853e7ef42d7b..cfba5cbbee3eb02ce90b5e7e757aa1fac7408e63 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_MessageBodyTypes.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_MessageBodyTypes.ttcn @@ -1,14 +1,14 @@ module LibHttp_MessageBodyTypes { - + // LibHttp import from LibHttp_XmlMessageBodyTypes all; import from LibHttp_JsonMessageBodyTypes all; import from LibHttp_BinaryMessageBodyTypes all; - + type charstring HtmlBody; - + type charstring TextBody; - + type union HttpMessageBody { BinaryBody binary_body, HtmlBody html_body, @@ -18,7 +18,7 @@ module LibHttp_MessageBodyTypes { } with { variant "" } // End of type HttpMessageBody - + } with { encode "HttpCodec" }// End of module LibHttp_MessageBodyTypes diff --git a/ttcn/LibHttp/ttcn/LibHttp_Pics.ttcn b/ttcn/LibHttp/ttcn/LibHttp_Pics.ttcn index c4c7b8a2424e0f2e7f049e52c55270c987efd030..9a759e1ec1e378f1d289736bdcb1391dc4f673a4 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_Pics.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_Pics.ttcn @@ -4,33 +4,33 @@ module LibHttp_Pics { * @desc HTTP major version */ modulepar integer PICS_HTTP_VERSION_MAJOR := 1; - + /** * @desc HTTP minor version */ modulepar integer PICS_HTTP_VERSION_MINOR := 1; - + /** * @desc */ modulepar charstring PICS_HEADER_HOST := "www.lisp.com"; - + /** * @desc */ modulepar charstring PICS_HEADER_CONTENT_TYPE := "application/x-its-request"; modulepar charstring PICS_HEADER_CTL_CONTENT_TYPE := "application/x-its-ctl"; modulepar charstring PICS_HEADER_CRL_CONTENT_TYPE := "application/x-its-crl"; - + /** * @desc Set to false in TOKEN header shall not be used */ modulepar boolean PICS_USE_TOKEN_HEADER := true; - + /** * @desc HTTP TOKEN value * "YWxhZGRpbjpvcGVuc2VzYW1l==" is the base64 encoding of the login:password "aladdin:opensesame" */ modulepar charstring PICS_TOKEN_HEADER := "Basic " & "YWxhZGRpbjpvcGVuc2VzYW1l==" ; // aladdin:opensesame - + } // End of module LibHttp_Pics diff --git a/ttcn/LibHttp/ttcn/LibHttp_Templates.ttcn b/ttcn/LibHttp/ttcn/LibHttp_Templates.ttcn index 08359cb17fd8ed137fee9a1f396395df2fdc430a..c112f192ce74aea329b6ddcbe2aaed1f8a57c925 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_Templates.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_Templates.ttcn @@ -10,44 +10,44 @@ * @see ETSI TS 103 478 */ module LibHttp_Templates { - + // LibHttp import from LibHttp_TypesAndValues all; import from LibHttp_MessageBodyTypes all; import from LibHttp_XmlMessageBodyTypes all; import from LibHttp_JsonMessageBodyTypes all; import from LibHttp_BinaryMessageBodyTypes all; - + group http_messages { - + template (value) HttpMessage m_http_request( in template (value) Request p_request ) := { request := p_request } // End of template m_http_request - + template (present) HttpMessage mw_http_request( template (present) Request p_request := ? ) := { request := p_request } // End of template mw_http_request - + template (value) HttpMessage m_http_response( in template (value) Response p_response ) := { response := p_response } // End of template m_http_response - + template (present) HttpMessage mw_http_response( template (present) Response p_response := ? ) := { response := p_response } // End of template mw_http_response - + } // End of group http_messages - + group http_headers { - + template (value) Header m_header_line( in template (value) charstring p_header_name, in template (value) charstring_list p_header_value @@ -55,11 +55,11 @@ module LibHttp_Templates { header_name := p_header_name, header_value := p_header_value } // End of template m_header_line - + } // End of group http_headers - + group http_requests { - + template (omit) Request m_http_request_get( in charstring p_uri, in template (value) Headers p_headers, @@ -72,7 +72,7 @@ module LibHttp_Templates { header := p_headers, body := p_body } // End of template m_http_request_get - + template Request mw_http_request_get( template (present) charstring p_uri := ?, template (present) Headers p_headers := ?, @@ -85,7 +85,7 @@ module LibHttp_Templates { header := p_headers, body := p_body } // End of template mw_http_request_get - + template (omit) Request m_http_request_post( in charstring p_uri, in template (value) Headers p_headers, @@ -93,7 +93,7 @@ module LibHttp_Templates { ) modifies m_http_request_get := { method := "POST" } // End of template m_http_request_post - + template Request mw_http_request_post( template (present) charstring p_uri := ?, template (present) Headers p_headers := ?, @@ -101,7 +101,7 @@ module LibHttp_Templates { ) modifies mw_http_request_get := { method := "POST" } // End of template mw_http_request_post - + template (omit) Request m_http_request_patch( in charstring p_uri, in template (value) Headers p_headers, @@ -109,7 +109,7 @@ module LibHttp_Templates { ) modifies m_http_request_get := { method := "PATCH" } // End of template m_http_request_patch - + template Request mw_http_request_patch( template (present) charstring p_uri := ?, template (present) Headers p_headers := ?, @@ -117,7 +117,7 @@ module LibHttp_Templates { ) modifies mw_http_request_get := { method := "PATCH" } // End of template mw_http_request_patch - + template (omit) Request m_http_request_put( in charstring p_uri, in template (value) Headers p_headers, @@ -125,7 +125,7 @@ module LibHttp_Templates { ) modifies m_http_request_get := { method := "PUT" } // End of template m_http_request_put - + template Request mw_http_request_put( template (present) charstring p_uri := ?, template (present) Headers p_headers := ?, @@ -133,7 +133,7 @@ module LibHttp_Templates { ) modifies mw_http_request_get := { method := "PUT" } // End of template mw_http_request_put - + template (omit) Request m_http_request_delete( in charstring p_uri, in template (value) Headers p_headers, @@ -141,7 +141,7 @@ module LibHttp_Templates { ) modifies m_http_request_get := { method := "DELETE" } // End of template m_http_request_delete - + template Request mw_http_request_delete( template (present) charstring p_uri := ?, template (present) Headers p_headers := ?, @@ -149,11 +149,11 @@ module LibHttp_Templates { ) modifies mw_http_request_get := { method := "DELETE" } // End of template mw_http_request_post - + } // End of group http_requests - + group http_responses { - + template (value) Response m_http_response_ok( in template (value) HttpMessageBody p_body, in template (value) Headers p_header @@ -167,7 +167,7 @@ module LibHttp_Templates { tls := omit, mutual_tls := omit } // End of template m_http_response_ok - + template (value) Response m_http_response_ok_no_body( in template (value) Headers p_header ) := { @@ -176,9 +176,11 @@ module LibHttp_Templates { statuscode := 200, statustext := "OK", header := p_header, - body := omit + body := omit, + tls := omit, + mutual_tls := omit } // End of template m_http_response_ok_no_body - + template (present) Response mw_http_response_ok_no_body( template (present) Headers p_header := ? ) := { @@ -191,14 +193,14 @@ module LibHttp_Templates { tls := *, mutual_tls := * } // End of template mw_http_response_ok_no_body - + template (value) Response m_http_response_204_no_content( in template (value) Headers p_header ) modifies m_http_response_ok_no_body := { statuscode := 204, statustext := "No Content" } // End of template m_http_response_204_no_content - + template (present) Response mw_http_response_ok( template (present) HttpMessageBody p_body := ?, template (present) Headers p_header := ? @@ -212,7 +214,7 @@ module LibHttp_Templates { tls := *, mutual_tls := * } // End of template mw_http_response_ok - + template (present) Response mw_http_response_201_created( template (present) HttpMessageBody p_body := ?, template (present) Headers p_header := ? @@ -220,7 +222,22 @@ module LibHttp_Templates { statuscode := 201, statustext := "Created" } // End of template mw_http_response_201_created - + + template (present) Response mw_http_response_201_created_no_body( + template (present) Headers p_header := ? + ) modifies mw_http_response_ok_no_body := { + statuscode := 201, + statustext := "Created" + } // End of template mw_http_response_201_created_no_status_text + + template (present) Response mw_http_response_201_created_no_status_text( + template (present) HttpMessageBody p_body := ?, + template (present) Headers p_header := ? + ) modifies mw_http_response_ok := { + statuscode := 201, + statustext := "Created" + } // End of template mw_http_response_201_created_no_status_text + template (present) Response mw_http_response_202_accepted( template (present) HttpMessageBody p_body := ?, template (present) Headers p_header := ? @@ -228,14 +245,14 @@ module LibHttp_Templates { statuscode := 202, statustext := "Accepted" } // End of template mw_http_response_202_accepted - + template (present) Response mw_http_response_204_no_content( template (present) Headers p_header := ? ) modifies mw_http_response_ok_no_body := { statuscode := 204, statustext := "No Content" } // End of template mw_http_response_204_no_content - + template (value) Response m_http_response_ko( in template (value) HttpMessageBody p_body, in template (value) Headers p_header, @@ -247,9 +264,11 @@ module LibHttp_Templates { statuscode := p_statuscode, statustext := p_statustext, header := p_header, - body := p_body + body := p_body, + tls := omit, + mutual_tls := omit } // End of template m_http_response_ko - + template (value) Response m_http_response_ko_no_body( in template (value) Headers p_header, in template (value) integer p_statuscode := 404, @@ -260,16 +279,18 @@ module LibHttp_Templates { statuscode := p_statuscode, statustext := p_statustext, header := p_header, - body := omit + body := omit, + tls := omit, + mutual_tls := omit } // End of template m_http_response_ko_no_body - + template (value) Response m_http_response_500_internal_error( in template (value) Headers p_header, in template (value) integer p_statuscode := 500, in template (value) charstring p_statustext := "Internal Error" ) modifies m_http_response_ko_no_body := { } // End of template m_http_response_ko - + template (present) Response mw_http_response_ko_no_body( template (present) Headers p_header := ?, template (present) integer p_statuscode := 404, @@ -280,9 +301,11 @@ module LibHttp_Templates { statuscode := p_statuscode, statustext := p_statustext, header := p_header, - body := omit + body := omit, + tls := omit, + mutual_tls := omit } // End of template mw_http_response_ko_no_body - + template Response mw_http_response_ko( template HttpMessageBody p_body := *, template (present) Headers p_header := ? @@ -292,9 +315,11 @@ module LibHttp_Templates { statuscode := complement(200), statustext := ?, header := p_header, - body := p_body + body := p_body, + tls := omit, + mutual_tls := omit } // End of template mw_http_response_ko - + template (value) Response m_http_response_400_bad_request( in template (value) HttpMessageBody p_body, in template (value) Headers p_header, @@ -302,7 +327,7 @@ module LibHttp_Templates { in template (value) charstring p_statustext := "Bad Request" ) modifies m_http_response_ko := { } // End of template m_http_response_400_bad_request - + template Response mw_http_response_400_bad_request( template HttpMessageBody p_body := *, template (present) Headers p_header := ? @@ -310,7 +335,7 @@ module LibHttp_Templates { statuscode := 400, statustext := "Bad Request" } // End of template mw_http_response_400_bad_request - + template Response mw_http_response_401_unauthorized( template HttpMessageBody p_body := *, template (present) Headers p_header := ? @@ -318,7 +343,7 @@ module LibHttp_Templates { statuscode := 401, statustext := "Unauthorized" } // End of template mw_http_response_401_unauthorized - + template Response mw_http_response_403_forbidden( template HttpMessageBody p_body := *, template (present) Headers p_header := ? @@ -326,7 +351,7 @@ module LibHttp_Templates { statuscode := 403, statustext := "Forbidden" } // End of template mw_http_response_403_forbidden - + template Response mw_http_response_404_not_found( template HttpMessageBody p_body := *, template (present) Headers p_header := ? @@ -334,7 +359,15 @@ module LibHttp_Templates { statuscode := 404, statustext := "Not Found" } // End of template mw_http_response_404_not_found - + + template Response mw_http_response_405_not_applicable( + template HttpMessageBody p_body := *, + template (present) Headers p_header := ? + ) modifies mw_http_response_ko := { + statuscode := 405, + statustext := "Not Applicable" + } // End of template mw_http_response_405_not_applicable + template Response mw_http_response_412_precondition_failed( template HttpMessageBody p_body := *, template (present) Headers p_header := ? @@ -342,71 +375,71 @@ module LibHttp_Templates { statuscode := 412, statustext := "Precondition Failed" } // End of template mw_http_response_412_not_found - + } // End of group http_responses - + group http_html_body { - + template (value) HttpMessageBody m_http_message_body_html( - in template (value) HtmlBody p_html_body + in template (value) HtmlBody p_html_body ) := { html_body := p_html_body } // End of template m_http_message_body_html - + template (present) HttpMessageBody mw_http_message_body_html( - template (present) HtmlBody p_html_body := ? + template (present) HtmlBody p_html_body := ? ) := { html_body := p_html_body } // End of template mw_http_message_body_html - + } // End of group http_html_body - + group http_xml_body { - + template (value) HttpMessageBody m_http_message_body_xml( in template (value) XmlBody p_xml_body ) := { xml_body := p_xml_body } // End of template m_http_message_body_xml - + template (present) HttpMessageBody mw_http_message_body_xml( template (present) XmlBody p_xml_body := ? ) := { xml_body := p_xml_body } // End of template mw_http_message_body_xml - + } // End of group http_xml_body - + group http_json_body { - + template (value) HttpMessageBody m_http_message_body_json( - in template (value) JsonBody p_json_body + in template (value) JsonBody p_json_body ) := { json_body := p_json_body } // End of template m_http_message_body_json - + template (present) HttpMessageBody mw_http_message_body_json( - template (present) JsonBody p_json_body := ? + template (present) JsonBody p_json_body := ? ) := { json_body := p_json_body } // End of template mw_http_message_body_json - + } // End of group http_json_body - + group http_binary_body { - + template (value) HttpMessageBody m_http_message_body_binary( in template (value) BinaryBody p_binary_body ) := { binary_body := p_binary_body } // End of template m_http_message_body_binary - + template (present) HttpMessageBody mw_http_message_body_binary( template (present) BinaryBody p_binary_body := ? ) := { binary_body := p_binary_body } // End of template mw_http_message_body_binary - + } // End of group http_binary_body - + } // End of module LibHttp_Templates diff --git a/ttcn/LibHttp/ttcn/LibHttp_TestSystem.ttcn b/ttcn/LibHttp/ttcn/LibHttp_TestSystem.ttcn index 767bc83a4c5a9b4cfe2e69a18acd50920571d223..945a87e3937e4fe82ae57d5348e496c9523a0e0c 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_TestSystem.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_TestSystem.ttcn @@ -10,31 +10,30 @@ * @see ETSI TS 103 478 */ module LibHttp_TestSystem { - + // LibCommon import from LibCommon_Sync all; import from LibCommon_Time all; - + // LibHttp import from LibHttp_TypesAndValues all; - + type port HttpPort message { inout HttpMessage; } - - type component HttpComponent extends SelfSyncComp { // FIXME To be rename into HttpTest + + type component HttpComponent extends SelfSyncComp { port HttpPort httpPort; port HttpPort httpPort_notif; // timers timer tc_wait := PX_TWAIT; timer tc_ac := PX_TAC; timer tc_noac := PX_TNOAC; - } // End of component HttpComponent - - type component HttpTestAdapter { // FIXME To be rename into HttpTestSystem + + type component HttpTestAdapter { port HttpPort httpPort; port HttpPort httpPort_notif; - } // End of component TestAdapter - + } // End of component HttpTestAdapter + } // End of module LibHttp_TestSystem diff --git a/ttcn/LibHttp/ttcn/LibHttp_TypesAndValues.ttcn b/ttcn/LibHttp/ttcn/LibHttp_TypesAndValues.ttcn index 77ca51b06eb999d229eaef52196c4abb043e187a..0d37019f9f53fdb59ef696f779f6e2474e712962 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_TypesAndValues.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_TypesAndValues.ttcn @@ -10,11 +10,11 @@ * @see ETSI TS 103 478 */ module LibHttp_TypesAndValues { - + // LibHttp import from LibHttp_MessageBodyTypes all; import from LibHttp_Pics all; - + const charstring c_header_host := "Host"; const charstring c_header_content_type := "Content-Type"; const charstring c_header_content_text := "Content-Text"; @@ -24,10 +24,10 @@ module LibHttp_TypesAndValues { const charstring c_header_pragma := "Pragma"; const charstring c_header_cache_control := "Cache-Control"; const charstring c_header_authorization := "Authorization"; - + const integer c_http_version_major := PICS_HTTP_VERSION_MAJOR; const integer c_http_version_minor := PICS_HTTP_VERSION_MINOR; - + type record of charstring charstring_list; type record Header { charstring header_name, @@ -35,9 +35,9 @@ module LibHttp_TypesAndValues { } with { variant "FIELDORDER(msb)" } - + type record of Header Headers; - + type record Request { charstring method, charstring uri, @@ -48,7 +48,7 @@ module LibHttp_TypesAndValues { } with { variant "FIELDORDER(msb)" } - + type record Response { integer version_major, integer version_minor, @@ -61,14 +61,14 @@ module LibHttp_TypesAndValues { } with { variant "FIELDORDER(msb)" } - + type union HttpMessage { Response response, Request request } with { variant "" } - + } with { variant "" encode "HttpCodec" diff --git a/ttcn/LibHttp/ttcn/LibHttp_XMLTypes.ttcn b/ttcn/LibHttp/ttcn/LibHttp_XMLTypes.ttcn index bdb9f7712c4ddeed6c24ea7db6eeb71241d0a284..a6c7f96c3ce1d85baa32bc2f585b8cd2fc4abd21 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_XMLTypes.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_XMLTypes.ttcn @@ -1,11 +1,11 @@ module LibHttp_XMLTypes { // FIXME To be removed - + /** * This file is volontary empry. You have to declare all XSD files required by your project * In addition, the TTCN-3 module LibHttp_XmlMessageBodyTypes have to be updated too. */ // TODO Add here your custom RFCs import - + //import from XSD all; - + } // End of module LibHttp_XMLTypes diff --git a/ttcn/LibHttp/ttcn/LibHttp_XmlMessageBodyTypes.ttcn b/ttcn/LibHttp/ttcn/LibHttp_XmlMessageBodyTypes.ttcn index 147f0c3fe0d1ae3498daff65822b46824c21a289..b57854c648cfafdd246305cd9e9451ad01c648dd 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_XmlMessageBodyTypes.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_XmlMessageBodyTypes.ttcn @@ -1,18 +1,24 @@ module LibHttp_XmlMessageBodyTypes { - + /** * This file volontary contains a trivial declaration of the type XmlBody. * In accordance with your TTCN-3 module LibHttp_XMLTypes, you have to change the XmlBody typing. */ // TODO Add here your custom RFCs import - - type union XmlBody { + + type union XmlBodyMsg { // TODO Add here your custom variants - charstring raw + charstring raw } with { variant "" } - + + type record XmlBody { + XmlBodyMsg msg, + charstring raw optional + } + } with { + encode "XML"; variant "" } // End of LibHttp_XmlMessageBodyTypes diff --git a/ttcn/LibHttp/ttcn/LibHttp_XmlTemplates.ttcn b/ttcn/LibHttp/ttcn/LibHttp_XmlTemplates.ttcn index fbfab3ab8b0eda2b982523b501033edaa9e2ce52..1c28c2624c24eed98eccefacd9b772ca1a018b4d 100644 --- a/ttcn/LibHttp/ttcn/LibHttp_XmlTemplates.ttcn +++ b/ttcn/LibHttp/ttcn/LibHttp_XmlTemplates.ttcn @@ -9,25 +9,27 @@ * All rights reserved. */ module LibHttp_XmlTemplates { - + // import from XSD all; - + // TODO Add here your custom RFCs import - + // LibHttp import from LibHttp_XmlMessageBodyTypes all; import from LibHttp_XMLTypes all; - + template (value) XmlBody m_xml_body_raw( in template (value) charstring p_raw ) := { + msg := { raw := p_raw }, raw := p_raw } // End of template m_xml_body_raw template (present) XmlBody mw_xml_body_raw( template (present) charstring p_raw := ? ) := { + msg := { raw := p_raw }, raw := p_raw } // End of template mw_xml_body_raw - + } // End of module LibHttp_XmlTemplates diff --git a/ttcn/LibJson/module.mk b/ttcn/LibJson/module.mk index a5d3e3b067498ebf1cbebe5212ff82699b9d1b84..2d0875696f9c74b553fa7d4a30a67248b396228f 100644 --- a/ttcn/LibJson/module.mk +++ b/ttcn/LibJson/module.mk @@ -1,4 +1,2 @@ sources := \ ttcn/Json.ttcn - -# Please, move and comment the module you need to overwrite tofit your project diff --git a/ttcn/LibJson/ttcn/Json.ttcn b/ttcn/LibJson/ttcn/Json.ttcn index 7fb36ef07dca8d1dd1b3f1a13de786d78a1109cc..cb7a8f56861b1d3b83043d0fa4d8aba6dd58ede4 100644 --- a/ttcn/LibJson/ttcn/Json.ttcn +++ b/ttcn/LibJson/ttcn/Json.ttcn @@ -1,5 +1,5 @@ module Json { - + // These constants are used in the Json date/time type definitions const charstring dash := "-", @@ -51,6 +51,17 @@ module Json { type integer Integer (-infinity .. infinity) /*with { variant "Json:integer" }*/; + // Unsigned Integer type + type integer UInteger (0 .. infinity) /*with { + variant "Json:integer" + }*/; + // Unsigned char type + type integer UInt8 (0 .. 255) /*with { + variant "Json:integer" + }*/; + type integer UInt16 (0 .. 65535) /*with { + variant "Json:integer" + }*/; // String type type utf8string String /*with { variant "Json:string" @@ -103,11 +114,17 @@ module Json { }*/ type record of Json.Integer IntArray; /*with { variant "Json:array" - } - type record of Json.Bool BoolArray with { + }*/ + type record of Json.UInteger UIntArray; /*with { variant "Json:array" - } - type record of Json.Object ObjArray with { + }*/ + type record of Json.Bool BoolArray; /*with { + variant "Json:array" + }*/ + type record of Json.AnyURI AnyURIArray; /*with { + variant "Json:array" + }*/ + /*type record of Json.Object ObjArray; with { variant "Json:array" }*/ // Object member @@ -139,13 +156,13 @@ module Json { } with { variant "asValue" }*/ - + //Json literals //When only the true and false literals are allowed type boolean Bool; /*with { variant "Json:literal" }*/ //When only the null literal is allowed type enumerated Null { null_ }; /*with { variant "Json:literal" }*/ - + } with { encode "Json" } // End of module Json diff --git a/ttcn/LibSecurity/module.mk b/ttcn/LibSecurity/module.mk new file mode 100644 index 0000000000000000000000000000000000000000..79a47a2a5e92dba75534c337755b8668a4d154df --- /dev/null +++ b/ttcn/LibSecurity/module.mk @@ -0,0 +1,8 @@ +sources := \ + ttcn/LibSecurity_Hash.ttcn \ + ttcn/LibSecurity_Hmac.ttcn \ + ttcn/LibSecurity_Signature.ttcn \ + ttcn/LibSecurity_Certificates.ttcn \ + ttcn/http_www_w3_org_2000_09_xmldsig.ttcn \ + + diff --git a/ttcn/LibSecurity/ttcn/LibSecurity_Certificates.ttcn b/ttcn/LibSecurity/ttcn/LibSecurity_Certificates.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..4af73996d10bab2f29b9ee54ee6b8bace3f593c2 --- /dev/null +++ b/ttcn/LibSecurity/ttcn/LibSecurity_Certificates.ttcn @@ -0,0 +1,15 @@ +module LibSecurity_Certificates { + + external function fx_init_certs_db(in charstring p_certs_db_path) return integer; + + external function fx_load_certificate(in charstring p_certificate_name, in charstring p_private_key_name, in charstring p_private_key_passwd) return integer; + + function f_init_certs_db(in charstring p_certs_db_path) return integer { + return fx_init_certs_db(p_certs_db_path); + } + + function f_load_certificate(in charstring p_certificate_name, in charstring p_private_key_name, in charstring p_private_key_passwd) return integer { + return fx_load_certificate(p_certificate_name, p_private_key_name, p_private_key_passwd); + } + +} // End of LibSecurity_Certificates \ No newline at end of file diff --git a/ttcn/LibSecurity/ttcn/LibSecurity_Hash.ttcn b/ttcn/LibSecurity/ttcn/LibSecurity_Hash.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..ecebd4f4da81c71c051e918bcb1695cdff7449b1 --- /dev/null +++ b/ttcn/LibSecurity/ttcn/LibSecurity_Hash.ttcn @@ -0,0 +1,21 @@ +module LibSecurity_Hash { + + type enumerated HashAlgorithm { + e_sha1, + e_sha256, + e_sha384 + } // End of type HashAlgorithm + + function f_hash( + in octetstring p_to_be_hased, + in HashAlgorithm p_hash_algorithm + ) return octetstring { + return fx_hash(p_to_be_hased, p_hash_algorithm); + } // End of function f_hash + + external function fx_hash( + in octetstring p_to_be_hased, + in HashAlgorithm p_hash_algorithm + ) return octetstring; + +} // End of module LibSecurity_Hash diff --git a/ttcn/LibSecurity/ttcn/LibSecurity_Hmac.ttcn b/ttcn/LibSecurity/ttcn/LibSecurity_Hmac.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..8f99e4eb542dcd04d69e9b4c1bc540f3389505a9 --- /dev/null +++ b/ttcn/LibSecurity/ttcn/LibSecurity_Hmac.ttcn @@ -0,0 +1,2 @@ +module LibSecurity_Hmac { +} // End of LibSecurity_Hmac \ No newline at end of file diff --git a/ttcn/LibSecurity/ttcn/LibSecurity_Signature.ttcn b/ttcn/LibSecurity/ttcn/LibSecurity_Signature.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..1d0b524d3d5608d1bb632a834533b2216396a553 --- /dev/null +++ b/ttcn/LibSecurity/ttcn/LibSecurity_Signature.ttcn @@ -0,0 +1,66 @@ +module LibSecurity_Signature { + + import from http_www_w3_org_2000_09_xmldsig all; + + external function fx_enc_xmldsig_signed_info(in Signature.signedInfo s) return bitstring + with {extension "prototype(convert) encode(XML)"}; + + external function fx_enc_xmldsig(in Signature s) return bitstring + with {extension "prototype(convert) encode(XML)"}; + + external function fx_dec_xmldsig(inout bitstring bs, out Signature s) return integer + with {extension "prototype(sliding) decode(XML)"}; + + /** + * @desc Sign message + * @param [in] p_encoded_message The raw message to be signed + * @param [in] p_certificate_name The certificate to use for the signature + * @param [in] p_private_key_name The private key to use for the signature, in PCKS#8 format + * @param [in] p_private_key_passwd The password tpo decrypt the private key. Empty if no encryption + * @param [out] p_signature The raw signature + * @param [out] p_digest The Hash algorithm to use + * @param [out] p_x509_certificate_subject The certificate subject + * @param [out] p_x509_certificate_pem The certificate in PEM format + * @return 0 on success, -1 otherwise + */ + function f_sign( + in octetstring p_encoded_message, + in octetstring p_empty_signature, + in charstring p_certificate_name, + in charstring p_private_key_name, + in charstring p_private_key_passwd, + out octetstring p_signature, + out octetstring p_digest, + out charstring p_x509_certificate_subject, + out charstring p_x509_certificate_pem, + out charstring p_pull_request_canonicalized + ) return integer { + return fx_sign(p_encoded_message, p_empty_signature, p_certificate_name, p_private_key_name, p_private_key_passwd, p_signature, p_digest, p_x509_certificate_subject, p_x509_certificate_pem, p_pull_request_canonicalized); + } + + external function fx_sign(in octetstring p_encoded_message, in octetstring p_empty_signature, in charstring p_certificate_name, in charstring p_private_key_name, in charstring p_private_key_passwd, out octetstring p_signature, out octetstring p_digest, out charstring p_x509_certificate_subject, out charstring p_x509_certificate_pem, out charstring p_pull_request_canonicalized) return integer; + + /** + * @desc Verify signature + * @param [in] p_message The raw message to be verified + * @param [in] TODO + * @return true on success, false otherwise + */ + function f_do_sign_verify( + in charstring p_message, + in octetstring p_empty_signature, + in universal charstring p_canonicalization_method, + in universal charstring p_signature_method, + in universal charstring p_digest_method, + in universal charstring p_digest_value, + in universal charstring p_signature_value, + in universal charstring p_subject_name, + in universal charstring p_certificate, + out charstring p_debug_message + ) return boolean { + return fx_do_sign_verify(p_message, p_empty_signature, p_canonicalization_method, p_signature_method, p_digest_method, p_digest_value, p_signature_value, p_subject_name, p_certificate, p_debug_message); + } + + external function fx_do_sign_verify(in charstring p_message, in octetstring p_empty_signature, in universal charstring p_canonicalization_method, in universal charstring p_signature_method, in universal charstring p_digest_method, in universal charstring p_digest_value, in universal charstring p_signature_value, in universal charstring p_subject_name, in universal charstring p_certificate, out charstring p_debug_message) return boolean; + +} // End of LibSecurity_Signature \ No newline at end of file diff --git a/ttcn/LibSecurity/ttcn/http_www_w3_org_2000_09_xmldsig.ttcn b/ttcn/LibSecurity/ttcn/http_www_w3_org_2000_09_xmldsig.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..4be8b0bda07fc6f2df821c14d26a71dfb5b927b3 --- /dev/null +++ b/ttcn/LibSecurity/ttcn/http_www_w3_org_2000_09_xmldsig.ttcn @@ -0,0 +1,111 @@ +/******************************************************************************* +* Copyright (c) 2000-2022 Ericsson Telecom AB +* +* XSD to TTCN-3 Translator version: CRL 113 200/6 R6B +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +*******************************************************************************/ +// +// File: http_www_w3_org_2000_09_xmldsig.ttcn +// Description: +// References: +// Rev: +// Prodnr: +// Updated: Thu Jul 7 00:55:24 2022 +// Contact: http://ttcn.ericsson.se +// +//////////////////////////////////////////////////////////////////////////////// +// Generated from file(s): +// - signature.xsd +// /* xml version = "1.0" encoding = "utf-8" */ +// /* targetnamespace = "http://www.w3.org/2000/09/xmldsig#" */ +//////////////////////////////////////////////////////////////////////////////// +// Modification header(s): +//----------------------------------------------------------------------------- +// Modified by: +// Modification date: +// Description: +// Modification contact: +//------------------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + + +module http_www_w3_org_2000_09_xmldsig { + + +import from XSD all; + +//import from http_www_cise_eu_sevicemodel_v1_message all; + +type record Transform { + XSD.String algorithm, + XSD.String path +} +with { + variant "element"; + variant (algorithm) "name as capitalized"; + variant (algorithm) "attribute"; + variant (path) "untagged"; +} + +type record Signature +{ + record { + record { + XSD.String algorithm + } canonicalizationMethod, + record { + XSD.String algorithm + } signatureMethod, + record { + XSD.String uRI, + record of Transform transforms, + record { + XSD.String algorithm + } digestMethod, + XSD.String digestValue + } reference + } signedInfo, + XSD.String signatureValue, + record { + record { + XSD.String x509SubjectName, + XSD.String x509Certificate + } x509Data + } keyInfo +} +with { + variant "element"; + variant (signedInfo) "name as capitalized"; + variant (signedInfo.canonicalizationMethod) "name as capitalized"; + variant (signedInfo.canonicalizationMethod.algorithm) "name as capitalized"; + variant (signedInfo.canonicalizationMethod.algorithm) "attribute"; + variant (signedInfo.signatureMethod) "name as capitalized"; + variant (signedInfo.signatureMethod.algorithm) "name as capitalized"; + variant (signedInfo.signatureMethod.algorithm) "attribute"; + variant (signedInfo.reference) "name as capitalized"; + variant (signedInfo.reference.uRI) "name as capitalized"; + variant (signedInfo.reference.uRI) "attribute"; + variant (signedInfo.reference.transforms) "name as capitalized"; + variant (signedInfo.reference.digestMethod) "name as capitalized"; + variant (signedInfo.reference.digestMethod.algorithm) "name as capitalized"; + variant (signedInfo.reference.digestMethod.algorithm) "attribute"; + variant (signedInfo.reference.digestValue) "name as capitalized"; + variant (signatureValue) "name as capitalized"; + variant (keyInfo) "name as capitalized"; + variant (keyInfo.x509Data) "name as capitalized"; + variant (keyInfo.x509Data.x509SubjectName) "name as capitalized"; + variant (keyInfo.x509Data.x509Certificate) "name as capitalized"; +}; + + +} +with { + encode "XML"; + variant "namespace as 'http://www.w3.org/2000/09/xmldsig#'"; + variant "controlNamespace 'http://www.w3.org/2001/XMLSchema-instance' prefix 'xsi'"; + variant "elementFormQualified"; +} diff --git a/ttcn/LibXsd/module.mk b/ttcn/LibXsd/module.mk new file mode 100644 index 0000000000000000000000000000000000000000..d3529516c8ac6c89634723be64d9d042f25939a4 --- /dev/null +++ b/ttcn/LibXsd/module.mk @@ -0,0 +1,6 @@ +sources := \ + ttcn/UsefulTtcn3Types.ttcn \ + ttcn/XSD.ttcn \ + ttcn/NoTargetNamespace.ttcn \ + ttcn/http_www_w3_org_XML_1998_namespace.ttcn \ + diff --git a/ttcn/LibXsd/ttcn/NoTargetNamespace.ttcn b/ttcn/LibXsd/ttcn/NoTargetNamespace.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..9bf9d29269920a8a5474fbf692abe6ea02dcf512 --- /dev/null +++ b/ttcn/LibXsd/ttcn/NoTargetNamespace.ttcn @@ -0,0 +1,183 @@ +/******************************************************************************* +* Copyright (c) 2000-2016 Ericsson Telecom AB +* +* XSD to TTCN-3 Translator version: CRL 113 200/5 R4D +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +*******************************************************************************/ +// +// File: NoTargetNamespace.ttcn +// Description: +// References: +// Rev: +// Prodnr: +// Updated: Fri Mar 4 09:23:30 2016 +// Contact: http://ttcn.ericsson.se +// +//////////////////////////////////////////////////////////////////////////////// +// Generated from file(s): +// - Ims3gpp.xsd +// /* xml version = "1.0" encoding = "UTF-8" */ +// /* targetnamespace = "NoTargetNamespace" */ +//////////////////////////////////////////////////////////////////////////////// +// Modification header(s): +//----------------------------------------------------------------------------- +// Modified by: +// Modification date: +// Description: +// Modification contact: +//------------------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + + +module NoTargetNamespace { + + +import from XSD all; + + +type record TIMS3GPP +{ + XSD.Decimal version, + record of XSD.String attr optional, + union { + TAlternativeService alternative_service, + XSD.String service_info + } choice, + record of XSD.String elem_list +} +with { + variant "name as uncapitalized"; + variant (version) "attribute"; + variant (attr) "anyAttributes"; + variant (choice) "untagged"; + variant (choice.alternative_service) "name as 'alternative-service'"; + variant (choice.service_info) "name as 'service-info'"; + variant (elem_list) "untagged"; + variant (elem_list[-]) "anyElement"; +}; + + +type record TAlternativeService +{ + record of XSD.String attr optional, + TType type_, + XSD.String reason, + record of XSD.String elem_list +} +with { + variant "name as uncapitalized"; + variant (attr) "anyAttributes"; + variant (type_) "name as 'type'"; + variant (elem_list) "untagged"; + variant (elem_list[-]) "anyElement"; +}; + + +type record TType +{ + record of XSD.String attr optional, + record of XSD.String elem_list +} +with { + variant "name as uncapitalized"; + variant (attr) "anyAttributes"; + variant (elem_list) "untagged"; + variant (elem_list[-]) "anyElement"; +}; + + +type record TAction +{ + record of XSD.String attr optional, + record of XSD.String elem_list +} +with { + variant "name as uncapitalized"; + variant (attr) "anyAttributes"; + variant (elem_list) "untagged"; + variant (elem_list[-]) "anyElement"; +}; + + +/* root element */ + + +type TIMS3GPP Ims_3gpp +with { + variant "name as 'ims-3gpp'"; + variant "element"; +}; + + +/* emergency element for //ims-3gpp//alternative-service//type */ + + +type record Emergency +{ + +} +with { + variant "name as uncapitalized"; + variant "element"; +}; + + +/* restoration element for //ims-3gpp//alternative-service//type */ + + +type record Restoration +{ + +} +with { + variant "name as uncapitalized"; + variant "element"; +}; + + +/* action element for //ims-3gpp//alternative-service */ + + +type TAction Action +with { + variant "name as uncapitalized"; + variant "element"; +}; + + +/* emergency-registration element for //ims-3gpp//alternative-service//action */ + + +type record Emergency_registration +{ + +} +with { + variant "name as 'emergency-registration'"; + variant "element"; +}; + + +/* initial-registration element for //ims-3gpp//alternative-service//action */ + + +type record Initial_registration +{ + +} +with { + variant "name as 'initial-registration'"; + variant "element"; +}; + + +} +with { + encode "XML"; + variant "controlNamespace 'http://www.w3.org/2001/XMLSchema-instance' prefix 'xsi'"; + variant "elementFormQualified"; +} diff --git a/ttcn/LibXsd/ttcn/UsefulTtcn3Types.ttcn b/ttcn/LibXsd/ttcn/UsefulTtcn3Types.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..ae682d65b0c40db0e6ad22d38cba1089e8d8fd0c --- /dev/null +++ b/ttcn/LibXsd/ttcn/UsefulTtcn3Types.ttcn @@ -0,0 +1,95 @@ +/******************************************************************************* +* Copyright (c) 2000-2022 Ericsson Telecom AB +* +* XSD to TTCN-3 Translator version: CRL 113 200/6 R6B +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +*******************************************************************************/ +// +// File: UsefulTtcn3Types.ttcn +// Description: +// References: +// Rev: +// Prodnr: +// Updated: +// Contact: http://ttcn.ericsson.se +// +//////////////////////////////////////////////////////////////////////////////// +module UsefulTtcn3Types { + + + type integer byte (-128 .. 127) /*with { variant "8 bit" }*/; + + type integer unsignedbyte (0 .. 255) /*with { variant "unsigned 8 bit" }*/; + + type integer short (-32768 .. 32767) /*with { variant "16 bit" }*/; + + type integer unsignedshort (0 .. 65535) /*with { variant "unsigned 16 bit" }*/; + + type integer long (-2147483648 .. 2147483647) /*with { variant "32 bit" }*/; + + type integer unsignedlong (0 .. 4294967295) /*with { variant "unsigned 32 bit" }*/; + + type integer longlong ( -9223372036854775808 .. 9223372036854775807 ) /*with { variant "64 bit" }*/; + + type integer unsignedlonglong ( 0 .. 18446744073709551615 ) /*with { variant "unsigned 64 bit" }*/; + + type float IEEE754float /*with { variant "IEEE754 float" }*/; + + type float IEEE754double /*with { variant "IEEE754 double" }*/; + + type float IEEE754extfloat /*with { variant "IEEE754 extended float" }*/; + + type float IEEE754extdouble /*with { variant "IEEE754 extended double" }*/; + + type universal charstring utf8string /*with { variant "UTF-8" }*/; + + type universal charstring bmpstring ( char ( 0,0,0,0 ) .. char ( 0,0,255,255) ) /*with { variant "UCS-2" }*/; + + type universal charstring utf16string ( char ( 0,0,0,0 ) .. char ( 0,16,255,255) ) /*with { variant "UTF-16" }*/; + + type universal charstring iso8859string ( char ( 0,0,0,0 ) .. char ( 0,0,0,255) ) /*with { variant "8 bit" }*/; + + type record IDLfixed + { + unsignedshort digits, + short scale, + charstring value_ + } + /*with { + variant "IDL:fixed FORMAL/01-12-01 v.2.6"; + }*/; + + /* + type charstring char length (1); + + NOTE 1: The name of this useful type is the same as the TTCN-3 keyword used to denote universal + charstring values in the quadraple form. In general it is disallowed to use TTCN-3 keywords as + identifiers. The "char" useful type is a solitary exception and allowed only for backward compatibility + with previous versions of the TTCN-3 standard. (except Titan doesn't) + + NOTE 2: The special string "8 bit" defined in clause 28.2.3 may be used with this type to specify a given encoding + for its values. Also, other properties of the base type can be changed by using attribute mechanisms. + */ + + type universal charstring uchar length (1); + + /* + NOTE: Special strings defined in clause 28.2.3 except "8 bit" may be used with this type to specify a given + encoding for its values. Also, other properties of the base type can be changed by using attribute + mechanisms. + */ + + type bitstring bit length (1); + + type hexstring hex length (1); + + type octetstring octet length (1); + +} +with { +encode "XML"; +} diff --git a/ttcn/LibXsd/ttcn/XSD.ttcn b/ttcn/LibXsd/ttcn/XSD.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..b519f6be8994038928d1a87a460d8d47a09c6a6c --- /dev/null +++ b/ttcn/LibXsd/ttcn/XSD.ttcn @@ -0,0 +1,338 @@ +/******************************************************************************* +* Copyright (c) 2000-2022 Ericsson Telecom AB +* +* XSD to TTCN-3 Translator version: CRL 113 200/6 R6B +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +*******************************************************************************/ +// +// File: XSD.ttcn +// Description: +// References: +// Rev: +// Prodnr: +// Updated: +// Contact: http://ttcn.ericsson.se +// +//////////////////////////////////////////////////////////////////////////////// +module XSD { + +import from UsefulTtcn3Types all; + +//These constants are used in the XSD date/time type definitions +const charstring + dash := "-", + cln := ":", + year := "[0-9]#4", + yearExpansion := "(-([1-9][0-9]#(0,))#(,1))#(,1)", + month := "(0[1-9]|1[0-2])", + dayOfMonth := "(0[1-9]|[12][0-9]|3[01])", + hour := "([01][0-9]|2[0-3])", + minute := "([0-5][0-9])", + second := "([0-5][0-9])", + sFraction := "(.[0-9]#(1,))#(,1)", + endOfDayExt := "24:00:00(.0#(1,))#(,1)", + nums := "[0-9]#(1,)", + ZorTimeZoneExt := "(Z|[+-]((0[0-9]|1[0-3]):[0-5][0-9]|14:00))#(,1)", + durTime := "(T[0-9]#(1,)"& + "(H([0-9]#(1,)(M([0-9]#(1,)(S|.[0-9]#(1,)S))#(,1)|.[0-9]#(1,)S|S))#(,1)|"& + "M([0-9]#(1,)(S|.[0-9]#(1,)S)|.[0-9]#(1,)M)#(,1)|"& + "S|"& + ".[0-9]#(1,)S))" + +//anySimpleType + +type XMLCompatibleString AnySimpleType +with { +variant "XSD:anySimpleType"; +}; + +//anyType; + +type record AnyType +{ + record of String embed_values optional, + record of String attr optional, + record of String elem_list +} +with { +variant "XSD:anyType"; +variant "embedValues"; +variant (attr) "anyAttributes"; +variant (elem_list) "anyElement"; +}; +// String types + +type XMLCompatibleString String +with { +variant "XSD:string"; +}; + +type XMLStringWithNoCRLFHT NormalizedString +with { +variant "XSD:normalizedString"; +}; + +type NormalizedString Token +with { +variant "XSD:token"; +}; + +type XMLStringWithNoWhitespace Name +with { +variant "XSD:Name"; +}; + +type XMLStringWithNoWhitespace NMTOKEN +with { +variant "XSD:NMTOKEN"; +}; + +type Name NCName +with { +variant "XSD:NCName"; +}; + +type NCName ID +with { +variant "XSD:ID"; +}; + +type NCName IDREF +with { +variant "XSD:IDREF"; +}; + +type NCName ENTITY +with { +variant "XSD:ENTITY"; +}; + +type octetstring HexBinary +with { +variant "XSD:hexBinary"; +}; + +type octetstring Base64Binary +with { +variant "XSD:base64Binary"; +}; + +type XMLStringWithNoCRLFHT AnyURI +with { +variant "XSD:anyURI"; +}; + +type charstring Language (pattern "[a-zA-Z]#(1,8)(-\w#(1,8))#(0,)") +with { +variant "XSD:language"; +}; +// Integer types + +type integer Integer +with { +variant "XSD:integer"; +}; + +type integer PositiveInteger (1 .. infinity) +with { +variant "XSD:positiveInteger"; +}; + +type integer NonPositiveInteger (-infinity .. 0) +with { +variant "XSD:nonPositiveInteger"; +}; + +type integer NegativeInteger (-infinity .. -1) +with { +variant "XSD:negativeInteger"; +}; + +type integer NonNegativeInteger (0 .. infinity) +with { +variant "XSD:nonNegativeInteger"; +}; + +type longlong Long +with { +variant "XSD:long"; +}; + +type unsignedlonglong UnsignedLong +with { +variant "XSD:unsignedLong"; +}; + +type long Int +with { +variant "XSD:int"; +}; + +type unsignedlong UnsignedInt +with { +variant "XSD:unsignedInt"; +}; + +type short Short +with { +variant "XSD:short"; +}; + +type unsignedshort UnsignedShort +with { +variant "XSD:unsignedShort"; +}; + +type octetstring byte length(1) with {encode "length(1)"}; +type byte Byte +with { +variant "XSD:byte"; +}; + +type unsignedbyte UnsignedByte +with { +variant "XSD:unsignedByte"; +}; + +// Float types + +type float Decimal +with { +variant "XSD:decimal"; +}; + +type IEEE754float Float +with { +variant "XSD:float"; +}; + +type IEEE754double Double +with { +variant "XSD:double"; +}; + +// Time types + +type charstring Duration (pattern + "{dash}#(,1)P({nums}(Y({nums}(M({nums}D{durTime}#(,1)|{durTime}#(,1))|D{durTime}#(,1))|" & + "{durTime}#(,1))|M({nums}D{durTime}#(,1)|{durTime}#(,1))|D{durTime}#(,1))|{durTime})") +with { +variant "XSD:duration"; +}; + +type charstring DateTime (pattern + "{yearExpansion}{year}{dash}{month}{dash}{dayOfMonth}T({hour}{cln}{minute}{cln}{second}" & + "{sFraction}|{endOfDayExt}){ZorTimeZoneExt}" ) +with { +variant "XSD:dateTime"; +}; + +type charstring Time (pattern + "({hour}{cln}{minute}{cln}{second}{sFraction}|{endOfDayExt}){ZorTimeZoneExt}" ) +with { +variant "XSD:time"; +}; + +type charstring Date (pattern + "{yearExpansion}{year}{dash}{month}{dash}{dayOfMonth}{ZorTimeZoneExt}" ) +with { +variant "XSD:date"; +}; + +type charstring GYearMonth (pattern + "{yearExpansion}{year}{dash}{month}{ZorTimeZoneExt}" ) +with { +variant "XSD:gYearMonth"; +}; + +type charstring GYear (pattern + "{yearExpansion}{year}{ZorTimeZoneExt}" ) +with { +variant "XSD:gYear"; +}; + +type charstring GMonthDay (pattern + "{dash}{dash}{month}{dash}{dayOfMonth}{ZorTimeZoneExt}" ) +with { +variant "XSD:gMonthDay"; +}; + +type charstring GDay (pattern + "{dash}{dash}{dash}{dayOfMonth}{ZorTimeZoneExt}" ) +with { +variant "XSD:gDay"; +}; + +type charstring GMonth (pattern + "{dash}{dash}{month}{ZorTimeZoneExt}" ) +with { +variant "XSD:gMonth"; +}; + +// Sequence types + +type record of NMTOKEN NMTOKENS +with { +variant "XSD:NMTOKENS"; +}; + +type record of IDREF IDREFS +with { +variant "XSD:IDREFS"; +}; + +type record of ENTITY ENTITIES +with { +variant "XSD:ENTITIES"; +}; + +type record QName +{ + AnyURI uri optional, + NCName name +} +with { +variant "XSD:QName"; +}; + +// Boolean type + +type boolean Boolean +with { +variant "XSD:boolean"; +}; + +//TTCN-3 type definitions supporting the mapping of W3C XML Schema built-in datatypes + +type utf8string XMLCompatibleString +( + char(0,0,0,9)..char(0,0,0,9), + char(0,0,0,10)..char(0,0,0,10), + char(0,0,0,13)..char(0,0,0,13), + char(0,0,0,32)..char(0,0,215,255), + char(0,0,224,0)..char(0,0,255,253), + char(0,1,0,0)..char(0,16,255,253) +) + +type utf8string XMLStringWithNoWhitespace +( + char(0,0,0,33)..char(0,0,215,255), + char(0,0,224,0)..char(0,0,255,253), + char(0,1,0,0)..char(0,16,255,253) +) + +type utf8string XMLStringWithNoCRLFHT +( + char(0,0,0,32)..char(0,0,215,255), + char(0,0,224,0)..char(0,0,255,253), + char(0,1,0,0)..char(0,16,255,253) +) + +} +with{ +encode "XML" +} diff --git a/ttcn/LibXsd/ttcn/http_www_w3_org_XML_1998_namespace.ttcn b/ttcn/LibXsd/ttcn/http_www_w3_org_XML_1998_namespace.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..e595c61e3f851de4ef8920ee199748c161f93adb --- /dev/null +++ b/ttcn/LibXsd/ttcn/http_www_w3_org_XML_1998_namespace.ttcn @@ -0,0 +1,204 @@ +/******************************************************************************* +* Copyright (c) 2000-2018 Ericsson Telecom AB +* +* XSD to TTCN-3 Translator version: CRL 113 200/6 R4B +* +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v2.0 +* which accompanies this distribution, and is available at +* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html +*******************************************************************************/ +// +// File: http_www_w3_org_XML_1998_namespace.ttcn +// Description: +// References: +// Rev: +// Prodnr: +// Updated: Tue Aug 7 08:36:53 2018 +// Contact: http://ttcn.ericsson.se +// +//////////////////////////////////////////////////////////////////////////////// +// Generated from file(s): +// - xml_2001.xsd +// /* xml version = "1.0" */ +// /* targetnamespace = "http://www.w3.org/XML/1998/namespace" */ +// - xml.xsd +// /* xml version = "1.0" */ +// /* targetnamespace = "http://www.w3.org/XML/1998/namespace" */ +//////////////////////////////////////////////////////////////////////////////// +// Modification header(s): +//----------------------------------------------------------------------------- +// Modified by: +// Modification date: +// Description: +// Modification contact: +//------------------------------------------------------------------------------ +//////////////////////////////////////////////////////////////////////////////// + + +module http_www_w3_org_XML_1998_namespace { + + +import from XSD all; + + +/* See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father */ + + +/* This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang or xml:space attributes + on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + + . . . + + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + + . . . + + + will define a type which will schema-validate an instance + element with any of those attributes */ + + +/* In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2001/03/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself. In other words, if the XML Schema namespace changes, the version + of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2001/03/xml.xsd will not change. */ + + +/* In due course, we should install the relevant ISO 2- and 3-letter + codes as the enumerated possible values . . . */ +type XSD.Language Lang +with { + variant "name as uncapitalized"; + variant "attribute"; +}; + + +type enumerated Space +{ + default_, + preserve +} +with { + variant "text 'default_' as 'default'"; + variant "defaultForEmpty as c_defaultForEmpty_1"; + variant "name as uncapitalized"; + variant "attribute"; +}; + + +/* See http://www.w3.org/TR/xmlbase/ for + information about this attribute. */ +type XSD.AnyURI Base +with { + variant "name as uncapitalized"; + variant "attribute"; +}; + + +const Space c_defaultForEmpty_1 := preserve; + + +type union Lang_1 +{ + XSD.Language language_, + enumerated { + x + } alt_ +} +with { + variant "name as 'lang'"; + variant "useUnion"; + variant "attribute"; + variant (language_) "name as 'language'"; + variant (alt_) "name as ''"; + variant (alt_) "text 'x' as ''"; +}; + + +type enumerated Space_1 +{ + default_, + preserve +} +with { + variant "text 'default_' as 'default'"; + variant "name as 'space'"; + variant "attribute"; +}; + + +type XSD.AnyURI Base_1 +with { + variant "name as 'base'"; + variant "attribute"; +}; + + +type XSD.ID Id +with { + variant "name as uncapitalized"; + variant "attribute"; +}; + + +} +with { + encode "XML"; + variant "namespace as 'http://www.w3.org/XML/1998/namespace' prefix 'xml'"; + variant "controlNamespace 'http://www.w3.org/2001/XMLSchema-instance' prefix 'xsi'"; +}