certificates_loader.cc 9.35 KB
Newer Older
garciay's avatar
garciay committed
#include <iostream>
#include <fstream>

#include "certificates_loader.hh"
namespace fs = std::experimental::filesystem;

#include "converter.hh"

#include "loggers.hh"

certificates_loader * certificates_loader::instance = nullptr;

certificates_loader::certificates_loader(): _certificateExt{".crt"}, _privateKeyExt{".pkey"}, _publicKeysExt{".vkey"}, _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;
  } else {
    _full_path = "./";
  }
  fs::canonical(_full_path);
  loggers::get_instance().log("certificates_loader::build_path: full path: %s", _full_path.string().c_str());
  if (!fs::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<const std::string, std::unique_ptr<security_db_record> >& p_certificates, std::map<const std::vector<unsigned char>, const std::string&>& p_hashed_id8s) {
  loggers::get_instance().log(">>> certificates_loader::load_certificates");

  // Sanity check
  if (_full_path.empty()) {
    return -1;
  }
  
  if (_is_cache_initialized) {
    return 0;
  }

  // Retrieve the list of the files in the path
  std::set<fs::path> files;
  if (retrieve_certificates_list(files) == -1) {
    return -1;
  }
  // Build the certificates cache
  if (build_certificates_cache(files, p_certificates, p_hashed_id8s) == -1) {
    return -1;
  }
  
  _is_cache_initialized = true;
  
  return 0;
} // End of method load_certificates

int certificates_loader::retrieve_certificates_list(std::set<std::experimental::filesystem::path>& p_files) {
  loggers::get_instance().log(">>> certificates_loader::retrieve_certificates_list");

  // Walk through directories
  std::set<fs::path> folders;
  for (const fs::directory_entry it : fs::recursive_directory_iterator(_full_path.string())) {
    loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Processing directory '%s'", it.path().string().c_str());
    if (fs::is_directory(it)) {
      std::set<std::string>::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");
    return -1;
  }
  // Process files
  p_files.clear();
  std::set<std::string> extensions_filter{ _certificateExt, _privateKeyExt, _publicKeysExt };
  for (std::set<fs::path>::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 fs::directory_entry it : fs::recursive_directory_iterator(*f)) {
      loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Processing file '%s'", it.path().filename().string().c_str());
      if (fs::is_regular_file(it)) {
        loggers::get_instance().log("certificates_loader::retrieve_certificates_list: Check extension '%s'", it.path().extension().string().c_str());
        std::set<std::string>::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:", 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<std::experimental::filesystem::path>& p_files, std::map<const std::string, std::unique_ptr<security_db_record> >& p_certificates, std::map<const std::vector<unsigned char>, const std::string&>& p_hashed_id8s) {
  loggers::get_instance().log(">>> certificates_loader::build_certificates_cache");

  std::set<std::experimental::filesystem::path>::const_iterator it = p_files.cbegin();
  do {
    loggers::get_instance().log("certificates_loader::build_certificates_cache: Caching '%s'", it->string().c_str());
    fs::path p = *it;
    std::string key = p.filename();
    
    // 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<unsigned char> certificate(fs::file_size(*it), 0x00);
    is.read(reinterpret_cast<char *>(certificate.data()), certificate.size());
    is.close();
    // Remove items from the list
    p_files.erase(it);

    // Load public key 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);
    int size = fs::file_size(*it);
    if ((size != 64) && (size != 96)) {
      loggers::get_instance().warning("certificates_loader::build_certificates_cache: Public keys file not found for '%s'", key.c_str());
      return -1;
    }
    std::vector<unsigned char> public_key_x(size / 2, 0x00);
    is.read(reinterpret_cast<char *>(public_key_x.data()), public_key_x.size());
    std::vector<unsigned char> public_key_y(size / 2, 0x00);
    is.read(reinterpret_cast<char *>(public_key_y.data()), public_key_y.size());
    is.close();
    // Remove items from the list
    p_files.erase(it);

    // FIXME Caching private key, digest and issuer

    // FIXME create new record
    /*p_certificates.insert(std::pair<const std::string, std::unique_ptr<security_db_record> >(key, std::unique_ptr<security_db_record>(
                                                                                                                                      new security_db_record(
                                                                                                                                                             key,
                                                                                                                                                             certificate, // Certificate
                                                                                                                                                             issuer, // Hashed ID fo the issuer, empty for CA
                                                                                                                                                             h, // Hashed ID
                                                                                                                                                             private_key, // Private key
                                                                                                                                                             public_key_x, // Public key X
                                                                                                                                                             public_key_y // Public key Y
                                                                                                                                                             ))
                                                                                             ));
    std::map<const std::string, std::unique_ptr<security_db_record> >::const_iterator i = p_certificates.find(key);
    if (i == _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<const std::vector<unsigned char>, const 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