Enable use of Cyclone DDS security features

Add utility function to insert security settings to the cyclone QOS
object used to create nodes.  Include a utility to find security
files and properly format their location to use with DDS.

Signed-off-by: Sid Faber <sid.faber@canonical.com>
This commit is contained in:
Sid Faber 2020-03-05 21:08:26 +00:00
parent 025762ac4f
commit 99d2738a84
2 changed files with 95 additions and 4 deletions

View file

@ -30,6 +30,5 @@ DDS directly instead of via the ROS2 abstraction.
## Known limitations ## Known limitations
Cyclone DDS doesn't yet implement the DDS Security standard, nor does it fully implement Cyclone DDS doesn't yet fully implement the Lifespan, Deadline and some of the Liveliness QoS modes.
the Lifespan, Deadline and some of the Liveliness QoS modes. Consequently these features Consequently these features of ROS2 are also not yet supported when using Cyclone DDS.
of ROS2 are also not yet supported when using Cyclone DDS.

View file

@ -26,9 +26,11 @@
#include <utility> #include <utility>
#include <regex> #include <regex>
#include "rcutils/filesystem.h"
#include "rcutils/get_env.h" #include "rcutils/get_env.h"
#include "rcutils/logging_macros.h" #include "rcutils/logging_macros.h"
#include "rcutils/strdup.h" #include "rcutils/strdup.h"
#include "rcutils/format_string.h"
#include "rmw/allocators.h" #include "rmw/allocators.h"
#include "rmw/convert_rcutils_ret_to_rmw_ret.h" #include "rmw/convert_rcutils_ret_to_rmw_ret.h"
@ -642,6 +644,80 @@ static std::string get_node_user_data(const char * node_name, const char * node_
std::string(";"); std::string(";");
} }
/* Returns the full URI of a security file properly formatted for DDS */
char * get_security_file_URI(
const char * security_filename, const char * node_secure_root,
const rcutils_allocator_t allocator)
{
char * ret;
char * file_path = rcutils_join_path(node_secure_root, security_filename, allocator);
if (file_path == nullptr) {
ret = nullptr;
} else if (!rcutils_is_readable(file_path)) {
RCUTILS_LOG_ERROR_NAMED(
"rmw_cyclonedds_cpp", "get_security_file: %s not found", file_path);
ret = nullptr;
allocator.deallocate(file_path, allocator.state);
} else {
/* Cyclone also supports a "data:" URI */
ret = rcutils_format_string(allocator, "file:%s", file_path);
allocator.deallocate(file_path, allocator.state);
}
return ret;
}
void store_security_filepath_in_qos(
dds_qos_t * qos, const char * qos_property_name, const char * file_name,
const rmw_node_security_options_t * security_options)
{
rcutils_allocator_t allocator = rcutils_get_default_allocator();
char * security_file_path = get_security_file_URI(
file_name, security_options->security_root_path, allocator);
if (security_file_path != nullptr) {
dds_qset_prop(qos, qos_property_name, security_file_path);
allocator.deallocate(security_file_path, allocator.state);
}
}
/* Set all the qos properties needed to enable DDS security */
void configure_qos_for_security(
dds_qos_t * qos, const rmw_node_security_options_t * security_options)
{
/* File path is set to nullptr if file does not exist or is not readable */
store_security_filepath_in_qos(
qos, "dds.sec.auth.identity_ca", "identity_ca.cert.pem",
security_options);
store_security_filepath_in_qos(
qos, "dds.sec.auth.identity_certificate", "cert.pem",
security_options);
store_security_filepath_in_qos(
qos, "dds.sec.auth.private_key", "key.pem",
security_options);
store_security_filepath_in_qos(
qos, "dds.sec.access.permissions_ca", "permissions_ca.cert.pem",
security_options);
store_security_filepath_in_qos(
qos, "dds.sec.access.governance", "governance.p7s",
security_options);
store_security_filepath_in_qos(
qos, "dds.sec.access.permissions", "permissions.p7s",
security_options);
dds_qset_prop(qos, "dds.sec.auth.library.path", "libdds_security_auth.so");
dds_qset_prop(qos, "dds.sec.auth.library.init", "init_authentication");
dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_authentication");
dds_qset_prop(qos, "dds.sec.crypto.library.path", "libdds_security_crypto.so");
dds_qset_prop(qos, "dds.sec.crypto.library.init", "init_crypto");
dds_qset_prop(qos, "dds.sec.crypto.library.finalize", "finalize_crypto");
dds_qset_prop(qos, "dds.sec.access.library.path", "libdds_security_ac.so");
dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control");
dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control");
}
extern "C" rmw_node_t * rmw_create_node( extern "C" rmw_node_t * rmw_create_node(
rmw_context_t * context, const char * name, rmw_context_t * context, const char * name,
const char * namespace_, size_t domain_id, const char * namespace_, size_t domain_id,
@ -666,7 +742,13 @@ extern "C" rmw_node_t * rmw_create_node(
static_cast<void>(domain_id); static_cast<void>(domain_id);
const dds_domainid_t did = DDS_DOMAIN_DEFAULT; const dds_domainid_t did = DDS_DOMAIN_DEFAULT;
#endif #endif
(void) security_options;
if (security_options == nullptr) {
RCUTILS_LOG_ERROR_NAMED(
"rmw_cyclonedds_cpp", "rmw_create_node: security options null");
return nullptr;
}
rmw_ret_t ret; rmw_ret_t ret;
int dummy_validation_result; int dummy_validation_result;
size_t dummy_invalid_index; size_t dummy_invalid_index;
@ -688,8 +770,18 @@ extern "C" rmw_node_t * rmw_create_node(
#endif #endif
dds_qos_t * qos = dds_create_qos(); dds_qos_t * qos = dds_create_qos();
if (qos == nullptr) {
RCUTILS_LOG_ERROR_NAMED(
"rmw_cyclonedds_cpp", "rmw_create_node: Unable to create qos");
return nullptr;
}
std::string user_data = get_node_user_data(name, namespace_); std::string user_data = get_node_user_data(name, namespace_);
dds_qset_userdata(qos, user_data.c_str(), user_data.size()); dds_qset_userdata(qos, user_data.c_str(), user_data.size());
if (security_options->enforce_security) {
configure_qos_for_security(qos, security_options);
}
dds_entity_t pp = dds_create_participant(did, qos, nullptr); dds_entity_t pp = dds_create_participant(did, qos, nullptr);
dds_delete_qos(qos); dds_delete_qos(qos);
if (pp < 0) { if (pp < 0) {