Newer
Older
#include <TTCN3.hh>
#include <cmath>
#include "security_services.hh"
using namespace std; // Required for isnan()
#include "etsi_ts103097_tobesigned_data_codec.hh"
#include "etsi_ts103097_data_codec.hh"
#include "etsi_ts103097_certificate_codec.hh"
#include "security_ecc.hh"
#include "sha256.hh"
#include "sha384.hh"
#include "params.hh"
#include "loggers.hh"
#include "converter.hh"
security_services * security_services::instance = nullptr;
security_services::security_services() : _setup_done{false}, _ec_keys_enc(nullptr), _security_cache(new security_cache), _security_db(nullptr), _last_generation_time(0), _unknown_certificate(0, nullptr), _latitude(0), _longitude(0), _elevation(0) {
loggers::get_instance().log(">>> security_services::security_services");
} // End of ctor
int security_services::setup(params& p_params) { // FIXME Rename this method
loggers::get_instance().log(">>> security_services::setup");
_params = p_params;
_params.log();
if (_setup_done) {
loggers::get_instance().warning("security_services::setup: Already done");
return 0;
}
// Build the certificate caching
try {
_security_db.reset(new security_db(_params[params::sec_db_path]));
if (_security_db.get() == nullptr) { // Memory allocation issue
loggers::get_instance().warning("security_services::setup: _security_db pointer is NULL");
return -1;
}
_setup_done = true;
} catch(...) {
loggers::get_instance().error("security_services::setup: Filesystem access error, terminate test suite on TTCN-3 error. Please check user name and paths in the test suite configuration file.");
return -1;
}
// Initialise encryption mechanism
params::const_iterator it = _params.find(params::cypher);
if (it == _params.cend()) {
_ec_keys_enc.reset(new security_ecc(ec_elliptic_curves::nist_p_256));
_params.insert(std::pair<std::string, std::string>(params::cypher, std::string("NISTP-256")));
p_params.insert(std::pair<std::string, std::string>(params::cypher, std::string("NISTP-256")));
} else if (it->second.compare("NISTP-256")) {
_ec_keys_enc.reset(new security_ecc(ec_elliptic_curves::nist_p_256));
} else if (it->second.compare("BP-256")) {
_ec_keys_enc.reset(new security_ecc(ec_elliptic_curves::brainpool_p_256_r1));
} else {
loggers::get_instance().warning("security_services::setup: Failed to encode ToBeSignedData");
return -1;
int security_services::store_certificate(const CHARSTRING& p_cert_id, const OCTETSTRING& p_cert, const OCTETSTRING& p_private_key, const OCTETSTRING& p_public_key_x, const OCTETSTRING& p_public_key_y, const OCTETSTRING& p_public_comp_key, const INTEGER& p_public_comp_key_mode, const OCTETSTRING& p_hash, const OCTETSTRING& p_hashid8, const OCTETSTRING& p_issuer, const OCTETSTRING& p_private_enc_key, const OCTETSTRING& p_public_enc_key_x, const OCTETSTRING& p_public_enc_key_y, const OCTETSTRING& p_public_enc_compressed_key, const INTEGER& p_public_enc_key_compressed_mode) {
loggers::get_instance().log_msg(">>> security_services::store_certificate: ", p_cert_id);
// Sanity checks
if (_security_db.get() == nullptr) { // Setup not called
loggers::get_instance().warning("security_services::store_certificate: Not initialised");
return -1;
}
return _security_db.get()->store_certificate(p_cert_id, p_cert, p_private_key, p_public_key_x, p_public_key_y, p_public_comp_key, p_public_comp_key_mode, p_hash, p_hashid8, p_issuer, p_private_enc_key, p_public_enc_key_x, p_public_enc_key_y, p_public_enc_compressed_key, p_public_enc_key_compressed_mode);
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
}
int security_services::verify_and_extract_gn_payload(const OCTETSTRING& p_secured_gn_payload, const bool p_verify, IEEE1609dot2::Ieee1609Dot2Data& p_ieee_1609dot2_data, OCTETSTRING& p_unsecured_gn_payload, params& p_params) {
loggers::get_instance().log_msg(">>> security_services::verify_and_extract_gn_payload: ", p_secured_gn_payload);
// Sanity checks
if (p_secured_gn_payload.lengthof() == 0) {
return -1;
}
// Decode the secured message (OER encoding)
etsi_ts103097_data_codec codec;
codec.decode(p_secured_gn_payload, p_ieee_1609dot2_data, &p_params);
// Sanity checks
if (!p_ieee_1609dot2_data.is_bound()) {
loggers::get_instance().warning("security_services::verify_and_extract_gn_payload: Unbound value, discard it");
return -1;
}
if (p_verify && ((unsigned int)(int)p_ieee_1609dot2_data.protocolVersion() != security_services::ProtocolVersion)) {
loggers::get_instance().warning("security_services::verify_and_extract_gn_payload: Wrong version protocol, discard it");
return -1;
}
return process_ieee_1609_dot2_content(p_ieee_1609dot2_data.content(), p_verify, p_unsecured_gn_payload, p_params);
} // End of method verify_and_extract_gn_payload
int security_services::process_ieee_1609_dot2_content(const IEEE1609dot2::Ieee1609Dot2Content& p_ieee_1609_dot2_content, const bool p_verify, OCTETSTRING& p_unsecured_payload, params& p_params) {
loggers::get_instance().log_msg(">>> security_services::process_ieee_1609_dot2_content: ", p_ieee_1609_dot2_content);
if (p_ieee_1609_dot2_content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_unsecuredData)) { // Unsecured packet, End of recursivity
p_unsecured_payload = p_ieee_1609_dot2_content.unsecuredData();
} else if (p_ieee_1609_dot2_content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_signedData)) {
const IEEE1609dot2::SignedData& signedData = p_ieee_1609_dot2_content.signedData();
if (process_ieee_1609_dot2_signed_data(signedData, p_verify, p_unsecured_payload, p_params) != 0) {
if (p_verify) {
return -1;
}
}
} else if (p_ieee_1609_dot2_content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_encryptedData)) {
const IEEE1609dot2::EncryptedData& encrypted_data = p_ieee_1609_dot2_content.encryptedData();
OCTETSTRING signed_payload;
if (process_ieee_1609_dot2_encrypted_data(encrypted_data, p_verify, signed_payload, p_params) != 0) {
return -1;
}
loggers::get_instance().log_msg("security_services::process_ieee_1609_dot2_content: Decrypted payload: ", signed_payload);
IEEE1609dot2::Ieee1609Dot2Data ieee_1609dot2_data; // TODO Check if it could be reused
if (verify_and_extract_gn_payload(signed_payload, p_verify, ieee_1609dot2_data, p_unsecured_payload, p_params) != 0) {
if (p_verify) {
return -1;
}
}
} else if (p_ieee_1609_dot2_content.ischosen(IEEE1609dot2::Ieee1609Dot2Content::ALT_signedCertificateRequest)) {
// Reset certificate timer
loggers::get_instance().log("security_services::process_ieee_1609_dot2_content: Set Certificate re-transmission flag and reset timer");
_last_generation_time = 0;
return 0;
} else { // Shall never be reached
loggers::get_instance().warning("security_services::process_ieee_1609_dot2_content: Undefined IEEE 1609.2 Content, discard it");
if (p_verify) {
return -1;
}
}
loggers::get_instance().log_msg("<<< security_services::process_ieee_1609_dot2_content: ", p_unsecured_payload);
return 0;
} // End of method process_ieee_1609_dot2_content
int security_services::process_ieee_1609_dot2_signed_data(const IEEE1609dot2::SignedData& p_signed_data, const bool p_verify, OCTETSTRING& p_unsecured_payload, params& p_params) {
loggers::get_instance().log_msg(">>> security_services::process_ieee_1609_dot2_signed_data: ", p_signed_data);
// Check the headerInfo content
const IEEE1609dot2::HeaderInfo& header_info = p_signed_data.tbsData().headerInfo();
p_params[params::its_aid] = std::to_string(header_info.psid().get_long_long_val());
if (!header_info.generationTime().is_present()) {
loggers::get_instance().warning("security_services::process_ieee_1609_dot2_signed_data: HeaderInfo::GenerationTime field is missing");
if (p_verify) {
return -1;
}
} else {
const OPTIONAL<INTEGER>& v = dynamic_cast<const OPTIONAL<INTEGER>& >(header_info.generationTime()); // in millisecond
unsigned long long gt = ((INTEGER&)(*v.get_opt_value())).get_long_long_val();
unsigned long long ms = base_time::get_instance().get_current_time(); // in millisecond
loggers::get_instance().log("security_services::process_ieee_1609_dot2_signed_data: generation time check %ld / %ld", header_info.generationTime(), ms);
if (abs((double)gt - (double)ms) >= 5.0) { // TODO Use a params for generation_time_epsilon
loggers::get_instance().warning("security_services::process_ieee_1609_dot2_signed_data: Invalid generation time, discard it");
if (p_verify) {
return -1;
}
}
}
// Check encryption keys if present
if (header_info.encryptionKey().is_present()) {
// TODO
}
// Check request certificate
if (header_info.inlineP2pcdRequest().is_present()) {
loggers::get_instance().error("security_services::process_ieee_1609_dot2_signed_data: inlineP2pcdRequest not supported yet");
// TODO
}
// Check requested certificate
if (header_info.requestedCertificate().is_present()) {
loggers::get_instance().error("security_services::process_ieee_1609_dot2_signed_data: requestedCertificate not supported yet");
// TODO
}
// Check and extract unsecured payload
if (p_signed_data.tbsData().payload().data().is_present()) {
// Check protocol version
const OPTIONAL<IEEE1609dot2::Ieee1609Dot2Data>& v = dynamic_cast<const OPTIONAL<IEEE1609dot2::Ieee1609Dot2Data>& >(p_signed_data.tbsData().payload().data());
loggers::get_instance().log_msg("security_services::process_ieee_1609_dot2_signed_data: SignedDataPayload.data=", v);
const IEEE1609dot2::Ieee1609Dot2Data& ieee_1609dot2_data = static_cast<const IEEE1609dot2::Ieee1609Dot2Data&>(*v.get_opt_value());
if (p_verify && ((unsigned int)(int)ieee_1609dot2_data.protocolVersion() != security_services::ProtocolVersion)) {
loggers::get_instance().warning("security_services::process_ieee_1609_dot2_signed_data: Wrong version protocol, discard it");
if (p_verify) {
return -1;
}
}
Loading full blame...