#include #include #include "EtsiTs103097Module.hh" #include "certificates_loader.hh" #include "etsi_ts103097_certificate_codec.hh" #include "converter.hh" #include "loggers.hh" certificates_loader * certificates_loader::instance = nullptr; certificates_loader::certificates_loader(): _certificateExt{".oer"}, _privateKeyExt{".vkey"}, _publicKeysExt{".vkey_pub"}, _publicCompKeysExt(".cvkey"), _privateEncKeyExt{".ekey"}, _publicEncKeysExt{".ekey_pub"}, _hashedidDigestExt{".hashedid"}, _issuerDigestExt{".issuer"}, _full_path(), _is_cache_initialized{false}, _directory_filter{".svn", "._.DS_Store", ".DS_Store"} { loggers::get_instance().log(">>> certificates_loader::certificates_loader"); } // End of ctor int certificates_loader::build_path(const std::string& p_root_directory) { loggers::get_instance().log(">>> certificates_loader::build_path: '%s'", p_root_directory.c_str()); // Build full path if (!p_root_directory.empty()) { _full_path = p_root_directory; if (!std::experimental::filesystem::exists(_full_path) || !std::experimental::filesystem::is_directory(_full_path)) { // FIXME Coredump when app hasn't the rights to create the directory!!!! // Create directory if (!std::experimental::filesystem::create_directory(_full_path)) { _full_path = "./"; } else { // Set rights for all users std::experimental::filesystem::permissions(_full_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 { _full_path = "./"; } std::experimental::filesystem::canonical(_full_path); loggers::get_instance().log("certificates_loader::build_path: full path: %s", _full_path.string().c_str()); if (!std::experimental::filesystem::exists(_full_path)) { loggers::get_instance().warning("certificates_loader::build_path: Invalid path"); _full_path.clear(); return -1; } return 0; } // End of method build_path int certificates_loader::load_certificates(std::map >& p_certificates, std::map, std::string>& p_hashed_id8s) { loggers::get_instance().log(">>> certificates_loader::load_certificates"); // Sanity check if (_is_cache_initialized) { return 0; } // Retrieve the list of the files in the path std::set files; if (retrieve_certificates_list(files) == -1) { loggers::get_instance().warning("certificates_loader::load_certificates: Failed to build the list of certificate files"); return -1; } // Build the certificates cache if (build_certificates_cache(files, p_certificates, p_hashed_id8s) == -1) { loggers::get_instance().warning("certificates_loader::load_certificates: Failed to build the certificate cache"); return -1; } _is_cache_initialized = true; return 0; } // End of method load_certificates int certificates_loader::retrieve_certificates_list(std::set& p_files) { loggers::get_instance().log(">>> certificates_loader::retrieve_certificates_list"); // Walk through directories std::set folders; for (const std::experimental::filesystem::directory_entry it : std::experimental::filesystem::recursive_directory_iterator(_full_path.string())) { //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Processing directory '%s'", it.path().string().c_str()); if (std::experimental::filesystem::is_directory(it)) { std::set::const_iterator i = _directory_filter.find(it.path().filename()); if (i != _directory_filter.cend()) { //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Exclude directory '%s'", it.path().string().c_str()); continue; } //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Add directory '%s'", it.path().string().c_str()); folders.insert(it.path()); } } // End of 'for' statement if (folders.size() == 0) { loggers::get_instance().warning("certificates_loader::retrieve_certificates_list: No folder after filtering"); folders.insert(_full_path); } // Process files p_files.clear(); std::set extensions_filter{ _certificateExt, _privateKeyExt, _publicKeysExt, _publicCompKeysExt, _privateEncKeyExt, _publicEncKeysExt, _hashedidDigestExt, _issuerDigestExt }; for (std::set::const_reverse_iterator f = folders.crbegin(); f != folders.crend(); ++f) { //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Processing directory '%s'", f->string().c_str()); for(const std::experimental::filesystem::directory_entry it : std::experimental::filesystem::recursive_directory_iterator(*f)) { //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Processing file '%s'", it.path().filename().string().c_str()); if (std::experimental::filesystem::is_regular_file(it)) { //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Check extension '%s'", it.path().extension().string().c_str()); std::set::const_iterator i = extensions_filter.find(it.path().extension().string()); if (i != extensions_filter.cend()) { //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Add file '%s'", it.path().filename().string().c_str()); p_files.insert(it); } } } // End of 'for' statement } // End of 'for' statement //loggers::get_instance().log("certificates_loader::retrieve_certificates_list: # of files to cache: %d", p_files.size()); if (p_files.size() == 0) { loggers::get_instance().warning("certificates_loader::retrieve_certificates_list: No certificate found"); return -1; } return 0; } // End of method retrieve_certificates_list int certificates_loader::build_certificates_cache(std::set& p_files, std::map >& p_certificates, std::map, std::string>& p_hashed_id8s) { loggers::get_instance().log(">>> certificates_loader::build_certificates_cache"); std::set::const_iterator it = p_files.cbegin(); do { //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching '%s'", it->string().c_str()); std::experimental::filesystem::path p = *it; const std::string& key = p.stem(); //loggers::get_instance().log("certificates_loader::build_certificates_cache: Key = '%s'", key.c_str()); // Load certificate file it = p_files.find(p.replace_extension(_certificateExt)); if (it == p_files.cend()) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Certificate file not found for '%s'", key.c_str()); return -1; } //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching certificate '%s'", it->string().c_str()); std::ifstream is(it->string(), ios::in | ios::binary); std::vector certificate(std::experimental::filesystem::file_size(*it), 0x00); is.read(reinterpret_cast(certificate.data()), certificate.size()); is.close(); // Remove items from the list p_files.erase(it); // Load private key file it = p_files.find(p.replace_extension(_privateKeyExt)); if (it == p_files.cend()) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Private keys file not found for '%s'", key.c_str()); return -1; } //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching private keys '%s'", it->string().c_str()); is.open(it->string(), ios::in | ios::binary); int size = std::experimental::filesystem::file_size(*it); if ((size != 32) && (size != 48)) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Private key size is incorrect for '%s'", key.c_str()); return -1; } std::vector private_key(size, 0x00); is.read(reinterpret_cast(private_key.data()), private_key.size()); is.close(); // Remove items from the list p_files.erase(it); // Load public keys file it = p_files.find(p.replace_extension(_publicKeysExt)); if (it == p_files.cend()) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Public keys file not found for '%s'", key.c_str()); return -1; } //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching public keys '%s'", it->string().c_str()); is.open(it->string(), ios::in | ios::binary); size = std::experimental::filesystem::file_size(*it); if ((size != 64) && (size != 96)) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Public keys size is incorrect for '%s'", key.c_str()); return -1; } std::vector public_key_x(size / 2, 0x00); is.read(reinterpret_cast(public_key_x.data()), public_key_x.size()); std::vector public_key_y(size / 2, 0x00); is.read(reinterpret_cast(public_key_y.data()), public_key_y.size()); is.close(); // Remove items from the list p_files.erase(it); // Load public compressed key file it = p_files.find(p.replace_extension(_publicCompKeysExt)); if (it == p_files.cend()) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Public compress key file not found for '%s'", key.c_str()); return -1; } //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching public compressed ke '%s'", it->string().c_str()); is.open(it->string(), ios::in | ios::binary); size = std::experimental::filesystem::file_size(*it); if ((size != 33) && (size != 49)) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Public compressed key size is incorrect for '%s'", key.c_str()); return -1; } std::vector public_comp_key(size, 0x00); is.read(reinterpret_cast(public_comp_key.data()), public_comp_key.size()); is.close(); // Remove items from the list p_files.erase(it); // Load private encryption key file if present std::vector private_enc_key; it = p_files.find(p.replace_extension(_privateEncKeyExt)); if (it != p_files.cend()) { //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching private encryption keys '%s'", it->string().c_str()); is.open(it->string(), ios::in | ios::binary); int size = std::experimental::filesystem::file_size(*it); if (size != 32) { // IEEE Std 1609.2 2017: NistP256 or BrainpoolP256r1 loggers::get_instance().warning("certificates_loader::build_certificates_cache: Private encryption key size is incorrect for '%s'", key.c_str()); return -1; } private_enc_key.resize(size, 0x00); is.read(reinterpret_cast(private_enc_key.data()), private_enc_key.size()); is.close(); // Remove items from the list p_files.erase(it); } // Load public encryption key file std::vector public_enc_key_x; std::vector public_enc_key_y; it = p_files.find(p.replace_extension(_publicEncKeysExt)); if (it != p_files.cend()) { //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching public encryption keys '%s'", it->string().c_str()); is.open(it->string(), ios::in | ios::binary); size = std::experimental::filesystem::file_size(*it); if (size != 64) { // IEEE Std 1609.2 2017: NistP256 or BrainpoolP256r1 loggers::get_instance().warning("certificates_loader::build_certificates_cache: Public encryption keys size is incorrect for '%s'", key.c_str()); return -1; } public_enc_key_x.resize(size / 2, 0x00); is.read(reinterpret_cast(public_enc_key_x.data()), public_enc_key_x.size()); public_enc_key_y.resize(size / 2, 0x00); is.read(reinterpret_cast(public_enc_key_y.data()), public_enc_key_y.size()); is.close(); // Remove items from the list p_files.erase(it); } // Load issuer it = p_files.find(p.replace_extension(_issuerDigestExt)); if (it == p_files.cend()) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Issuer keys file not found for '%s'", key.c_str()); return -1; } //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching issuer keys '%s'", it->string().c_str()); is.open(it->string(), ios::in | ios::binary); size = std::experimental::filesystem::file_size(*it); if (size != 8) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Issuer keys file not found for '%s'", key.c_str()); return -1; } std::vector issuer(size, 0x00); is.read(reinterpret_cast(issuer.data()), issuer.size()); is.close(); // Remove items from the list p_files.erase(it); // Load hashed_id it = p_files.find(p.replace_extension(_hashedidDigestExt)); if (it == p_files.cend()) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Hashed_Id keys file not found for '%s'", key.c_str()); return -1; } //loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching hashed_id keys '%s'", it->string().c_str()); is.open(it->string(), ios::in | ios::binary); size = std::experimental::filesystem::file_size(*it); if (size != 8) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Hashed_Id keys file not found for '%s'", key.c_str()); return -1; } std::vector hashed_id(size, 0x00); is.read(reinterpret_cast(hashed_id.data()), hashed_id.size()); is.close(); // Remove items from the list p_files.erase(it); // Create new record etsi_ts103097_certificate_codec codec; IEEE1609dot2::CertificateBase decoded_certificate; OCTETSTRING os(certificate.size(), certificate.data()); codec.decode(os, decoded_certificate); //loggers::get_instance().log_msg("certificates_loader::build_certificates_cache: Decoded certificate: ", decoded_certificate); p_certificates.insert(std::pair >(key, std::unique_ptr( new security_db_record( key, certificate, // Certificate decoded_certificate, issuer, // Hashed ID fo the issuer hashed_id, // Hashed ID private_key, // Private key public_key_x, // public keys X-coordinate public_key_y, // public keys Y-coordinate public_comp_key, // public compressed key, 33 or 49 bytes length, byte #0 indicating compressed-y-0 (0x02) or compressed-y-1 (0x03) private_enc_key, // Private enciption key public_enc_key_x, // Public enciption key X-coordinate public_enc_key_y // Public enciption key Y-coordinate )) )); std::map >::const_iterator i = p_certificates.find(key); if (i == p_certificates.cend()) { loggers::get_instance().warning("certificates_loader::build_certificates_cache: Failed to insert new record '%s'", key.c_str()); return -1; } p_hashed_id8s.insert(std::pair, std::string>(i->second.get()->hashed_id(), i->first)); // Reset pointer it = p_files.cbegin(); } while (it != p_files.cend()); return 0; } // End of method build_certificates_cache int certificates_loader::save_certificate(const security_db_record& p_certificate) { loggers::get_instance().log(">>> certificates_loader::save_certificate"); // Certificate file std::experimental::filesystem::path p(_full_path); p /= p_certificate.certificate_id(); p += _certificateExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Certificate file: '%s'", p.string().c_str()); std::ofstream os(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.certificate().data()), p_certificate.certificate().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); // Private key p = _full_path; p /= p_certificate.certificate_id(); p += _privateKeyExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Private key file: '%s'", p.string().c_str()); os.open(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.private_key().data()), p_certificate.private_key().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); // Public keys p = _full_path; p /= p_certificate.certificate_id(); p += _publicKeysExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Public keys file: '%s'", p.string().c_str()); os.open(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.public_key_x().data()), p_certificate.public_key_x().size()); os.write(reinterpret_cast(p_certificate.public_key_y().data()), p_certificate.public_key_y().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); // Public compressed key p = _full_path; p /= p_certificate.certificate_id(); p += _publicCompKeysExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Public compressed keys file: '%s'", p.string().c_str()); os.open(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.public_comp_key().data()), p_certificate.public_comp_key().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); // Private encryption key if (p_certificate.private_enc_key().size() != 0) { p = _full_path; p /= p_certificate.certificate_id(); p += _privateEncKeyExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Private encryption key file: '%s'", p.string().c_str()); os.open(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.private_enc_key().data()), p_certificate.private_enc_key().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); // Public encription keys p = _full_path; p /= p_certificate.certificate_id(); p += _publicEncKeysExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Public encryption keys file: '%s'", p.string().c_str()); os.open(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.public_enc_key_x().data()), p_certificate.public_enc_key_x().size()); os.write(reinterpret_cast(p_certificate.public_enc_key_y().data()), p_certificate.public_enc_key_y().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); } // Issuer p = _full_path; p /= p_certificate.certificate_id(); p += _issuerDigestExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Issuer digest file: '%s'", p.string().c_str()); os.open(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.issuer().data()), p_certificate.issuer().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); // Hashedid8 p = _full_path; p /= p_certificate.certificate_id(); p += _hashedidDigestExt; if (std::experimental::filesystem::exists(p)) { std::experimental::filesystem::remove(p); } loggers::get_instance().log("certificates_loader::save_certificate: Hashedid8 digest file: '%s'", p.string().c_str()); os.open(p.string(), ios::out | ios::binary); os.write(reinterpret_cast(p_certificate.hashed_id().data()), p_certificate.hashed_id().size()); os.close(); std::experimental::filesystem::permissions(p, std::experimental::filesystem::perms::add_perms | std::experimental::filesystem::perms::owner_all | std::experimental::filesystem::perms::group_all | std::experimental::filesystem::perms::others_all); return 0; } // End of method save_certificate