Skip to content

Commit

Permalink
Add pkcs11 support to get_security_files (#66)
Browse files Browse the repository at this point in the history
* Adding overload of get_security_files.

* Implement changes to support .p11 files.

* Security tests converted into TEST_P

* Adding pkcs11 specific tests.

Signed-off-by: Miguel Company <[email protected]>
  • Loading branch information
MiguelCompany authored Apr 8, 2024
1 parent ae7df87 commit d82d23a
Show file tree
Hide file tree
Showing 3 changed files with 391 additions and 45 deletions.
32 changes: 32 additions & 0 deletions rmw_dds_common/include/rmw_dds_common/security.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,38 @@ bool get_security_files(
const std::string & prefix, const std::string & secure_root,
std::unordered_map<std::string, std::string> & result);

/// Get the set of security files in a security enclave.
/**
* This function will look through the passed in 'secure root'
* for a set of required filenames that must be in the enclave.
* If any of the required filenames are missing, the 'result'
* will be empty and the function will return false.
* If all of the required filenames are present, then this function
* will fill in the 'result' map with a key-value pair of
* friendy name -> filename. If the prefix is not empty, then
* the prefix will be applied to the filename.
*
* The friendly names that this function will currently fill in are:
* IDENTITY_CA
* CERTIFICATE
* PRIVATE_KEY
* PERMISSIONS_CA
* GOVERNANCE
* PERMISSIONS
*
* \param[in] supports_pkcs11 Whether the RMW has support for PKCS#11 URIs.
* \param[in] prefix An optional prefix to apply to the filenames when storing them.
* \param[in] secure_root The path to the security enclave to look at.
* \param[out] result The map where the friendly name -> filename pairs are stored.
* \return `true` if all required files exist in the security enclave, `false` otherwise.
*/
RMW_DDS_COMMON_PUBLIC
bool get_security_files(
bool supports_pkcs11,
const std::string & prefix,
const std::string & secure_root,
std::unordered_map<std::string, std::string> & result);

} // namespace rmw_dds_common

#endif // RMW_DDS_COMMON__SECURITY_HPP_
112 changes: 99 additions & 13 deletions rmw_dds_common/src/security.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,127 @@
// limitations under the License.

#include <filesystem>
#include <fstream>
#include <functional>
#include <string>
#include <utility>
#include <unordered_map>
#include <vector>

#include "rmw_dds_common/security.hpp"

namespace rmw_dds_common
{

// Processor for security attributes with FILE URI
static bool process_file_uri_security_file(
bool /*supports_pkcs11*/,
const std::string & prefix,
const std::filesystem::path & full_path,
std::string & result)
{
if (!std::filesystem::is_regular_file(full_path)) {
return false;
}
result = prefix + full_path.generic_string();
return true;
}

// Processor for security attributes with PKCS#11 URI
static bool process_pkcs_uri_security_file(
bool supports_pkcs11,
const std::string & /*prefix*/,
const std::filesystem::path & full_path,
std::string & result)
{
if (!supports_pkcs11) {
return false;
}

const std::string p11_prefix("pkcs11:");

std::ifstream ifs(full_path);
if (!ifs.is_open()) {
return false;
}

if (!(ifs >> result)) {
return false;
}
if (result.find(p11_prefix) != 0) {
return false;
}

return true;
}

bool get_security_files(
const std::string & prefix, const std::string & secure_root,
std::unordered_map<std::string, std::string> & result)
{
const std::unordered_map<std::string, std::string> required_files{
{"IDENTITY_CA", "identity_ca.cert.pem"},
{"CERTIFICATE", "cert.pem"},
{"PRIVATE_KEY", "key.pem"},
{"PERMISSIONS_CA", "permissions_ca.cert.pem"},
{"GOVERNANCE", "governance.p7s"},
{"PERMISSIONS", "permissions.p7s"},
return get_security_files(false, prefix, secure_root, result);
}

bool get_security_files(
bool supports_pkcs11,
const std::string & prefix,
const std::string & secure_root,
std::unordered_map<std::string, std::string> & result)
{
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using std::placeholders::_4;
using security_file_processor =
std::function<bool (bool, const std::string &, const std::filesystem::path &, std::string &)>;
using processor_vector =
std::vector<std::pair<std::string, security_file_processor>>;

// Key: the security attribute
// Value: ordered sequence of pairs. Each pair contains one possible file name
// for the attribute and the corresponding processor method
// Pairs are ordered by priority: the first one matching is used.
const std::unordered_map<std::string, processor_vector> required_files{
{"IDENTITY_CA", {
{"identity_ca.cert.p11", std::bind(process_pkcs_uri_security_file, _1, _2, _3, _4)},
{"identity_ca.cert.pem", std::bind(process_file_uri_security_file, _1, _2, _3, _4)}}},
{"CERTIFICATE", {
{"cert.p11", std::bind(process_pkcs_uri_security_file, _1, _2, _3, _4)},
{"cert.pem", std::bind(process_file_uri_security_file, _1, _2, _3, _4)}}},
{"PRIVATE_KEY", {
{"key.p11", std::bind(process_pkcs_uri_security_file, _1, _2, _3, _4)},
{"key.pem", std::bind(process_file_uri_security_file, _1, _2, _3, _4)}}},
{"PERMISSIONS_CA", {
{"permissions_ca.cert.p11", std::bind(process_pkcs_uri_security_file, _1, _2, _3, _4)},
{"permissions_ca.cert.pem", std::bind(process_file_uri_security_file, _1, _2, _3, _4)}}},
{"GOVERNANCE", {
{"governance.p7s", std::bind(process_file_uri_security_file, _1, _2, _3, _4)}}},
{"PERMISSIONS", {
{"permissions.p7s", std::bind(process_file_uri_security_file, _1, _2, _3, _4)}}},
};

const std::unordered_map<std::string, std::string> optional_files{
{"CRL", "crl.pem"},
};

for (const std::pair<const std::string, std::string> & el : required_files) {
std::filesystem::path full_path(secure_root);
full_path /= el.second;
if (!std::filesystem::is_regular_file(full_path)) {
for (const std::pair<const std::string,
std::vector<std::pair<std::string, security_file_processor>>> & el : required_files)
{
std::string attribute_value;
bool processed = false;
for (auto & proc : el.second) {
std::filesystem::path full_path(secure_root);
full_path /= proc.first;
if (proc.second(supports_pkcs11, prefix, full_path, attribute_value)) {
processed = true;
break;
}
}
if (!processed) {
result.clear();
return false;
}

result[el.first] = prefix + full_path.generic_string();
result[el.first] = attribute_value;
}

for (const std::pair<const std::string, std::string> & el : optional_files) {
Expand Down
Loading

0 comments on commit d82d23a

Please sign in to comment.