Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • cti-tools/titan-test-system-framework
1 result
Show changes
Showing
with 1490 additions and 6 deletions
......@@ -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
/*!
* \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 <string>
#include <libxml/tree.h>
/**
* \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()); }
sources := \
src/xml_converters.cc
includes += ./include
/*!
* \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 <libxml/parser.h>
#include <libxml/c14n.h>
#include <libxml/xpath.h>
#include <libxml/tree.h>
//#include <libxslt/transform.h>
//#include <libxslt/xsltutils.h>
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<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:s=\"http://www.w3.org/2000/09/xmldsig#\">\\n\\t\\t<xsl:strip-space elements=\"*\"/>\\n\\t\\t<xsl:output indent=\"false\" method=\"xml\" omit-xml-declaration=\"yes\"/>\\n\\t\\t\\t<xsl:template match=\"*[not(self::s:Signature)]\">\\n\\t\\t\\t<xsl:element name=\"{local-name()}\">\\n\\t\\t\\t<xsl:apply-templates select=\"*|text()\"/>\\n\\t\\t</xsl:element></xsl:template><xsl:template match=\"s:Signature\"/>\\n\\t</xsl:stylesheet>\\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
//<ns4:PullRequest xmlns:ns4="http://www.cise.eu/servicemodel/v1/message/">
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
// <Payload xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="XmlEntityPayload">
first = p_transformed.find("<Payload ");
int l = 9;
if ((first != -1) && (first < p_to_transform.length())) {
next = 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);
}
// <Agent xsi:type="ns6:Organization" xmlns:ns6="http://www.cise.eu/datamodel/v1/entity/organization/">
first = p_transformed.find("<Agent ");
l = 7;
if ((first != -1) && (first < p_to_transform.length())) {
next = 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);
}
// <Location xsi:type=...">
first = p_transformed.find("<Location ");
l = 10;
if ((first != -1) && (first < p_to_transform.length())) {
next = 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);
}
// <Object xsi:type=...">
first = p_transformed.find("<Object ");
l = 8;
if ((first != -1) && (first < p_to_transform.length())) {
next = 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);
}
// <Event xsi:type=...">
first = p_transformed.find("<Event ");
l = 7;
if ((first != -1) && (first < p_to_transform.length())) {
next = 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);
}
// <Document xsi:type=...">
first = p_transformed.find("<Document ");
l = 10;
if ((first != -1) && (first < p_to_transform.length())) {
next = 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);
}
// <Document xsi:type=...">
first = p_transformed.find("<Requests ");
l = 10;
if ((first != -1) && (first < p_to_transform.length())) {
next = 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;
}
......@@ -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<std::string, std::clock_t>::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
......
/*!
* \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 <map>
#include <memory>
#include <string>
#include <vector>
#include <openssl/x509.h>
#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<std::string, const std::string> _certificates_idx; //! List of the certificate names indexed by the certificate identifier, i.e. the SH1 of the certificate name
std::map<std::string, const std::string> _certificates_subject; //! List of the certificates indexed by the certificate subject name
std::map<std::string, std::unique_ptr<const certs_db_record>> _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<unsigned char>& 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
/*!
* \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
/*!
* \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 <string>
#include <openssl/x509.h>
/*!
* \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
/*!
* \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 <certificate.pem> -noout -text` to view the certficate content
* Use `openssl [rsa|dsa|...] -inform PEM -in <private-key.pem> -text -noout` to view the private key content
* Use `openssl x509 -in <certificate.der> -out <certificate.pem>` to convert a DER certificate into a PEM certificate
*/
#pragma once
#include <map>
#include <set>
#include <string>
#include <vector>
#include <experimental/filesystem>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#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<std::string, std::unique_ptr<const certs_db_record>> & 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<std::string, std::unique_ptr<const certs_db_record>> & 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<std::string, std::map<std::string, std::unique_ptr<const certs_db_record>> & 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<std::string, std::unique_ptr<const certs_db_record>> & p_certificates);
}; // End of class certs_loader
/*!
* \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 <vector>
#include <openssl/hmac.h>
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
#pragma once
#include <memory>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include "certs_db.hh"
class CHARSTRING;
class OCTETSTRING;
class security_services {
/*std::unique_ptr<certs_db> _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<std::string, std::unique_ptr<const certs_db_record>> & 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
/*!
* \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 <openssl/objects.h>
#include <openssl/sha.h>
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
/*!
* \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 <openssl/objects.h>
#include <openssl/sha.h>
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
/*!
* \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 <openssl/objects.h>
#include <openssl/sha.h>
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
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
/*!
* \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<std::string, std::unique_ptr<const certs_db_record>>::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<std::string, const std::string>::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<std::string, std::unique_ptr<const certs_db_record>>::const_iterator it = _certificates.find(certificate_id);
*p_record = it->second.get();
// Mapping certificate id/certificate name
_certificates_idx.insert(std::pair<std::string, const std::string>(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<std::string, const std::string>(sn, certificate_id));
} else {
// Certificate is on the DB, load it
std::map<std::string, std::unique_ptr<const certs_db_record>>::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<std::string, const std::string>::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<std::string, std::unique_ptr<const certs_db_record>>::const_iterator it = _certificates.find(p_certificate_id);
*p_record = it->second.get();
// Mapping certificate id/certificate name
_certificates_idx.insert(std::pair<std::string, const std::string>(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<std::string, const std::string>(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<std::string, std::unique_ptr<const certs_db_record>>::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<unsigned char>& 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
#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;
}
/*!
* \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 <openssl/x509.h>
#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);
}
}
}
#include <fstream>
#include <iostream>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <TTCN3.hh>
#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<const char*>(hash_str), static_cast<const char*>(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<std::string, std::unique_ptr<const certs_db_record>> & 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, decltype(&::BIO_free)> 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<std::map<std::string, std::unique_ptr<const certs_db_record>>::iterator, bool> result = p_certificates.insert(std::pair<std::string, std::unique_ptr<const certs_db_record>>(p_certificate_id, std::unique_ptr<const certs_db_record>(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<std::string, std::unique_ptr<const certs_db_record>> & 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<std::map<std::string, std::unique_ptr<const certs_db_record>>::iterator, bool> result = p_certificates.insert(std::pair<std::string, std::unique_ptr<const certs_db_record>>(p_certificate_id, std::unique_ptr<const certs_db_record>(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
/*!
* \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 <TTCN3.hh>
#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<const unsigned char *>(p_buffer), p_buffer.lengthof(), static_cast<const unsigned char *>(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<const unsigned char *>(p_hmac), &length);
loggers::get_instance().log_to_hexa("hmac::generate: ", (unsigned char *)static_cast<const unsigned char *>(p_hmac), length);
// Resize the hmac
if (_hash_algorithms == hash_algorithms::sha_256) {
p_hmac = OCTETSTRING(16, static_cast<const unsigned char *>(p_hmac));
} // FIXME Check length for the other hash algorithm
return 0;
}