Skip to content

Commit

Permalink
Use correct algorithm strings on PermissionsToken and IdentityToken (#…
Browse files Browse the repository at this point in the history
…5450)

* Refs #19925. Add conversion methods for token algorithms.

Signed-off-by: Miguel Company <[email protected]>

* Refs #19925. Configure legacy transmission on PKIDH.

Signed-off-by: Miguel Company <[email protected]>

* Refs #19925. Configure legacy transmission on Permissions.

Signed-off-by: Miguel Company <[email protected]>

* Refs #19925. Add blackbox test.

Signed-off-by: Miguel Company <[email protected]>

* Refs #19925. Add doxygen documentation to new methods.

Signed-off-by: Miguel Company <[email protected]>

---------

Signed-off-by: Miguel Company <[email protected]>
(cherry picked from commit 971f120)
  • Loading branch information
MiguelCompany authored and mergify[bot] committed Dec 11, 2024
1 parent ead5329 commit 6e5a0d9
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 9 deletions.
78 changes: 74 additions & 4 deletions src/cpp/security/accesscontrol/Permissions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,67 @@ using namespace eprosima::fastrtps;
using namespace eprosima::fastrtps::rtps;
using namespace eprosima::fastrtps::rtps::security;

/**
* @brief Convert a signature algortihm before adding it to a PermissionsToken.
*
* This methods converts the signature algorithm to the format used in the PermissionsToken.
* Depending on the value of the use_legacy parameter, the algorithm will be converted to the legacy format or to the
* one specified in the DDS-SEC 1.1 specification.
*
* @param algorithm The algorithm to convert.
* @param use_legacy Whether to use the legacy format or not.
*
* @return The converted algorithm.
*/
static std::string convert_to_token_algo(
const std::string& algorithm,
bool use_legacy)
{
// Leave as internal format when legacy is used
if (use_legacy)
{
return algorithm;
}

// Convert to token format
if (algorithm == RSA_SHA256)
{
return RSA_SHA256_FOR_TOKENS;
}
else if (algorithm == ECDSA_SHA256)
{
return ECDSA_SHA256_FOR_TOKENS;
}

return algorithm;
}

/**
* @brief Parse a signature algorithm from a PermissionsToken.
*
* This method parses a signature algorithm from a PermissionsToken.
* It converts the algorithm to the internal (legacy) format used by the library.
*
* @param algorithm The algorithm to parse.
*
* @return The parsed algorithm.
*/
static std::string parse_token_algo(
const std::string& algorithm)
{
// Convert to internal format, allowing both legacy and new formats
if (algorithm == RSA_SHA256_FOR_TOKENS)
{
return RSA_SHA256;
}
else if (algorithm == ECDSA_SHA256_FOR_TOKENS)
{
return ECDSA_SHA256;
}

return algorithm;
}

static bool is_domain_in_set(
const uint32_t domain_id,
const Domains& domains)
Expand Down Expand Up @@ -693,7 +754,8 @@ static bool check_subject_name(
}

static bool generate_permissions_token(
AccessPermissionsHandle& handle)
AccessPermissionsHandle& handle,
bool transmit_legacy_algorithms)
{
Property property;
PermissionsToken& token = handle->permissions_token_;
Expand All @@ -705,7 +767,7 @@ static bool generate_permissions_token(
token.properties().push_back(std::move(property));

property.name("dds.perm_ca.algo");
property.value() = handle->algo;
property.value() = convert_to_token_algo(handle->algo, transmit_legacy_algorithms);
property.propagate(true);
token.properties().push_back(std::move(property));

Expand Down Expand Up @@ -765,6 +827,13 @@ PermissionsHandle* Permissions::validate_local_permissions(
return nullptr;
}

bool transmit_legacy_algorithms = false;
std::string* legacy = PropertyPolicyHelper::find_property(access_properties, "transmit_algorithms_as_legacy");
if (legacy != nullptr)
{
transmit_legacy_algorithms = (*legacy == "true");
}

std::string* permissions_ca = PropertyPolicyHelper::find_property(access_properties, "permissions_ca");

if (permissions_ca == nullptr)
Expand Down Expand Up @@ -807,7 +876,7 @@ PermissionsHandle* Permissions::validate_local_permissions(
// Check subject name.
if (check_subject_name(identity, *ah, domain_id, rules, permissions_data, exception))
{
if (generate_permissions_token(*ah))
if (generate_permissions_token(*ah, transmit_legacy_algorithms))
{
if (generate_credentials_token(*ah, *permissions, exception))
{
Expand Down Expand Up @@ -941,7 +1010,8 @@ PermissionsHandle* Permissions::validate_remote_permissions(

if (algo != nullptr)
{
if (algo->compare(lph->algo) != 0)
std::string used_algo = parse_token_algo(*algo);
if (used_algo.compare(lph->algo) != 0)
{
exception = _SecurityException_("Remote participant PermissionsCA algorithm differs from local");
EMERGENCY_SECURITY_LOGGING("Permissions", exception.what());
Expand Down
79 changes: 74 additions & 5 deletions src/cpp/security/authentication/PKIDH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,67 @@ static bool generate_challenge(
return returnedValue;
}

/**
* @brief Convert a signature algortihm before adding it to an IdentityToken.
*
* This methods converts the signature algorithm to the format used in the IdentityToken.
* Depending on the value of the use_legacy parameter, the algorithm will be converted to the legacy format or to the
* one specified in the DDS-SEC 1.1 specification.
*
* @param algorithm The algorithm to convert.
* @param use_legacy Whether to use the legacy format or not.
*
* @return The converted algorithm.
*/
static std::string convert_to_token_algo(
const std::string& algorithm,
bool use_legacy)
{
// Leave as internal format when legacy is used
if (use_legacy)
{
return algorithm;
}

// Convert to token format
if (algorithm == RSA_SHA256)
{
return RSA_SHA256_FOR_TOKENS;
}
else if (algorithm == ECDSA_SHA256)
{
return ECDSA_SHA256_FOR_TOKENS;
}

return algorithm;
}

/**
* @brief Parse a signature algorithm from an IdentityToken.
*
* This method parses the signature algorithm from an IdentityToken.
* It converts the algorithm to the internal (legacy) format used by the library.
*
* @param algorithm The algorithm to parse.
*
* @return The parsed algorithm.
*/
static std::string parse_token_algo(
const std::string& algorithm)
{
// Convert to internal format, allowing both legacy and new formats
if (algorithm == RSA_SHA256_FOR_TOKENS)
{
return RSA_SHA256;
}
else if (algorithm == ECDSA_SHA256_FOR_TOKENS)
{
return ECDSA_SHA256;
}

return algorithm;
}

std::shared_ptr<SecretHandle> PKIDH::generate_sharedsecret(
EVP_PKEY* private_key,
EVP_PKEY* public_key,
Expand Down Expand Up @@ -962,7 +1023,8 @@ std::shared_ptr<SecretHandle> PKIDH::generate_sharedsecret(
}

static bool generate_identity_token(
PKIIdentityHandle& handle)
PKIIdentityHandle& handle,
bool transmit_legacy_algorithms)
{
Property property;
IdentityToken& token = handle->identity_token_;
Expand All @@ -974,7 +1036,7 @@ static bool generate_identity_token(
token.properties().push_back(std::move(property));

property.name("dds.cert.algo");
property.value() = handle->sign_alg_;
property.value() = convert_to_token_algo(handle->sign_alg_, transmit_legacy_algorithms);
property.propagate(true);
token.properties().push_back(std::move(property));

Expand All @@ -984,7 +1046,7 @@ static bool generate_identity_token(
token.properties().push_back(std::move(property));

property.name("dds.ca.algo");
property.value() = handle->algo;
property.value() = convert_to_token_algo(handle->algo, transmit_legacy_algorithms);
property.propagate(true);
token.properties().push_back(std::move(property));

Expand All @@ -1011,6 +1073,13 @@ ValidationResult_t PKIDH::validate_local_identity(
return ValidationResult_t::VALIDATION_FAILED;
}

bool transmit_legacy_algorithms = false;
std::string* legacy = PropertyPolicyHelper::find_property(auth_properties, "transmit_algorithms_as_legacy");
if (legacy != nullptr)
{
transmit_legacy_algorithms = (*legacy == "true");
}

std::string* identity_ca = PropertyPolicyHelper::find_property(auth_properties, "identity_ca");

if (identity_ca == nullptr)
Expand Down Expand Up @@ -1111,7 +1180,7 @@ ValidationResult_t PKIDH::validate_local_identity(
adjusted_participant_key, exception))
{
// Generate IdentityToken.
if (generate_identity_token(*ih))
if (generate_identity_token(*ih, transmit_legacy_algorithms))
{
(*ih)->participant_key_ = adjusted_participant_key;
*local_identity_handle = ih;
Expand Down Expand Up @@ -1164,7 +1233,7 @@ ValidationResult_t PKIDH::validate_remote_identity(

(*rih)->sn = ca_sn ? *ca_sn : "";
(*rih)->cert_sn_ = ""; // cert_sn ? *cert_sn : "";
(*rih)->algo = cert_algo ? *cert_algo : "";
(*rih)->algo = cert_algo ? parse_token_algo(*cert_algo) : "";
(*rih)->participant_key_ = remote_participant_key;
*remote_identity_handle = rih;

Expand Down
3 changes: 3 additions & 0 deletions src/cpp/security/authentication/PKIIdentityHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ namespace security {
static const char* const RSA_SHA256 = "RSASSA-PSS-SHA256";
static const char* const ECDSA_SHA256 = "ECDSA-SHA256";

static const char* const RSA_SHA256_FOR_TOKENS = "RSA-2048";
static const char* const ECDSA_SHA256_FOR_TOKENS = "EC-prime256v1";

static const char* const DH_2048_256 = "DH+MODP-2048-256";
static const char* const ECDH_prime256v1 = "ECDH+prime256v1-CEUM";

Expand Down
64 changes: 64 additions & 0 deletions test/blackbox/common/BlackboxTestsSecurity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5218,6 +5218,70 @@ TEST(Security, openssl_correctly_finishes)
std::exit(0);
}

// Regression test for Redmine issue #19925
TEST(Security, legacy_token_algorithms_communicate)
{
auto test_run = [](bool legacy_pub, bool legacy_sub) -> void
{
// Create
PubSubWriter<HelloWorldPubSubType> writer("HelloWorldTopic_legacy_token_algorithms_communicate");
PubSubReader<HelloWorldPubSubType> reader("HelloWorldTopic_legacy_token_algorithms_communicate");
const std::string governance_file("governance_helloworld_all_enable.smime");
const std::string permissions_file("permissions_helloworld.smime");

// Configure Writer
{
PropertyPolicy extra_policy;
const char* value = legacy_pub ? "true" : "false";
auto& properties = extra_policy.properties();
properties.emplace_back(
"dds.sec.auth.builtin.PKI-DH.transmit_algorithms_as_legacy", value);
properties.emplace_back(
"dds.sec.access.builtin.Access-Permissions.transmit_algorithms_as_legacy", value);
CommonPermissionsConfigure(writer, governance_file, permissions_file, extra_policy);
}

// Configure Reader
{
PropertyPolicy extra_policy;
const char* value = legacy_sub ? "true" : "false";
auto& properties = extra_policy.properties();
properties.emplace_back(
"dds.sec.auth.builtin.PKI-DH.transmit_algorithms_as_legacy", value);
properties.emplace_back(
"dds.sec.access.builtin.Access-Permissions.transmit_algorithms_as_legacy", value);
CommonPermissionsConfigure(reader, governance_file, permissions_file, extra_policy);
}

// Initialize
reader.reliability(eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS).init();
ASSERT_TRUE(reader.isInitialized());
writer.reliability(eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS).init();
ASSERT_TRUE(writer.isInitialized());

// Wait for discovery
reader.waitAuthorized();
writer.waitAuthorized();
reader.wait_discovery();
writer.wait_discovery();
ASSERT_TRUE(reader.is_matched());
ASSERT_TRUE(writer.is_matched());

// Perform communication
auto data = default_helloworld_data_generator(1);
reader.startReception(data);
writer.send(data);
ASSERT_TRUE(data.empty());
reader.block_for_all();
};

// Test all possible combinations
test_run(false, false);
test_run(false, true);
test_run(true, false);
test_run(true, true);
}

void blackbox_security_init()
{
certs_path = std::getenv("CERTS_PATH");
Expand Down

0 comments on commit 6e5a0d9

Please sign in to comment.